标签移动时未调用paintComponent [英] paintComponent not being called when label moved

查看:75
本文介绍了标签移动时未调用paintComponent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 JPanel (otherJPanel),下面带有标签,都位于另一个 JPanel (mainJPanel)中. mainJPanel覆盖paintComponent,并且在其他位置手动调用repaint(),并且动态设置标签文本和otherJPanel的背景.

I have a simple JPanel (otherJPanel) with a label below, both inside another JPanel (mainJPanel). mainJPanel overrides paintComponent, and repaint() is called manually elsewhere and the label text and the background of otherJPanel are set dynamically.

但是,当我将标签移动到otherJPanel内时,将永远不会调用paintComponent.知道为什么吗?

However, when I move the label inside otherJPanel then paintComponent is never called. Any idea why?

要对此进行测试,我创建了下面的测试项目,两个位置均带有标签.但是,由于在处理循环中未调用此paintComponent,我在做什么错了?

To test this I have created the test project below with labels in both positions. However, with this paintComponent is not called within the processing loop, what am I doing wrong?

package uk.co.moons.gui.components.testapps;

import java.util.logging.Level;
import java.util.logging.Logger;

public class DisplayJFrame extends javax.swing.JFrame {

/** Creates new form DisplayJFrame */
public DisplayJFrame() {
    initComponents();
}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    displayJPanel1 = new uk.co.moons.gui.components.DisplayJPanel();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setName("Form"); // NOI18N

    displayJPanel1.setName("displayJPanel1"); // NOI18N
    getContentPane().add(displayJPanel1, java.awt.BorderLayout.CENTER);

    pack();
}// </editor-fold>                        


public void draw() {       
    displayJPanel1.revalidate();
    displayJPanel1.repaint();
}

public void setTO(TestObject to) {
    displayJPanel1.setTo(to);        
}

