JFrame does not add component when JButton is pres

2020-05-09 17:00发布

问题:

My code is basically about having a frame and it has a button. You press the button you can draw rectangles, getting coordinates from the mouse press and the mouse release.

Now, if you remove the button the code works perfectly, here is the code.

//testing file

package ActionTest;    
import java.awt.*;
import javax.swing.*;    

public class MouseTest
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(new Runnable()
         {
            public void run()
            {
               JFrame frame = new MouseFrame();
               frame.setTitle("MouseTest");
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               frame.setVisible(true);
               frame.setSize(500,500);
            }
         });
   }
}

My frame, calls on the mouse component

package ActionTest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class MouseFrame extends JFrame
{           
   public MouseFrame()
   {       
      add(new MouseComponent());                   
   }
}

The component class: handles mouse clicks and drawing the rectangle

package ActionTest;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class MouseComponent extends JComponent
{    
   Point first;
   Point second;
   private ArrayList<Rectangle2D> rectangles;

   public MouseComponent()
   {
      rectangles = new ArrayList<>();//contains rectangles
      addMouseListener(new MouseHandler());
   }
   //paint method of the component, simply re-paint the array
   public void paintComponent(Graphics g)
   {
      Graphics2D g2 = (Graphics2D) g;
      for (Rectangle2D r : rectangles)
         g2.draw(r);
   }


   /**
    * creates a rectangle and adds it to the rectangles ArrayList
    * then repaint the component
    * inside some operations to deal with rectangle drawing nothing to do with the issue
    * @param p1: first coordinates
    * @param p2: second coordinates
    */
   public void addRec(Point2D p1, Point2D p2)
   {
       double w, h, x, y;
       double x1 = p1.getX();
       double y1 = p1.getY();
       double x2 = p2.getX();
       double y2 = p2.getY();
       if(x1 <= x2){
           x = x1;
           w = x2-x1;        
       }
       else{
           x = x2;
           w = x1-x2;           
       }
       if (y1 <= y2){
           y = y1;
           h = y2-y1;           
       }
       else{
           y = y2;
           h = y1-y2;           
       }
      rectangles.add(new Rectangle2D.Double(x, y, w, h));
      repaint();
   }


   //records mouse click and mose release
   //you press the mouse that is the 1st coordinates
   //you release it that is the 2nd coordinates
   //pass both to the addRec method
   private class MouseHandler extends MouseAdapter
   {
      @Override
      public void mousePressed(MouseEvent event)
      {          
          first = event.getPoint();
      }
      @Override
      public void mouseReleased(MouseEvent event)
      {
          second = event.getPoint();          
          addRec(first, second);
      }
   }
}

It works perfectly. However, going back to the original problem, if I add a button, and then when the button pressed go ahead and begin drawing rectangles it doesn't work.

Here is the modified frame class

package ActionTest;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class MouseFrame extends JFrame
{    
   private JPanel buttonPanel;
   public MouseFrame()
   {       

       JFrame frame = this;
       buttonPanel = new JPanel();
       JButton rec = new JButton("Rectangle");
       rec.addActionListener(new ActionListener(){        
           public void actionPerformed(ActionEvent event)
           {         
               System.out.println("pressed");                   
               frame.add(new MouseComponent());                
           }});
       buttonPanel.add(rec);
       add(buttonPanel);            
   }
}

Thanks in advance.

回答1:

frame.add(new MouseComponent());   

The size of a newly created component is (0, 0) so there is nothing to paint. So you need to invoke the layout manager when you add a component to a visible GUI.

frame.add(new MouseComponent());   
frame.revalidate();
frame.repaint();

Note this will only work if the layout manager allows you to add multiple components to the frame. The default layout manager for a frame is the BorderLayout and only a single components can be added to the CENTER of the BorderLayout.

So maybe you need to add the button using:

frame.add(button, BorderLayout.PAGE_START);

Read the section from the Swing tutorial on How to Use Layout Managers for more information and working examples.

Also, any time you do custom painting you need to override the getPreferredSize() method of the custom component so the layout managers can do their job.