Results 1 to 19 of 19

Thread: paintCompnent

  1. #1
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default paintCompnent

    I have been learning to draw shapes in Java, and after playing around a lot and reading quite a few guides i'v managed to do it on my own but the problem is i don't understand a few things. Would anyone care to explain me what exactly are these lines of codes doing?

    Whole class(I create an instance of this class in a frame which is another class on its own):
    Java Code:
    package container;
    
    import java.awt.Graphics;
    import javax.swing.JPanel;
    
    public class drawPanel extends JPanel
    {
    	public void paintComponent(Graphics g)
    	{
    		 super.paintComponent(g);
                     g.drawLine(50, 50, 100, 100);
    	}
    }
    Program draws the line just the way i want it but I have few questions.

    what does this line of code do?
    Java Code:
    super.paintComponent(g);
    and in this code the "Graphics g" what does that do? I understand that i am editing method paintComponent but what is Graphics adding on to it?
    Java Code:
    public void paintComponent(Graphics g)
    Also If i were to draw another line does this new line has to be done within painComponent or can i do something like:

    Java Code:
    drawPanel.paintComponent.drawLine(20, 20, 40, 40);
    or type this in another method?
    Java Code:
    g.drawLine(20, 20, 40, 40);
    I am aware this line wouldn't even compile I am just wondering is there a way to draw the line in same drawPanel from another class?

    Hope i was not too confusing >.<
    Last edited by Bagzli; 07-01-2011 at 05:43 PM.

  2. #2
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,655
    Blog Entries
    7
    Rep Power
    21

    Default

    In Swing there's a separate thread, the EDT (Event Dispatch Thread) that checks which components need to be (partly) repainted. If so, it constructs a Graphics object for the component and calls its paintComponent(Graphics) method to do the repainting. A JPanel simply sets its entire surface to the background colour. You are calling it by doing super.paintComponent(g). Leave it out and see what happens. Also, for fun, add a System.out.println("in my paintComponent!") line to your method and move your frame around a bit or move another window over your panel and see. Also, the EDT calls the buttons (or whatever components) when it needs to. If your actionPerformed( ... ) method takes a long time to complete that EDT can't do anything else (it's working in your method) and your entire GUI becomes sluggish, so beware of that pitfall. Your last example indeed doesn't work, it's the paintComponent method in that particular component that needs to do the painting. Of course you can come up with a couple of tricks to make another object make your panel do the painting but I leave that as an exercise to the reader(s) ;-)

    kind regards,

    Jos
    cenosillicaphobia: the fear for an empty beer glass

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

    Default

    Quote Originally Posted by Bagzli View Post
    what does this line of code do?
    Java Code:
    super.paintComponent(g);
    This calls the paintComponent method of the JPanel that you're extending, allowing it to any necessary house-keeping that may need to be done. Most importantly, it will redraw the JPanel's background and erase any old graphics that need to be erased. This is especially important in animations.


    and in this code the "Graphics g" what does that do? I understand that i am editing method paintComponent but what is Graphics adding on to it?
    Java Code:
    public void paintComponent(Graphics g)
    The Graphics object is somewhat like a pen that is used to draw the images with. It needs to be obtained from the JVM each time repainting is done, and so the JVM will pass the object into this method via the parameter you see above.


    Also If i were to draw another line does this new line has to be done within painComponent
    Yes.


    or can i do something like:

    Java Code:
    drawPanel.paintComponent.drawLine(20, 20, 40, 40);
    No, you never call paintComponent directly (except the super method as shown above). Instead you can change the state of your class and call repaint on the JPanel which suggests to the JVM that the JPanel be repainted and that it should call the paintComponent method.


    or type this in another method?
    Java Code:
    g.drawLine(20, 20, 40, 40);
    Only if this other method is called from within paintComponent and that the other method gets passed the Graphics object from paintComponent.
    Last edited by Fubarable; 07-01-2011 at 05:50 PM.

  4. #4
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    ok so if i were to press a button, i need it to create a pop up windows (JDialog) and in here you enter size of your box. After you type in your dimensions you press ok and it draws box on the screen. my actual lines of "g.drawRec(50, 50, 10, 10);" needs to be inside paint component. From what i understood in post by JosAH there are few tricks I can work to make this possible and I should figure them out on my own. Well I'll give it a try then. ATM i don't have any ideas.

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

    Default

    Quote Originally Posted by Bagzli View Post
    ok so if i were to press a button, i need it to create a pop up windows (JDialog) and in here you enter size of your box. After you type in your dimensions you press ok and it draws box on the screen. my actual lines of "g.drawRec(50, 50, 10, 10);" needs to be inside paint component. From what i understood in post by JosAH there are few tricks I can work to make this possible and I should figure them out on my own. Well I'll give it a try then. ATM i don't have any ideas.
    One thing to do is to have the g.drawRec method in paintComponent and use variables for the drawRec parameters. You could initialize the variables to some nonsense value such as -1, and then have the drawRec method in an if block that only allows it to be called if the parameters are > 1 (or you could use a boolean for this). Then in the dialog, set the class's variables and call repaint on the JPanel.

    Example to follow...

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

    Default

    Quote Originally Posted by Bagzli View Post
    ok so if i were to press a button, i need it to create a pop up windows (JDialog) and in here you enter size of your box. After you type in your dimensions you press ok and it draws box on the screen. my actual lines of "g.drawRec(50, 50, 10, 10);" needs to be inside paint component. From what i understood in post by JosAH there are few tricks I can work to make this possible and I should figure them out on my own. Well I'll give it a try then. ATM i don't have any ideas.
    One thing to do is to have the g.drawRec method in paintComponent and use variables for the drawRec parameters. You could initialize the variables to some nonsense value such as -1, and then have the drawRec method in an if block that only allows it to be called if the parameters are > 1 (or you could use a boolean for this). Then in the dialog, set the class's variables and call repaint on the JPanel.

    Example to follow...

  7. #7
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    I did it this way, Can you guys tell me if its wrong way to do it? It works:

    Class 1:
    Java Code:
    package container;
    
    import java.awt.Graphics;
    import javax.swing.JPanel;
    
    public class drawPanel extends JPanel
    {
    	public void paintComponent(Graphics g)
    	{
    		 super.paintComponent(g);
    	}
    }
    Class 2:

    Java Code:
    package container;
    
    public class trailer extends JFrame
    {
    	private JPanel pnl_topView = new JPanel();
    	private JPanel pnl_leftView = new JPanel();
    	private JPanel pnl_rightView = new JPanel();
    	private JPanel pnl_threePanels = new JPanel();
    	private drawPanel pnl_bottom = new drawPanel();
    	
    	private JButton btn_test = new JButton("Draw a line");
    	
    	private void initialize()
    	{
    		pnl_leftView.setBorder(BorderFactory.createLineBorder(Color.black));
    		pnl_rightView.setBorder(BorderFactory.createLineBorder(Color.black));
    		pnl_topView.setBorder(BorderFactory.createLineBorder(Color.black));
    		pnl_bottom.setBorder(BorderFactory.createLineBorder(Color.black));
    		
    		pnl_threePanels.setLayout(new GridLayout(4, 1, 30, 30));
    	}
    	
    	private void addToPanels()
    	{
    		pnl_threePanels.add(pnl_topView);
    		pnl_threePanels.add(pnl_rightView);
    		pnl_threePanels.add(pnl_leftView);
    		pnl_threePanels.add(pnl_bottom);
    		
    		pnl_bottom.add(btn_test);
    	}
    	
    	public trailer()
    	{
    		this.setSize(1500, 1000);
    		this.setTitle("Trailer Panel Loader");
    		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    		this.setLocationRelativeTo(null);
    		this.setResizable(false);
    		
    		this.add(pnl_threePanels);
    		
    		initialize();
    		addToPanels();
    		
    		btn_test.addActionListener(new ActionListener(){
    			public void actionPerformed(ActionEvent e)
    			{
    				Graphics g = getGraphics();
    				g.drawLine(100, 950, 150, 960);
    			}
    		});
    	}
    	
    	public static void main(String[] args)
    	{
    		new trailer().setVisible(true);
    	}
    }
    when button test is pressed it draws a line where i wanted it.

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

    Default

    Yes, you're doing it wrong as you should rarely if ever use getGraphics to get a graphics object since the object won't be stable. What happens if you minimize and the re-display this gui? Does the drawn graphic persist?

    Here's my example. Sorry for its length:

    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class DrawExample extends JPanel {
       private static final int PANEL_WIDTH = 800;
       private static final int PANEL_HEIGHT = 600;
       private boolean drawRectangle = false;
       private int rectX;
       private int rectY;
       private int rectWidth;
       private int rectHeight;
       
       private JTextField parametersField = new JTextField("" + rectX + ", " + rectY + ", " + rectWidth + ", " + rectHeight, 20);
    
       public DrawExample() {
          setLayout(new BorderLayout());
    
          JButton getParametersBtn = new JButton("Get Parameters");
          getParametersBtn.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
                getParameters();
             }
          });
          JPanel southPanel = new JPanel();
          southPanel.add(getParametersBtn);
    
          add(southPanel, BorderLayout.SOUTH);
       }
    
       private void getParameters() {
          JPanel parameterPanel = new JPanel();
    
          parameterPanel.add(new JLabel(
                            "Add numbers for rectangle's x, y, width, height, separated by a comma:"));
          parameterPanel.add(parametersField);
    
          int response = JOptionPane.showConfirmDialog(this, parameterPanel,
                   "Get Rectangle Parameters", JOptionPane.OK_CANCEL_OPTION);
          
          if (response != JOptionPane.OK_OPTION) {
             eraseDrawing();
             return;
          }
          
          try {
             String text = parametersField.getText();
             String[] tokens = text.split(",");
             if (tokens.length != 4) {
                eraseDrawing();
                return;
             }
    
             [color="red"][b]// **** here is where I change the class fields with the entered values **** [/b][/color]
             rectX = Integer.parseInt(tokens[0].trim());
             rectY = Integer.parseInt(tokens[1].trim());
             rectWidth = Integer.parseInt(tokens[2].trim());
             rectHeight = Integer.parseInt(tokens[3].trim());
             drawRectangle = true; // change the sentinel boolean
             repaint();  // and tell the JPanel to repaint
          } catch (NumberFormatException e) {
             eraseDrawing();
             // show an error message
          }
       }
    
       private void eraseDrawing() {
          drawRectangle = false;
          repaint();
       }
    
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
       }
    
       @Override
       protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (drawRectangle) {
             g.drawRect(rectX, rectY, rectWidth, rectHeight);
          }
       }
    
       private static void createAndShowUI() {
          JFrame frame = new JFrame("DrawExample");
          frame.getContentPane().add(new DrawExample());
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                createAndShowUI();
             }
          });
       }
    }
    Last edited by Fubarable; 07-01-2011 at 06:38 PM.

  9. #9
    camickr is offline Senior Member
    Join Date
    Jul 2009
    Posts
    1,236
    Rep Power
    7

    Default

    my actual lines of "g.drawRec(50, 50, 10, 10);" needs to be inside paint component.
    So you know the proper way to do it and yet your example code doesn't do it this way?

    All components have "setter" methods (like setText, setIcon, setBackground) to change the properties of the component. If you want to change the line then you need a setter method and the paint component method needs to be aware of the new properties.

    It works:
    It only appears to work. Make the frame resizeable and resize the frame and see what happens.

    Also, use proper Java naming conventions. Classes should start with an upper case character.
    Last edited by camickr; 07-01-2011 at 06:29 PM.

  10. #10
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    I went over that code few times and i think i understand how it works, but i do have few questions to some parts of the code I have never seen before.


    my guess is that this checks if ok or cancel button is pressed? I really don't understand what is going on here, would you please explain?
    Java Code:
    int response = JOptionPane.showConfirmDialog(this, parameterPanel,
                   "Get Rectangle Parameters", JOptionPane.OK_CANCEL_OPTION);
          
          if (response != JOptionPane.OK_OPTION) {
             eraseDrawing();
             return;
    What exactly does this do? I get it over rides something but would you please explain when it is being used in the program?

    Java Code:
    @Override
    I don't understand what this part is doing at all
    Java Code:
    @Override
       public Dimension getPreferredSize() {
          return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
       }
    Will this part of the code activate every time the Boolean is switched to true? For example its like an action listener waiting to happen?
    Java Code:
    @Override
       protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (drawRectangle) {
             g.drawRect(rectX, rectY, rectWidth, rectHeight);
          }
       }

    what is invokeLater?
    Java Code:
    public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                createAndShowUI();
             }
          });
       }

    I apologies for so many questions, i understand how the program works though for most part.

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

    Default

    Quote Originally Posted by Bagzli View Post
    my guess is that this checks if ok or cancel button is pressed? I really don't understand what is going on here, would you please explain?
    Java Code:
    int response = JOptionPane.showConfirmDialog(this, parameterPanel,
                   "Get Rectangle Parameters", JOptionPane.OK_CANCEL_OPTION);
          
          if (response != JOptionPane.OK_OPTION) {
             eraseDrawing();
             return;
    Yes. The JOptionPane.showConfirmDialog returns an int. If the "OK" button was pressed, the int will be JOptionPane.OK_OPTION.


    What exactly does this do? I get it over rides something but would you please explain when it is being used in the program?

    Java Code:
    @Override
    This is an annotation. It will cause the compiler to throw an error if the method below it is not actually overriding a parent class method. It is not absolutely necessary but is a good habit to get into for safety's sake.

    I don't understand what this part is doing at all
    Java Code:
    @Override
       public Dimension getPreferredSize() {
          return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
       }
    Most layout managers respect a component's preferredSize, and this method is what is called by the layout managers to get that property. I've overridden it so that my component's preferredSize is constant.


    Will this part of the code activate every time the Boolean is switched to true? For example its like an action listener waiting to happen?
    Java Code:
    @Override
       protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (drawRectangle) {
             g.drawRect(rectX, rectY, rectWidth, rectHeight);
          }
       }
    No, this will be called when the JVM calls it. You can suggest to the JVM to call this by calling repaint() on your JPanel, and the JVM will call this if the operating system tells it to do so (for instance when you minimize and then restore the GUI's window).


    what is invokeLater?
    Java Code:
    public static void main(String[] args) {
          java.awt.EventQueue.invokeLater(new Runnable() {
             public void run() {
                createAndShowUI();
             }
          });
       }
    This will make the code that is within the runnable be called on the Event Dispatch Thread or EDT which is the main Swing thread. Doing this will help prevent the Swing code from crashing unexpectedly.

    You're coming along. Sorry for the confusing bits.
    Last edited by Fubarable; 07-01-2011 at 07:01 PM.

  12. #12
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    No, this will be called when the JVM calls it. You can suggest to the JVM to call this by calling repaint() on your JPanel, and the JVM will call this if the operating system tells it to do so (for instance when you minimize and then restore the GUI's window).
    How would i go about drawing multiple rectangles then when i press the same button? With your method they just redraw the same one.

  13. #13
    JosAH's Avatar
    JosAH is offline Moderator
    Join Date
    Sep 2008
    Location
    Voorschoten, the Netherlands
    Posts
    13,655
    Blog Entries
    7
    Rep Power
    21

    Default

    Quote Originally Posted by Bagzli View Post
    How would i go about drawing multiple rectangles then when i press the same button? With your method they just redraw the same one.
    Here's how I would do it: define a simple interface:

    Java Code:
    public interface Drawer {
       public void drawYourThing(Graphics g);
    }
    I think the class and method names don't need a further explanation. In your panel (that extends a JPanel), define the paintComponent( ... ) method like this:

    Java Code:
    public class YourPanel extends JPanel {
       private List<Drawer> drawers= new ArrayList<Drawer>(); // they draw on the panel
       ...
       public void paintComponent(Graphics g) {
          super.paintComponent(g); // wipe out everything
          for (Drawer d : drawers) // let them all draw something
             d.paintYourThing(g);
       }
    }
    All you have to do is implement the Drawer interface with whatever you want to draw and add them to the drawers List (add some methods for this to YourPanel) and voila.

    kind regards,

    Jos
    cenosillicaphobia: the fear for an empty beer glass

  14. #14
    camickr is offline Senior Member
    Join Date
    Jul 2009
    Posts
    1,236
    Rep Power
    7

    Default

    Did you read my suggestion about "setter" methods?

    Well, you need an "addRectangle" type of method that would store Rectangle objects in an ArrayList. Then the paintComponent() code would loop through the ArrayList and draw each Rectangle.

    See: Custom Painting Approaches « Java Tips Weblog

  15. #15
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    Ok so i'v been playing with this quite a lot today, i'v come my next stage of the program. These boxes represent boxes in real life. Each box has height, length, width and weight. I need to make each of these boxes a class of its own so they can have properties. If I do that do I have to extend JPanel in order to get paintComponent or will it work without extending JPanel.

    It just seems rather off having crap loads of panels, I know it is possible, just is this how I should go about it?

  16. #16
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    my idea is to have a class that will extend JPanel with a paint component and simply that class will draw one rectangle with dimensions stored in the class.

    something like this:
    Java Code:
    public class Box extends JPanel
    {
    	private int boxName;
    	private int height;
    	private int length;
    	private int width;
    	private boolean drawRect;
    	
    	public Box()
    	{
    		this.height = 0;
    		this.length = 0;
    		this.height = 0;
    	}
    	
    	@Override
    	protected void paintComponent(Graphics g) 
    	{
    	      super.paintComponent(g);
    	      if(drawRect)
    	      {
    	    	  g.drawRect(100, 100, length, width);
    	      }
    	}
    	public Box(int h, int l, int w)
    	{
    		this.height = h;
    		this.length = l;
    		this.height = w;
    		
    		if(h > 0 && l > 0 && w > 0)
    		{
    			drawRect = true;
    		}
    		
    		this.setVisible(true);
    	}
    	
    	public void setHeight(int h)
    	{
    		this.height = h;
    	}
    	public void setLength(int l)
    	{
    		this.length = l;
    	}
    	public void setWidth(int w)
    	{
    		this.width = w;
    	}
    	
    	public int getHeight()
    	{
    		return this.height;
    	}
    	public int getLength()
    	{
    		return this.length;
    	}
    	public int getWidth()
    	{
    		return this.width;
    	}
    }
    So far I wasn't able to get it to work...

  17. #17
    camickr is offline Senior Member
    Join Date
    Jul 2009
    Posts
    1,236
    Rep Power
    7

    Default

    ... or will it work without extending JPanel.
    You need to extend a class if you are going to have special properties for the class because you will need getter/setter methods.

    However, you don't need to extend the class to draw a Rectangle. For this you can use use a LineBorder.

    See: How to Use Borders (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Swing Components)

    Also, if you ever do need to do custom painting then you also need to override the getPreferredSize() method to give the component a size. See: Lesson: Performing Custom Painting (The Java™ Tutorials > Creating a GUI With JFC/Swing)

    Take a look at the table of contents there is all kind of advice and examples for Swing coding.

  18. #18
    Bagzli is offline Member
    Join Date
    Feb 2011
    Posts
    63
    Rep Power
    0

    Default

    ok but the problem with that is, this program is representing a truck being loaded with boxes, so boxes can't be drawn over one another and I need to be able later with mouse to left click a box and drag it anywhere i want, for this reason i was going with paintComponent. From what you guys advised me it was the best way.

    Also with using LineBorder what exactly is my class then? What am I extending to make it work?

  19. #19
    camickr is offline Senior Member
    Join Date
    Jul 2009
    Posts
    1,236
    Rep Power
    7

    Default

    Your question is about "learning to draw shapes", so yes this is done by overriding the paintComponent() method and doing custom painting. You where given an example of how to draw multiple shapes on the same panel.

    Now your question is about dragging objects in this case a rectangular object. There is no need for a custom object for this simple requirement:

    a) create a JLabel (or JPanel)
    b) give the component a preferred size
    c) add a Border to the component
    d) add the component to your frame.

    If you need more help post your SSCCE in a new posting because this thread is getting off topic.

Similar Threads

  1. PAINTCompnent
    By sims in forum New To Java
    Replies: 4
    Last Post: 08-08-2008, 03:38 PM

Posting Permissions

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