public static void main(String args[]) {
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(DisplayJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(DisplayJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(DisplayJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(DisplayJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {

        public void run() {
            DisplayJFrame df = new DisplayJFrame();
            df.setVisible(true);
            TestObject to = new TestObject();
            df.setTO(to);
            for (int i = 10; i < 20; i++) {
                to.setValue(i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    Logger.getLogger(DisplayJFrame.class.getName()).log(Level.SEVERE, null, ex);
                }

                df.draw();//df.repaint();
            }
        }
    });
}



// Variables declaration - do not modify                     
private uk.co.moons.gui.components.DisplayJPanel displayJPanel1;
// End of variables declaration                   
}







package uk.co.moons.gui.components;

import java.awt.Graphics;
import uk.co.moons.gui.components.testapps.TestObject;

public class DisplayJPanel extends javax.swing.JPanel {

    private TestObject to = null;

/** Creates new form DisplayJPanel */
public DisplayJPanel() {
    initComponents();
}

public TestObject getTo() {
    return to;
}

public void setTo(TestObject to) {
    this.to = to;
}

@Override
public void paintComponent(Graphics g) {
    System.out.println("paintComponent");
    super.paintComponents(g);
    if (to != null) {
        int i = to.getValue();
        System.out.println("paintComponent " + i);
        jLabel1.setText(String.valueOf(i));
        jLabel2.setText(String.valueOf(i + 1));
    }
}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

    jPanel1 = new javax.swing.JPanel();
    jLabel2 = new javax.swing.JLabel();
    jLabel1 = new javax.swing.JLabel();

    setName("Form"); // NOI18N
    setLayout(new java.awt.BorderLayout());

    jPanel1.setName("jPanel1"); // NOI18N
    jPanel1.setLayout(new java.awt.BorderLayout());

    jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
    org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(uk.co.moons.gui.controlpanel.ControlPanelApp.class).getContext().getResourceMap(DisplayJPanel.class);
    jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
    jLabel2.setBorder(javax.swing.BorderFactory.createEtchedBorder());
    jLabel2.setName("jLabel2"); // NOI18N
    jPanel1.add(jLabel2, java.awt.BorderLayout.CENTER);

    add(jPanel1, java.awt.BorderLayout.CENTER);

    jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
    jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
    jLabel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
    jLabel1.setName("jLabel1"); // NOI18N
    add(jLabel1, java.awt.BorderLayout.PAGE_END);
}// </editor-fold>
// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JPanel jPanel1;
// End of variables declaration
}



package uk.co.moons.gui.components.testapps;

public class TestObject {
    private int value=0;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

推荐答案

您正在Swing事件线程上调用Thread.sleep(...),这将导致整个应用程序进入睡眠状态:

You're calling Thread.sleep(...) on the Swing event thread which is causing your entire application to sleep:

        for (int i = 10; i < 20; i++) {
           to.setValue(i);
           try {
              Thread.sleep(100);
           } catch (InterruptedException ex) {
              Logger.getLogger(DisplayJFrame.class.getName()).log(
                    Level.SEVERE, null, ex);
           }

           df.draw();
        }


不要这样做;请改用Swing计时器.


Don't do this; use a Swing Timer instead.

     public void run() {
        final DisplayJFrame df = new DisplayJFrame();
        df.setVisible(true);
        final TestObject to = new TestObject();
        df.setTO(to);

        int timerDelay = 100;
        final int maxCount = 20;
        new Timer(timerDelay, new ActionListener() {
           private int count = 0;

           @Override
           public void actionPerformed(ActionEvent evt) {
              if (count < maxCount) {
                 df.repaint();
                 to.setValue(count);
                 count++;
              } else {
                 ((Timer) evt.getSource()).stop();
              }
           }
        }).start();
        // for (int i = 10; i < 20; i++) {
        // to.setValue(i);
        // try {
        // Thread.sleep(100);
        // } catch (InterruptedException ex) {
        // Logger.getLogger(DisplayJFrame.class.getName()).log(
        // Level.SEVERE, null, ex);
        // }
        //
        // df.draw();
        // }
     }


也是无关的问题,但是super.paintComponents(g);不是paintComponent(g)方法的超级.在paintComponent s 末尾的 s 会让您大跌眼镜.


Also unrelated problem, but super.paintComponents(g); is not the super for the paintComponent(g) method. That s on the end of paintComponents will mess you up royal.

// TODO: delete this method
public void paintComponent(Graphics g) {
  System.out.println("paintComponent");
  // super.paintComponents(g); // *** !! No -- this is not the super method ***
  super.paintComponent(g);
  if (to != null) {
     int i = to.getValue();
     System.out.println("paintComponent " + i);

     // of course you'll never set a JLabel's text from within this method
     jLabel1.setText(String.valueOf(i));
     jLabel2.setText(String.valueOf(i + 1));
  }
}


修改
您在评论中声明:


Edit
You state in comments:

好吧,为什么我不想在paintComponent内设置JLabel的文本?

Ok, why would I not want to set a JLabel's text inside paintComponent?

paintComponent方法仅适用于绘画.出于多种原因,不应将其用于设置程序或组件的状态,其中包括您无法完全控制何时甚至调用此方法(如您所发现的),以及因此而导致的状态.代码不应该依赖于它的调用.

The paintComponent method is for painting and painting only. It should not be used to set the state of the program or components for several reasons including that you don't have full control over when or even if this method is called (as you're finding out), and so the state of your code should not depend on its getting called.

无论何时调用重画,我应该如何更新JLabel?

How should I get the JLabel to update whenever repaint is called?

同样,您不应使用重新绘画来触发此操作. JLabel应该显示什么?为什么您认为必须在重涂时更改它?

Again, you should not use repainting to trigger this. What is the JLabel supposed to display? Why do you feel that it must change on a repaint?

编辑2

我以为paintComponent是这样做的地方.我的显示器包含许多嵌套组件的层次结构,这些组件的标签和背景不断变化.我应该从主处理循环中检索组件并在那里设置值,而不是使用paintComponent?

I thought paintComponent was the place to do it. My display comprises a hierarchy of many nested components the labels and backgrounds of which are continuously changing. Rather than using paintComponent should I be retrieving the components from my main processing loop and setting the values there?

否,不允许外部类像这样直接操纵您的视图.相反,请分离模型并查看并使用诸如PropertyChangeListener之类的侦听器以及公共方法来为您完成此操作.

No, don't allow outside classes to directly manipulate your view like so. Instead separate out your model and view and use listeners such as a PropertyChangeListener as well as public methods to do this for you.

例如,您可以通过将TestObject的value字段设置为绑定属性"来轻松更新JLabel文本.可以通过为该类提供一个PropertyChangeSupport对象(实际上是因为它是Swing,一个SwingPropertyChangeSupport对象)来轻松完成此操作,并允许外部类像这样监听值的值更改:

For instance, you can easily update your JLabel text by making your TestObject's value field a "bound property". This can easily be done by giving the class a PropertyChangeSupport object (actually since this is Swing, a SwingPropertyChangeSupport object), and allow outside classes to listen to changes in the value's value like so:

class DisplayJPanel extends javax.swing.JPanel {

   private TestObject to = null;

   public DisplayJPanel() {
      initComponents();
   }

   public TestObject getTo() {
      return to;
   }

   public void setTo(final TestObject to) {
      this.to = to;

      // add listener to listen and react to changes in to value's state
      to.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if (TestObject.VALUE.equals(evt.getPropertyName())) {
               setLabel2Text(String.valueOf(to.getValue()));
            }
         }
      });
   }

   private void initComponents() {

      // etc...

   }

   public void setLabel2Text(String text) {
      jLabel2.setText(text);
   }

   private javax.swing.JLabel jLabel2;
   private javax.swing.JPanel jPanel1;
}

class TestObject {
   public static final String VALUE = "value";
   private int value = 0;
   private SwingPropertyChangeSupport propChangeSupport = new SwingPropertyChangeSupport(this);

   public int getValue() {
      return value;
   }

   public void setValue(int value) {
      int oldValue = this.value;
      int newValue = value;
      this.value = newValue;

      propChangeSupport.firePropertyChange(VALUE, oldValue, newValue);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      propChangeSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      propChangeSupport.removePropertyChangeListener(listener);
   }

}

这篇关于标签移动时未调用paintComponent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