Results 1 to 14 of 14
  1. #1
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Help - Yet Another Paint() Called Twice thread

    Well, I'm posting this hoping that more has been learned about this situation after reading the somewhat inconclusive previous posts about specific instances of the Graphics2D paint() routing getting run twice when it is only called once in the code. The general consensus seems to be that nobody really knows when paint() will be called, so don't count on it or write to accomodate it. But this begs the question in my particular case: why does the following code always get called exactly two times? The original code in the full program I'm developing got called twice, and this (really rough) little demonstration is called exactly twice, at least on my equipment. If your experience is different PLEASE tell me because that is significant. And what I really want to know, of course, is how to control the number of times it is called. I only want it called once.

    This really matters, at least to me, because I am not worried about painting the graphics twice, I am concerned with the side effects of painting an object twice that has a mouseListener attached to it. (And yes, I specifically want to attach it to the object and not put the routine in the panel or somewhere else. It is an important design decision.)

    To use this demo just run file CallsALot.java and click on the little note while watching the console for output. You will see the results of println(). If you see repeated words, then you know that the paint() routine is being called multiple times. "BEEP ONCE" is the output from clicking once on the little note. If that shows up more than once, you'll know how many extra times the paint() routine is being called simply by counting the number of occurrences of "BEEP ONCE" (or any of the other calls.)

    Thanks in advance for your time and wisdom.

    Java Code:
    package com.mst.test;
    
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.geom.Ellipse2D;
    import java.awt.geom.Line2D;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import java.awt.BorderLayout;
    
    
    public class CallsALot extends JFrame {
    	private static final long serialVersionUID = 1L;
    
    	public CallsALot() {
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		setMinimumSize(new Dimension(492, 200));
    
    		NotationPanel panel = new NotationPanel();
    		getContentPane().add(panel, BorderLayout.CENTER);
    		// setBackground(Color.white);
    		// setMaximumSize(new Dimension(492, 200));
    		// setPreferredSize(new Dimension(492, 200));
    
    	}
    	/////////////////////////////////////////////////////
    	public static void main(String[] args) {
    		EventQueue.invokeLater(new Runnable() {
    			public void run() {
    				try {
    					CallsALot np = new CallsALot();
    					np.setVisible(true);
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		});
    	}
    
    	////////////////////////////////////////////////////////	
    
    	class NotationPanel extends JPanel {
    		private static final long serialVersionUID = 1L;
    
    		public void drawNotehead(Graphics2D g) {
    			final Ellipse2D myEllipse;
    
    			double x = (getWidth() * .1);
    			double y = (getHeight() * .35);
    
    			myEllipse = new Ellipse2D.Double(x, y, 9.0, 6.0);
    
    			addMouseListener(new MouseAdapter() { 
    				public void mouseReleased(MouseEvent e) { 
    					if (myEllipse.contains(e.getX(), e.getY())){
    						System.out.println("BEEP ONCE.");
    					}
    				} 
    			}); 
    
    			g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    					RenderingHints.VALUE_ANTIALIAS_ON);
    			// g.setStroke(new BasicStroke(1));
    			// g.fill(myEllipse);
    			g.draw(myEllipse);
    			System.out.println("Notehead");
    
    		}
    
    
    
    		public void drawStaffLines(Graphics2D g2){
    			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    			double x1 = getWidth() * .02;
    			double x2 = getWidth() * .98;
    			double y1 = getHeight() * .30;
    			double y2 = y1;	    
    			for (int i=0; i<5; i++){
    				g2.draw(new Line2D.Double(x1, y1, x2, y2));
    				y1 +=6; y2 = y1;
    			}
    			System.out.println("StaffLines");
    		}
    
    
    		public void paint(Graphics g) {
    			Graphics2D g2 = (Graphics2D) g;
    			super.paint(g2);
    			drawStaffLines(g2);
    			drawNotehead(g2);
    			System.out.println("paint");
    		} 
    	}
    }

  2. #2
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,458
    Rep Power
    20

    Default Re: Help - Yet Another Paint() Called Twice thread

    First off, the correct method to override is paintComponent(...) not paint(...).

    How many MouseListeners do you intend to add to the panel? one for each time it is repainted? Long enough and you could end up with a OOME that way.

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  3. #3
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    Excellent point. I overlooked that completely. Thanks!

  4. #4
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    Hello, I'm back. I've been working with this a couple hours now and wonder what your advice is on how to implement what I'm actually after. Every which way I turn I run into some reason why I can't implement this (taking your thoughtful hint though, of course), and I'm sure I must be missing something fundamental. I've never dabbled in sprites, is this an area that might help me and if so do you have any references? Any help is welcome. Thanks. -Don

  5. #5
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,315
    Blog Entries
    1
    Rep Power
    26

    Default Re: Help - Yet Another Paint() Called Twice thread

    For one thing, you never want to add components or listeners from with a paint/paintComponent method or any method called by either of the two methods above. So add your MouseListener in a constructor.

    Then if still stuck show your latest code and ask as specific a series of questions as possible.

  6. #6
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    Hi. OK, following is my current code. It is not working at the moment.

    A little background: I come from a c++/QT background where it is trivial to put a painted ellipse on the screen and attach a mouseevent to it. I am trying simply to recreate that here. I want to draw an ellipse ( a musical note, much better looking in the real program) and make that painted ellipse something that I can position at will and make "smart." Previously I developed an extensive program in QT/C++ that did this. But I'm new to Java and want my old habits to work still I guess...

    So that is my aim. Maybe in Java a complete paradigm shift is in order for me. So be it. But I am stumped right now and this mornings garbage was posted after an all nighter and shouldn't have seen the light of day. Oh well.

    Here's the latest code. I am in the middle of experimenting with turning the ellipse into a JComponent although that seems extreme to me but I thought I'd try it as an experiment.

    Java Code:
    package com.mst.test;
    
    import java.awt.BasicStroke;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.geom.Ellipse2D;
    import java.awt.geom.Line2D;
    
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import java.awt.BorderLayout;
    
    
    public class CallsALot extends JFrame {
    	private static final long serialVersionUID = 1L;
    
    	public CallsALot() {
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		setMinimumSize(new Dimension(492, 200));
    
    		NotationPanel panel = new NotationPanel();
    		getContentPane().add(panel, BorderLayout.CENTER);
    		// setBackground(Color.white);
    		// setMaximumSize(new Dimension(492, 200));
    		// setPreferredSize(new Dimension(492, 200));
    
    	}
    	/////////////////////////////////////////////////////
    	public static void main(String[] args) {
    		EventQueue.invokeLater(new Runnable() {
    			public void run() {
    				try {
    					CallsALot np = new CallsALot();
    					np.setVisible(true);
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    		});
    	}
    
    	////////////////////////////////////////////////////////   
    
    	class NotationPanel extends JPanel implements MouseListener {
    		private static final long serialVersionUID = 1L;
    
    		public NotationPanel(){
    			addMouseListener(this);
    			setLayout(null);
    		}
    
    		public class Note extends JComponent{
    			final Ellipse2D notehead;
    			public Note(){
    
    				double x = (getWidth() * .1);
    				double y = (getHeight() * .35);
    
    				notehead = new Ellipse2D.Double(x, y, 9.0, 6.0);
    
    			}
    
    			void drawNotehead(Graphics2D g) {
    				g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    						RenderingHints.VALUE_ANTIALIAS_ON);
    				g.setStroke(new BasicStroke(1));
    				g.fill(notehead);
    				g.draw(notehead);
    				System.out.println("Notehead");
    			}
    
    			void clicked(int x, int y) {
    				System.out.println("I WAS CLICKED.");
    			}
    
    			
    		}
    
    		public void drawStaffLines(Graphics2D g2){
    			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    			double x1 = getWidth() * .02;
    			double x2 = getWidth() * .98;
    			double y1 = getHeight() * .30;
    			double y2 = y1;    
    			for (int i=0; i<5; i++){
    				g2.draw(new Line2D.Double(x1, y1, x2, y2));
    				y1 +=6; y2 = y1;
    			}
    			System.out.println("StaffLines");
    		}
    
    
    		public void paint(Graphics g) {
    			Graphics2D g2 = (Graphics2D) g;
    			super.paint(g2);
    			drawStaffLines(g2);
    			Note n = new Note();
    			n.drawNotehead(g2);
    			System.out.println("paint");
    		}
    
    
    		@Override
    		public void mouseClicked(MouseEvent e) {
    			// TODO Auto-generated method stub
    			
    		}
    
    
    		@Override
    		public void mousePressed(MouseEvent e) {
    			// TODO Auto-generated method stub
    			
    		}
    
    
    		@Override
    		public void mouseReleased(MouseEvent e) {
    			Component[] cs = this.getComponents();
    
    			for (Component c : cs) {
    				if (c.contains(e.getX(), e.getY())){
    					System.out.println("BEEP ONCE.");
    				}
    			}
    		}
    
    		@Override
    		public void mouseEntered(MouseEvent e) {
    			// TODO Auto-generated method stub
    			
    		}
    
    
    		@Override
    		public void mouseExited(MouseEvent e) {
    			// TODO Auto-generated method stub
    			
    		}
    	}
    }

  7. #7
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,315
    Blog Entries
    1
    Rep Power
    26

    Default Re: Help - Yet Another Paint() Called Twice thread

    You need to have the dragging shape exist as a reference that has been created outside of paint/paintComponent and in fact should have class scope. Then it can be manipulated by methods outside of paint/paintComponent. An example of this can be found in my code on StackOverflow.com (I'm hovercraftfullofeels): Change mouseListener while mouse is pressed

  8. #8
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    I'll check out the code you just referenced. In the meantime I was just typing this up:

    SPECIFIC QUESTIONS on the above code example:

    Why is paint called twice each and every time?
    Why is paintComponent() the correct choice over paint() when painting an ellipse?
    Why is there no discernable difference between calls to paint() and paintComponent() if one replaces the other?
    Why does Java allow me to put a mouseListener onto an ellipse then not allow me to add the ellipse to a JPanel?

  9. #9
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,315
    Blog Entries
    1
    Rep Power
    26

    Default Re: Help - Yet Another Paint() Called Twice thread

    Quote Originally Posted by devdon View Post
    I'll check out the code you just referenced. In the meantime I was just typing this up:

    SPECIFIC QUESTIONS on the above code example:
    Fair enough

    Why is paint called twice each and every time?
    I don't know as paint is called as often as needed to render the GUI. Most of this is out of your control, and for this reason, you must have no program logic within paint or paintComponent, and you should not have your code depend on how often or when these methods are called.

    Why is paintComponent() the correct choice over paint() when painting an ellipse?
    paintComponent allows for automatic double buffering and will reduced flickering of your graphics rendering especially if you do any animation. Also paint is responsible for painting a component's borders and its children. If you don't want the responsibility of making sure that you're not stepping on this functionality, you'll avoid paint unless you specifically want to override this functionality (I've done it once when trying to make a translucent JButton.

    Why is there no discernable difference between calls to paint() and paintComponent() if one replaces the other?
    Because you're not using animation yet or doing complex enough drawing. Trust me, though, you'll see the difference soon enough.

    Why does Java allow me to put a mouseListener onto an ellipse then not allow me to add the ellipse to a JPanel?
    1) I don't see anywhere where you "put a MouseListener onto an ellipse".
    2) That's how the add(...) method is defined. You can't add a non-component to a container. You can draw them but the Container add method is strictly for Components or their children.

  10. #10
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    In my very first SCCCE posting I have code that works but, as you say, it appears in a paint routine so it creates too many listeners. But the following is copy/pasted from the top of this thread and is EXACTLY why I wrote to you because I am confused about how Java works and I need to understand. Again, the code I posted above, the first one, works but is called twice. All day now I have been trying to re-write what was working twice too well so to speak. And I'm counting on you to shed some light on this because it is trivial in other languages and you are the Java expert. I admit to not getting along as well with Java as I do with other languages but I'm trying to change...

    Here's the code from above:

    Java Code:
     class NotationPanel extends JPanel {
            private static final long serialVersionUID = 1L;
     
            public void drawNotehead(Graphics2D g) {
                final Ellipse2D myEllipse;
     
                double x = (getWidth() * .1);
                double y = (getHeight() * .35);
     
                myEllipse = new Ellipse2D.Double(x, y, 9.0, 6.0);
     
                addMouseListener(new MouseAdapter() {
                    public void mouseReleased(MouseEvent e) {
                        if (myEllipse.contains(e.getX(), e.getY())){
                            System.out.println("BEEP ONCE.");
                        }
                    }
                }); 
     ....... (EXCERPT FROM TOP OF THE THREAD)

    ... OK, I see now that I added the mouselistener to the panel. In the meantime I turned the ellipse into a JComponent and wrangled it about some and now it works.

    Thanks.
    Last edited by devdon; 04-11-2012 at 02:03 AM. Reason: CORRECTIONS MADE

  11. #11
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,315
    Blog Entries
    1
    Rep Power
    26

    Default Re: Help - Yet Another Paint() Called Twice thread

    Again, paint(...) and by the same token paintComponent (since paint calls paintComponent()) are called by the JVM many times, and most times out of your control. You can suggest to the JVM that they be called by calling repaint(), but this doesn't always work, especially when repaint() calls get stacked on the queue. But the JVM will call this method when it receives notification from the operating system that a window is "dirty", or perhaps for other internal reasons. So please understand, that you do not have much control over this method. Because it is often called many times in a program's run, you do not want to add components to a GUI in this method, and you don't want to add listeners to a component in these methods.

    Next, these methods are responsible for drawing any graphics in your GUI including drawing the buttons, and text components -- everything. You want these methods to be as lean and fast as possible and do not want to bog them down unnecessarily creating objects, adding listeners, or reading from in from files.

    Your drawNotehead(...) method is called by paint, so in effect, all code inside of it is inside of the paint method. If you don't listen to us, your GUI is going to have a component that has accumulated 100 MouseListeners added to it, and it's going to paint very slowly, and you're program is going to appear very unresponsive. Plus those listeners will all fire causing lord knows what effect.

    I'm not sure how I can make you believe that you're not supposed to do this. If any of this is unclear, please let me know.

  12. #12
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    "If you don't listen to us, your GUI is going to have a component that has accumulated 100 MouseListeners added to it, and it's going to paint very slowly, and you're program is going to appear very unresponsive. Plus those listeners will all fire causing lord knows what effect."

    I believe you and understand perfectly. My new code is entirely different from what is here, I've had a whole day to work on it. I have an entirely new panel, several different classes and a system that works. As a piece of hopefully constructive criticism, if you might consider letting up a bit on the gatekeeper aspect of making your patrons jump through hoops and blaming them for how they ask questions and just answer the damn questions maybe more productive conversations would ensue. But I've never run a forum and I don't know for sure. I just thought that have twice taken the time away from real coding to write an SCCCE would have resulted in more info, more understanding, in less time and with less stress. But maybe that's just me.

    I think we misunderstand each other. I just wanted a general understanding of specific java areas. I'm not a geeky 20 year old in his mother's basement. I'm working with a new language which - no offense - I'm not very good at yet and so far I don't particularly like. And I don't think Java is well suited to desktop development for a variety of reasons. But here I am. Thanks for your support.

  13. #13
    Fubarable's Avatar
    Fubarable is offline Moderator
    Join Date
    Jun 2008
    Posts
    19,315
    Blog Entries
    1
    Rep Power
    26

    Default Re: Help - Yet Another Paint() Called Twice thread

    Quote Originally Posted by devdon View Post
    I believe you and understand perfectly. My new code is entirely different from what is here, I've had a whole day to work on it. I have an entirely new panel, several different classes and a system that works. As a piece of hopefully constructive criticism, if you might consider letting up a bit on the gatekeeper aspect of making your patrons jump through hoops and blaming them for how they ask questions and just answer the damn questions maybe more productive conversations would ensue.
    Fair enough. I was just a bit frustrated again seeing the listener being added in the same method as previously. But regardless, I don't "run" this forum, but rather am one of several moderators.


    But I've never run a forum and I don't know for sure. I just thought that have twice taken the time away from real coding to write an SCCCE would have resulted in more info, more understanding, in less time and with less stress. But maybe that's just me.
    Writing an SSCCE takes quite a bit of effort, yes, but so does reading it and understanding it. I've been replying from work and so have not had a chance to run nor analyze your code yet. Since we're all volunteers, the pace of our efforts can be slow due to other valid demands on our time. Your understanding on this is greatly appreciated.


    I think we misunderstand each other. I just wanted a general understanding of specific java areas. I'm not a geeky 20 year old in his mother's basement. I'm working with a new language which - no offense - I'm not very good at yet and so far I don't particularly like. And I don't think Java is well suited to desktop development for a variety of reasons. But here I am. Thanks for your support.
    No offense taken here, and your efforts will be worth it in the end, I believe. Part of the current problem I think is in trying to understand Java Swing's common use of passive rather than active graphics.

    Anyway, let's look at your SSCCE, and you, if you can, please have a look at my StackOverflow code...

  14. #14
    devdon is offline Member
    Join Date
    Mar 2012
    Posts
    21
    Rep Power
    0

    Default Re: Help - Yet Another Paint() Called Twice thread

    Ok. Here is the solution I've found to a clickable note. (Very rough example, just enough for the note to work. See the results in console.) It seems to work just fine but it causes another problem. Now that the note is a component rather than a graphic ellipse it comes unstuck from the staff lines when you resize the windows. How do I deal with that?

    Java Code:
    package com.mst.test;
    
    import java.awt.Color;
    
    public class ClickableNote extends JPanel {
    	private static final long serialVersionUID = 1L;
    
    	public ClickableNote() {
    		setMinimumSize(new Dimension(200, 100));
    		setMaximumSize(new Dimension(200, 100));
    		setPreferredSize(new Dimension(200, 100));
    		setBackground(Color.white);
    		setOpaque(true);
    		setLayout(null);
    		addNote();
    	}
    	
    	public static void main(String[] args) {
    	    EventQueue.invokeLater(new Runnable() {
    	        public void run() {
    	            try {
    	                JFrame frame = new JFrame();
    	                frame.setMinimumSize(new Dimension(200, 100));
    	        		frame.setMaximumSize(new Dimension(200, 100));
    	        		frame.setPreferredSize(new Dimension(200, 100));
    
    	                ClickableNote cn = new ClickableNote();
    	                frame.add(cn);
    	                frame.setVisible(true);
    
    	            } catch (Exception e) {
    	                e.printStackTrace();
    	            }
    	        }
    	    });
    	}
    	
    	
    	void addNote(){
    		Note n = new Note();
    		add(n);	
    	}
    
    	public class StaffLines {
    
    		public void draw(Graphics2D g2){
    			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    			double x1 = getWidth() * .02;
    			double x2 = getWidth() * .98;
    			double y1 = getHeight() * .30;
    			double y2 = y1;    
    			for (int i=0; i<5; i++){
    				g2.draw(new Line2D.Double(x1, y1, x2, y2));
    				y1 +=6; y2 = y1;
    			}
    			System.out.println("StaffLines");
    		}
    	}
    
    	
    	public void paintComponent(Graphics g) {
    		Graphics2D g2 = (Graphics2D) g;
    		super.paintComponent(g2);
    		StaffLines sl = new StaffLines();
    		sl.draw(g2);
    		Note n = new Note();
    		n.draw(g2);
    		System.out.println("paint");
    	}
    
    }
    
    class Note extends JComponent implements MouseListener {  
    	Ellipse2D notehead = null;
    	int midiNumber = 0; 
    	
    	public Note(){			
    		notehead =  new Ellipse2D.Double(50, 45, 9, 6);
    		midiNumber = 64;
    		setBounds(notehead.getBounds());
    		addMouseListener(this);
    	}
    			
    	public void draw(Graphics2D g2){
    		g2.fill(notehead);		
    		g2.rotate(Math.toRadians(-30), 50 + (9 / 2), 45 + (6 / 2));
    		// g2.rotate(Math.toRadians(angle), x + (width / 2), y + (height / 2));
    		g2.draw(notehead);
    	}
    	
    	@Override
    	public void mouseClicked(MouseEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void mousePressed(MouseEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    	@Override
    	public void mouseReleased(MouseEvent e) {
    		System.out.println("Note played.");		
    	}
    	@Override
    	public void mouseEntered(MouseEvent e) {
    		// TODO Auto-generated method stub			
    	}
    	@Override
    	public void mouseExited(MouseEvent e) {
    		// TODO Auto-generated method stub			
    	}
    }

Similar Threads

  1. Replies: 2
    Last Post: 08-24-2011, 12:04 AM
  2. Replies: 5
    Last Post: 10-22-2010, 02:55 PM
  3. while running multiple thread repaint isnt being called....
    By raptor in forum Threads and Synchronization
    Replies: 4
    Last Post: 08-26-2010, 12:47 AM
  4. Why the paint() method is called two times ?
    By supremo in forum New To Java
    Replies: 4
    Last Post: 06-03-2010, 07:21 PM
  5. [SOLVED] Method from one thread called on another thread
    By Ypsilon IV in forum Threads and Synchronization
    Replies: 7
    Last Post: 04-24-2009, 03:07 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •