Java JLayeredPane内容在刷新时闪烁

时间:2014-01-11 16:21:28

标签: java swing loops refresh flicker

我在NetBeans中有一个项目,它使用分层窗格通过在必要时在它们之间切换来显示重叠的面板。启动时,程序在其中一个面板上显示一个介绍动画(在一个单独的线程上运行),由以下内容实现:

public class IntroPanel extends javax.swing.JPanel implements Runnable {

private boolean finished;
private int opacity;
private JLabel[] labels = new JLabel[3];

public IntroPanel() {
    initComponents();
    labels[0] = jLabel1;
    labels[1] = jLabel2;
    labels[2] = jLabel3;
}

@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    for(JLabel label : labels)
        label.setForeground(new Color(200,200,200,opacity));
}

@Override
public void run(){
    while (!finished) {            
        while (opacity < 255) {
            try {
                Thread.sleep(30);
                opacity += 5;
                repaint();
            } catch (InterruptedException ex) {
                Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    try {
        repaint();
        Thread.sleep(3000);
    } catch (InterruptedException ex) {
        Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
    while (opacity > 0) {
        try {
            Thread.sleep(30);
            opacity -= 5;
            repaint();
        } catch (InterruptedException ex) {
            Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException ex) {
            Logger.getLogger(IntroPanel.class.getName()).log(Level.SEVERE, null, ex);
        }
    finished = true;
    }
}

预期的效果是让三个JLabel淡入,在屏幕上停留一会儿然后淡出。前两个标签包含大字体的斜体文本,第三个包含小字体。这里的问题:

  1. 前两个标签的文字在淡入或淡出时显示为非斜体,仅在标签不褪色时短暂变为斜体。
  2. 第三个标签(小字体,非斜体)不会褪色,而是在重画循环中快速上下摇动。
  3. 我读到了如何编写自己的主动渲染方法而不是使用paintComponent(),而是使用以下代码替换paintComponent()更好的主意:

    public void render() {
        Graphics g = getGraphics();
        for(JLabel label : labels)
            label.setForeground(new Color(200,200,200,opacity));
        g.dispose();
    }
    

    做同样的闪烁。我在这里遗漏了什么东西,或者循环重绘和分层帧只是不混合?

1 个答案:

答案 0 :(得分:1)

  1. 您不应该在该方法的paintComponent中执行任何代码。那应该在你的程序的另一个区域。 paintComponent仅用于绘制,不用于设置状态。
  2. 你的while循环应该被Swing Timer取代,这就是setForground调用的地方。
  3. 您应该发布一个我们可以编译运行和测试的最小值complete valid, example, a small program。您的代码不允许这样做。

  4. 例如:

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.*;
    
    public class IntroPanel extends JPanel {
       private static final int DELAY_TIME = 5;
       protected static final Color FG_COLOR = Color.blue;
       private List<JLabel> labelList = new ArrayList<JLabel>();
       private List<Color> colorList = new ArrayList<>();
    
       public IntroPanel() {
          for (int i = 0; i < 255; i++) {
             colorList.add(new Color(0, 0, 255, i));
          }
          for (int i = 0; i < 255; i++) {
             colorList.add(new Color(0, 0, 255, 255 - i));
          }
    
          setLayout(new GridLayout(0, 1));
    
          JLabel label1 = new JLabel("Label 1");
          label1.setFont(label1.getFont().deriveFont(Font.ITALIC, 24));
          add(label1);
          labelList.add(label1);
          JLabel label2 = new JLabel("Label 2");
          label2.setFont(label2.getFont().deriveFont(Font.ITALIC, 24));
          add(label2);
          labelList.add(label2);
          JLabel label3 = new JLabel("Label 3");
          label3.setFont(label3.getFont().deriveFont(Font.PLAIN, 10));
          add(label3);
          labelList.add(label3);
    
          new Timer(DELAY_TIME, new ActionListener() {
             private int index = 0;
    
             @Override
             public void actionPerformed(ActionEvent evt) {
                if (index < colorList.size()) {
                   for (JLabel label : labelList) {
                      label.setForeground(colorList.get(index));
                   }
                   index++;
                } else {
                   ((Timer)evt.getSource()).stop();
                }
             }
          }).start();
       }
    
       private static void createAndShowGUI() {
          IntroPanel paintEg = new IntroPanel();
    
          JFrame frame = new JFrame("IntroPanel");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(paintEg);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGUI();
             }
          });
       }
    }