Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 19 of 19

Thread: JPanel's BufferedImage Comes Then Goes

  1. #1
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default JPanel's BufferedImage Comes Then Goes

    Sometimes it correctly displays my BufferedImage drawing, but if you run the program a few times, it ceases to display anything.

    I've vastly simplified the compilable code below to simply draw a single rectangle into a BufferedImage contained by a JPanel. Usually, but not always, a rectangle will appear as planned, but if you run the program a few times things begin to go awry; a rectangle will appear for only a millisecond then disappear, or not appear at all in the first place. Please help me find the problem there.

    Also, I can't get my listeners to do anything at all. In the Action menu, "Re-run Program" is supposed to discard the first rectangle and draw another one. The "Paint On This Image" selection should keep the first rectangle while drawing another randomly placed rectangle on, or near, the first one.

    Here's the stripped down, compilable, runnable code:

     
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.*;
     
    public class ArtMaker extends JFrame
    {
    	private static final int WIDTH = 600;
    	private static final int HEIGHT = 600;
    	private JMenuBar mBar;
    	private JMenu menu1;
    	private JMenuItem menuItem1;
    	private JMenuItem menuItem2;
    	private PixelPainter panel;
    	private ArtMaker artMaker;
     
    	public ArtMaker()
    	{
    		setTitle("ArtMaker (First Experiments)");
    		setSize(WIDTH, HEIGHT);
    		setResizable(true);
    		setDefaultCloseOperation(EXIT_ON_CLOSE);
    		createContents();
    		panel = new PixelPainter();
    		add(panel);
    		validate();
    		setVisible(true);
     
    	}
     
    	//***************************************************************
     
    	private void createContents()
    	{
     
    		mBar = new JMenuBar();
    		menu1 = new JMenu("Actions");
    		menuItem1 = new JMenuItem("Re-run Program");
    		menuItem2 = new JMenuItem("Paint On This Image");
    		//these two listeners don't hear so well
    		// when items are chosen in the "Actions" menu
    		menuItem1.addActionListener(new RunListener());
    		menuItem2.addActionListener(new RunListener());
     
    		menu1.add(menuItem1);
    		menu1.add(menuItem2);
     
    		mBar.add(menu1);
    		setJMenuBar(mBar);
     
    	}
     
        //***************************************************************
    	// these two listeners don't work when items are chosen in the
    	// "Actions" menu
    	private class RunListener implements ActionListener
    	{
    		public void actionPerformed(ActionEvent e)
    		{
    			if (e.getSource() == menuItem1)
    			{
    				panel.repaint();
    			}
    			else if (e.getSource() == menuItem2)
    			{
    				panel.paintAgain();
    			}
    		}
     
    	}
     
    	//***************************************************************
     
    	public static void main(String[] args)
    	{
    		System.setProperty("apple.laf.useScreenMenuBar", "true");
    		new ArtMaker();
     
    	}
     
    } // end class ArtMaker


    Then here's the class with the paintComponent():


     
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.image.BufferedImage;
     
    public class PixelPainter extends JPanel
    {
        private static final int WIDTH = 600;
        private static final int HEIGHT = 600;
        private static int[] colors = {0, 0, 64, 0, 128, 0, 0, 0};
        private static Color black = new Color(0, 0, 0);
        private static Color midGray = new Color(128, 128, 128);
        private static Color white = new Color(255, 255, 255);
        private static Color ltGray = new Color(192, 192, 192);
        private static Color dkGray = new Color(64, 64, 64);
        private static Color grayWhite = new Color(223, 223, 223);
        private static Color[] color = {ltGray, dkGray, black, midGray, 
        	black, dkGray};
        private static BufferedImage art;
     
        //***************************************************************
     
        public PixelPainter()
        {
        	repaint();
        }
     
        //***************************************************************
     
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
     
            if (art == null)
            {
                int x = 290;
                int y = 290;
                int w = this.getWidth();
                int h = this.getHeight();
                art = (BufferedImage)(this.createImage(w,h));
                Graphics2D cg = art.createGraphics();
     
     
            	g2.setColor(colorChooser());
            	g2.drawRect(x, y, ((int)(Math.random() * 300)), 
            			((int)(Math.random() * 300)));
            	cg.drawImage(art, null, 0, 0);
     
            }
     
        }
     
        //***************************************************************
     
        // This method is my rookie attempt to draw a new rectangle on top of the
        // the first one whenever the "Paint On This Image" is chosen from the
        // Action menu. But my listeners aren't working, and this method probably
        // isn't my best bet, either.
     
        public void paintAgain()
        {
        	Graphics2D g2d = art.createGraphics();
     
            if (art != null)
            {
                int x = 250;
                int y = 250;
     
            	g2d.setColor(colorChooser());
            	g2d.drawRect(x, y, ((int)(Math.random() * 300)), 
            			((int)(Math.random() * 300)));
            	g2d.drawImage(art, null, 0, 0);
     
            }
     
        }
     
        //***************************************************************
     
        public static Color colorChooser()
        {	 
        	int randomPicker = ((int)(Math.random() * 6));
     
        	Color colorChoice = color[randomPicker];
     
        	return colorChoice;
     
        } // end colorChooser
     
    } // end class PixelPainter

    Any suggestions would be greatly appreciated!


  2. #2
    Super Moderator curmudgeon's Avatar
    Join Date
    Aug 2012
    Posts
    1,130
    My Mood
    Cynical
    Thanks
    64
    Thanked 140 Times in 135 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    You appear to be trying to draw the BufferedImage, art, into itself. Why?

    Also, you should be drawing with the BufferedImage's Graphics object outside of the paintComponent method, and you should always dispose of this Graphics object when done with it. You only draw the BufferedImage into the JPanel if art is null to begin with -- why?

    Consider drawing the BufferedImage in the paintAgain method, and calling that method in the class's constructor. Consider *always* drawing the BufferedImage in the JPanel's paintComponent method unless it is null. If it is null, don't create it in paintComponent.

    --- Update ---

    Other suggestions:
    • If this were my program, I'd move my size constants into the JPanel and use them in my PixelPainter's public getPreferredSize() method override.
    • I'd call paintAgain in my PixelPainter's constructor and would not call repaint there.
    • My paintComponent method would draw the art image if it is not null, but wouldn't do anything else (at this point).
    • I'd make art a non-static variable.
    • paintAgain could create the art BufferedImage in a lazy way (create it if its null), and would draw the random rectangles.
    • I would dispose of g2d when done with it in this method.
    • I would call repaint() at the bottom of this method.
    • My JFrame would not have its size set.
    • Rather I'd call pack() on the JFrame after adding the PixelPainter JPanel and before setting it visible.

  3. #3
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Your always a big help, Curmudgeon. Thanks again.

    To answer your "why's": Because for me there doesn't seem to be the kind of impressive online tutoring documentation that effectively articulates the countless why's and how's and when's necessary to have a total aha moment about Java image manipulation. Like most noobs, I try to take a gazillion murky explanations and stitch them together.

    Your taking the time to assess my messes is a helpful step forward.

    I'll try your suggestions.

  4. #4
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    @Curmudgeon -

    While implementing your suggestions I ran into this problem: the compiler won't let me call paintAgain() from the constructor. Here's the error message:

    ./PixelPainter.java:26: paintAgain(java.awt.Graphics) in PixelPainter cannot be applied to ()
    paintAgain();
    ^
    Why? My new code:

     
     
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.*;
     
     
    public class ArtMaker extends JFrame
    {
    	public PixelPainter panel;
    	private JMenuBar mBar;
    	private JMenu menu1;
    	private JMenuItem menuItem1;
    	private JMenuItem menuItem2;
     
    	public ArtMaker()
    	{
    		setTitle("ArtMaker (First Experiments)");
    		setResizable(true);
    		setDefaultCloseOperation(EXIT_ON_CLOSE);
    		createContents();
    		panel = new PixelPainter();
    		add(panel);
    		pack();
    		validate();
    		setVisible(true);
     
    	}
     
    	//***************************************************************
     
    	private void createContents()
    	{
     
    		mBar = new JMenuBar();
    		menu1 = new JMenu("Actions");
    		menuItem1 = new JMenuItem("Re-run Program");
    		menuItem2 = new JMenuItem("Paint On This Image");
    		//these two listeners don't hear so well
    		// when items are chosen in the "Actions" menu
    		menuItem1.addActionListener(new RunListener());
    		menuItem2.addActionListener(new RunListener());
     
    		menu1.add(menuItem1);
    		menu1.add(menuItem2);
     
    		mBar.add(menu1);
    		setJMenuBar(mBar);
     
    	}
     
        //***************************************************************
    	// these two listeners don't work when items are chosen in the
    	// "Actions" menu
    	private class RunListener implements ActionListener
    	{
    		public void actionPerformed(ActionEvent e)
    		{
     
    				panel.repaint();
     
    		}
     
    	}
     
    	//***************************************************************
     
    	public static void main(String[] args)
    	{
    		System.setProperty("apple.laf.useScreenMenuBar", "true");
    		new ArtMaker();
     
    	}
     
    } // end class ArtMaker

    ...and the JPanel:

     
    import java.util.*;
    import javax.swing.*;
    import java.awt.*;
    import java.awt.image.BufferedImage;
     
    public class PixelPainter extends JPanel
    {
        private static final int WIDTH = 600;
        private static final int HEIGHT = 600;
        private static int[] colors = {0, 0, 64, 0, 128, 0, 0, 0};
        private static Color black = new Color(0, 0, 0);
        private static Color midGray = new Color(128, 128, 128);
        private static Color white = new Color(255, 255, 255);
        private static Color ltGray = new Color(192, 192, 192);
        private static Color dkGray = new Color(64, 64, 64);
        private static Color grayWhite = new Color(223, 223, 223);
        private static Color[] color = {ltGray, dkGray, black, midGray, 
        	black, dkGray};
        private BufferedImage art = new BufferedImage(WIDTH, HEIGHT, 
        	BufferedImage.TYPE_INT_RGB);
     
        //***************************************************************
     
        public PixelPainter()
        {
        	paintAgain();
        }
     
        //***************************************************************
     
        public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
     
            if (art != null)
            {
     
            	g2.drawImage(art, null, 0, 0);
     
            }
            g2.dispose();
     
        } // end paintComponent()
     
        //***************************************************************
        // 
        public void paintAgain(Graphics g)
        {
        	Graphics2D g2 = (Graphics2D) g;
     
        	if (art == null)
        	{
        		g2 = art.createGraphics();
            	int x = 250;
                int y = 250;
     
     
            	g2.setColor(colorChooser());
            	g2.drawRect(x, y, ((int)(Math.random() * 300)), 
            			((int)(Math.random() * 300)));
            }
     
            g2.dispose();
           	repaint();
     
     
        } // end paintAgain()
     
        //***************************************************************
     
        public static Color colorChooser()
        {	 
        	int randomPicker = ((int)(Math.random() * 6));
     
        	Color colorChoice = color[randomPicker];
     
        	return colorChoice;
     
        } // end colorChooser
     
    } // end class PixelPainter

    Until I get it to compile I can't even try the new paintAgain() method to see if it works.

  5. #5
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    The paintAgain() method takes a Graphics object for an arg. There is no Graphics object available in the constructor. The paintComponent() method has one. Try calling it from inside the paintComponent method.

    Why is there a paintAgain() method? Why not do all the drawing from the paintComponent() method?
    If you don't understand my answer, don't ignore it, ask a question.

  6. The Following User Says Thank You to Norm For This Useful Post:

    pict3000 (December 8th, 2012)

  7. #6
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Why is there a paintAgain() method? Why not do all the drawing from the paintComponent() method?
    Two reasons:

    1) Because Curmudgeon suggested I take all of my drawing out of paintComponent. Here's what he said:
    Also, you should be drawing with the BufferedImage's Graphics object outside of the paintComponent method, and you should always dispose of this Graphics object when done with it.
    Please see his post above. And...

    2) Because later I want to be able to call another draw method from a menu selection that draws something else on top of the existing drawing. Can't have two paintComponents(), so I'll need another draw method for that.

    By the way, adding a Graphics argument to the paintAgain() call in the constructor, like this - paintAgain(g), doesn't compile either. Here's the error message:

    ./PixelPainter.java:26: cannot find symbol
    symbol : variable g
    location: class PixelPainter
    paintAgain(g);
    ^

  8. #7
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    cannot find symbol
    symbol : variable g
    Where is the variable: g defined that is in scope (within the same pair of {}s) as where it is being used?

    It looks like you are trying to write code without understanding what the different parts of the code are supposed to do. I'll leave the design to you and Curmudgeon.
    If you don't understand my answer, don't ignore it, ask a question.

  9. #8
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    That's not true at all. I'm just new to drawing and I don't understand how to get the BufferedImage "art" into a graphics context outside of paintComponent(). I've tried getGraphics() for a Graphics context and createGraphics() for a Graphics2D context. One tutorial suggested the using Graphics argument (yes, outside of paintComponent) as you can see above. Those two methods are not difficult to use. But it's not working here for some unknown reason. So I've turned to the forum for some insights.

    How can I get my BufferedImage art into a Graphics context so I can draw into it, so I can draw it onto my JPanel?

  10. #9
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    paintAgain(g);
    I based my statement on the above code. It looks like it was coded without defining a variable g and giving that variable a value.

    Why does the paintAgain() method need an arg? It looks like it sets the value of g2 itself and never uses what is passed to it.
    If you don't understand my answer, don't ignore it, ask a question.

  11. #10
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    It uses its arg the same way paintComponent does. It immediately converts the Graphics context to a Graphics2D in order to draw into the BufferedImage.

    As far as paintAgain(g) is concerned, having that un-declared Graphics variable was a last-ditch, desperation attempt to get a Graphics context outside of paintComponent() - to see if, per outside chance, imitating paintComponent() might work. Nothing else worked.

  12. #11
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Try removing the Graphics parameter for the paintAgain() method since it is never used.
    If you don't understand my answer, don't ignore it, ask a question.

  13. #12
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    I've tried that. Without that g arg, the code looks fine. It should work. That's what's so weird.

    I'll make it work. Thanks for your time.

  14. #13
    Super Moderator curmudgeon's Avatar
    Join Date
    Aug 2012
    Posts
    1,130
    My Mood
    Cynical
    Thanks
    64
    Thanked 140 Times in 135 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Regarding my design recommendations: I figured that the paintAgain method should be where you create your randomized parameters including the rectangle sizes and colors, that would be used in the paintComponent(...) method. This paintAgain method could be called by some actionPerformed method and again would create new random values.

    You could draw directly in the paintAgain method if you are drawing on a BufferedImage object, and if so, then the paintAgain() method would extract the Graphics2D object from the BufferedImage, draw with it, then dispose it, then call repaint() which suggests the JVM to call the paint and paintComponent methods. In the paintComponent method you would draw the BufferedImage with the Graphics object supplied by the JVM and you would not dispose of this.

    If on the other hand you desire to draw directly in paintComponent, then there would be no need for a BufferedIamge, and you would change the random fields in paintAgain() call repaint() and the paintComponent method would use those fields to draw the rectangles.

  15. The Following User Says Thank You to curmudgeon For This Useful Post:

    pict3000 (December 8th, 2012)

  16. #14
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Check the code in paintAgain(). Is this what you want:
     	if (art == null)
    If you don't understand my answer, don't ignore it, ask a question.

  17. #15
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    I like that plan. I think that, and several pieces of pizza, ought to work. You're a titan, Curmudgeon.

    Norm - Here, removing that code doesn't improve or detract. The code I posted here is just a stripped down version of my program for posting sake.

  18. #16
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    The code I posted here is just a stripped down version of my program for posting sake.
    Its a waste of time posting code that does not compile, execute and show the problem.
    The posted code would not show the problem. It would get a NPE.
    If you don't understand my answer, don't ignore it, ask a question.

  19. The Following User Says Thank You to Norm For This Useful Post:

    curmudgeon (December 8th, 2012)

  20. #17
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Norm - I did post complete code that compiles. Look at the beginning of this thread. But after I made changes suggested to me, I posted the new code because now it wouldn't compile - to get help figuring out why it wouldn't compile. All the code I posted was more than ample for the problems I was experiencing. Even better was the fact that I took the time to strip it down and isolate relevant code. To assume I omitted relevant code would be mistaken.

  21. #18
    Super Moderator Norm's Avatar
    Join Date
    May 2010
    Location
    Eastern Florida
    Posts
    25,042
    Thanks
    63
    Thanked 2,708 Times in 2,658 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Making the changes I suggested I get this image:
    Attached Images Attached Images
    If you don't understand my answer, don't ignore it, ask a question.

  22. #19
    Member
    Join Date
    Jul 2012
    Location
    Dallas area
    Posts
    34
    Thanks
    2
    Thanked 0 Times in 0 Posts

    Default Re: JPanel's BufferedImage Comes Then Goes

    Very good!

    My bad --- I misread your suggestion. You correctly said:
    Try calling it from inside the paintComponent method.
    But I misread that as saying
    Try drawing inside paintComponent instead of paintAgain.
    Moving my paintAgain call into paintComponent was the right call. I can't thank you enough, Norm!!!

Similar Threads

  1. byte[] to bufferedImage always NULL?
    By Baraa in forum What's Wrong With My Code?
    Replies: 1
    Last Post: October 18th, 2012, 02:08 AM
  2. [SOLVED] Pesky <JPanel>.getWidth() and <JPanel>.getHeight() Methods...
    By snowguy13 in forum AWT / Java Swing
    Replies: 1
    Last Post: December 31st, 2011, 03:35 PM
  3. drawing a BufferedImage onto a JPanel
    By nemo in forum What's Wrong With My Code?
    Replies: 2
    Last Post: October 13th, 2010, 07:48 PM
  4. Creating a bufferedimage!
    By Vexst in forum Java ME (Mobile Edition)
    Replies: 0
    Last Post: June 16th, 2010, 08:05 AM
  5. Creating and displaying a JPanel inside another JPanel
    By JayDuck in forum AWT / Java Swing
    Replies: 1
    Last Post: April 7th, 2009, 08:02 AM

Tags for this Thread