【问题标题】:JPanel doesn't update until resize JframeJPanel 在调整 Jframe 大小之前不会更新
【发布时间】:2012-06-19 15:40:24
【问题描述】:

我将 JPanel 子类化以覆盖paintComponent(Graphics),我想在 jframe 中将图像绘制到 jpanel 上。

但是直到我更改 jframe 的大小后,我的图像才显示出来。 这是我的代码:

public class ImagePanel extends JPanel{

    public void setImage(BufferedImage bi)
    {
        image = bi;
        revalidate();
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if(image != null)
        {
            g.drawImage(image, 0, 0, this);
        }
    }
}

【问题讨论】:

    标签: java swing user-interface paintcomponent


    【解决方案1】:

    验证您是否在添加组件并调用pack() 之后调用setVisible(),如相关example 中所述。您可能还需要采用适当的layout。按照建议here 调用repaint() 可能会解决症状,但不能解决根本原因。

    【讨论】:

      【解决方案2】:

      如果你想“刷新”JPanel,那么你应该调用repaint(),它会调用你的paintComponent()。这应该可以解决您的问题:

      public void setImage(BufferedImage bi)
      {
          image = bi;
          EventQueue.invokeLater(new Runnable()
          {
              public void run()
              {
                  repaint();
              }
          });
      }
      

      使用 EDT 更新和更改 GUI 是一种很好的做法。如果您有兴趣,这里有更多关于 EDT 的信息:

      How does the event dispatch thread work?

      repaint 不需要从 EDT 调用。如果要更改 GUI,例如将文本设置为 JLabel,则它应该位于 EDT 内部。以下是关于在 EDT 之外可以调用什么的更多信息(由 nIcE cOw 提供):

      Safe to use Component.repaint() outside EDT?

      【讨论】:

      • +1 表示有价值的输入。只是一个建议,不需要在 EDT 中调用 repaint(),因为从任何线程调用 repaint() 都是安全的,如 here 所述
      • "具有 UI 委托的 Swing 组件的子类......应该调用 super.paintComponent()"—The Paint Methods
      【解决方案3】:

      查看the docs 中的JPanel.add(),它继承自java.awt.Container

      将指定的组件附加到此容器的末尾。这是 addImpl(java.awt.Component, java.lang.Object, int) 的便捷方法。 此方法更改与布局相关的信息,因此 使组件层次结构无效。如果容器已显示,则必须随后验证层次结构才能显示添加的组件。

      已添加重点。

      因此,如果您在容器显示之后对其进行修改,则必须调用validate() 以使其显示。仅仅调用repaint() 是不够的。您可能已经注意到调用setVisible(true) 也可以;这是因为it calls validate() internally

      【讨论】:

      • 我使用revalidate() 获得了更好的结果。 validate() 完成了这项工作,但它不会更改尺寸以适应添加的新组件。
      • @Chameleon 虽然现在有点晚了,但我认为这是因为你没有覆盖 getPreferredSize
      【解决方案4】:

      我遇到了同样的问题并通过调用 setVisible(true); 修复了它我正在使用的 JFrame。

      示例:如果您的 JFrame 在使用后没有更新:

      jframe.setContentPane(new MyContentPane());
      

      修复它:

      jframe.setContentPane(new MyContentPane());
      jframe.setVisible(true);
      

      我知道即使您的 JFrame 已经可见,这样做听起来很愚蠢,但这是我迄今为止找到的解决此问题的唯一方法(上面提出的解决方案对我不起作用)。

      这是一个完整的例子。运行它,然后取消注释“f.setVisible(true);” Panel1 和 Panel2 类中的说明,您会看到不同之处。不要忘记导入(Ctrl + Shift + O 用于自动导入)。

      主类:

      public class Main {
          private static JFrame f;
          public static void main(String[] args) {
              f = new JFrame();
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              f.setContentPane(new Panel1(f));
              f.pack();    
              f.setVisible(true);
          }
      }
      

      Panel1 类:

      public class Panel1 extends JPanel{
          private JFrame f;
          public Panel1(JFrame frame) {
              f = frame;
              this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
              JButton b = new JButton("Panel 1");
              b.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      f.setContentPane(new Panel2(f));
                      // Uncomment the instruction below to fix GUI "update-on-resize-only" problem
                      //f.setVisible(true);
                  }
              });
              add(b);
          }
      }
      

      Panel2 类:

      public class Panel2 extends JPanel{
          private JFrame f;
          public Panel2(JFrame frame) {
              f = frame;
              this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
              JButton b = new JButton("Panel 2");
              b.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      f.setContentPane(new Panel1(f));
                      // Uncomment the instruction below to fix GUI "update-on-resize-only" problem
                      //f.setVisible(true);
                  }
              });
              add(b);
          }
      }
      

      希望对您有所帮助。

      问候。

      【讨论】:

      • 完美!不知道为什么会这样,但这是解决我问题的唯一方法。在此之前,我是这样做的:Dimension size = frame.getSize();布尔最大化 = frame.getExtendedState() == JFrame.MAXIMIZED_BOTH; frame.setSize(new Dimension((int)size.getWidth()-1,(int)size.getHeight()-1)); if (最大化) frame.setExtendedState(JFrame.MAXIMIZED_BOTH);否则 frame.setSize(大小);您的答案要干净得多,而且不那么老套。谢谢!
      • @dberm22 实际上,不需要乱搞(至少在这个例子中没有,没有检查原始图像可能不同大小的图像,也没有扩展尺寸状态,这也可能很棘手) : 设置 contentPane 是对框架容器层次结构的修改,因此需要对框架进行重新验证。
      【解决方案5】:

      我也有同样的问题,但我找到了解决方案。只需在顶部创建一个jframe 对象并在底部调用jframe 方法,如jf.pack()jf.setVisible()jf.setSize()jf.setDefaultCloseOpetion() 应该位于该框架中添加的所有 UI 的底部,您会发现它工作得很好。

      【讨论】:

        猜你喜欢
        • 2016-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-29
        • 1970-01-01
        • 2012-09-01
        相关资源
        最近更新 更多