【问题标题】:JLabel on JPanel doesn't update when setText from another method当来自另一个方法的 setText 时,JPanel 上的 JLabel 不会更新
【发布时间】:2015-07-12 16:59:01
【问题描述】:

感谢您的帮助。我是一个新手,正在尝试一些非常简单的事情。 我想要一个带有每隔几秒钟更改一次的文本(JLabel)的窗口(面板)。整个应用程序运行良好,除了正在更新的 JLabel(文本确实更改),但它没有显示在窗口(面板)上。即使我有检查点告诉我 JLabel 的文本正在更新和更改,该窗口从头到尾保持相同的文本。我到处寻找相同的问题并找到了一些 cmets,但没有任何帮助。有人说是 ActionListener,但是当我摆脱它时,它并没有什么不同。有人说线程中的循环不会让 JLabel 刷新,所以我尝试使用 JLabel 并且它的更新位于单独的线程上,但这也不起作用。我唯一没有尝试过的是使用 swingWorker (不太清楚如何)。线程尝试使用具有可运行方法的线程类。同样,这种方式一切正常,除了 JLabel 没有重新绘制自己。

这是没有线程的代码。这一切都在一个类中。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.*;





public class SWUI extends JFrame implements ActionListener {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private JPanel panel;
    JLabel label;
    private Font font;


    //Set up the interface. SWUI is working perfectly
SWUI() {

        System.out.println("run started");      //just to check that the method gets called.
        panel = new JPanel();
        panel.setLayout(new BorderLayout(1, 1));
        panel.setPreferredSize(new Dimension(1000, 400));
        panel.setBackground(Color.white);
        getContentPane().add(panel);

        label = new JLabel("Ready");                    //These four statements are working
        label.setHorizontalAlignment(JLabel.CENTER);
        font = new Font("Comic Sans MS", Font.PLAIN, 70);
        label.setFont(font);

        panel.add(label, BorderLayout.CENTER);

        System.out.println("run done and draw to start");

        label.setText("label is updatable");        //Checks that the whole method gets done and that the label is indeed able to get updated. It works.

    }


// draw() mostly sets the Frame up, names it, sets closing behavior. It's working.
    public void draw() {

        System.out.println("draw started");         //To check that the method is getting invoked.

        SWUI frame = new SWUI();
        frame.setTitle("Sight Words Rock");

        WindowListener l = new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
           System.exit(0);
         }
      };
        frame.addWindowListener(l);

        frame.pack();
        frame.setVisible(true);

        System.out.println("draw done");        //To check that the whole method went through. It's all working.

    }



    //Should change the label to 4 sentences every 1 second. The text of the label does change, but it doesn't show on the interface (panel).
    private void updateLabel(String word){

        label.setText(word);

        //label.revalidate();       //I tried these three statements one at a time and both together and they made no difference.
        //label.updateUI();
        //label.repaint();

        System.out.println("The label now is: "+ label.getText());   //This confirms that the setText() is indeed changing the text
                                                                    // of the label, but it doesn't show on the interface.
    }


    //Main gets the draw() started to initiate the interface and gets the sentences changed and sent to updateLabel() every second.
    public static void main(String args[]) 

        throws InterruptedException {

        SWUI ui = new SWUI();
        ui.draw();


        String importantInfo[] = {
            "Mares eat oats",
            "Dogs eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };

        for (int i = 0;
             i < importantInfo.length;
             i++) {
            //Pause for 1 second
            Thread.sleep(1000);

            //Print a message
            System.out.println(importantInfo[i]);

            ui.label.setText(importantInfo[i]);
            ui.updateLabel(importantInfo[i]);
        }

    }

    //This will come later once I figure how to fix the label. Someone else suggested that the problem were the listeners not letting the thread
    // do the repainting(), but I tried getting rid of the "implements ActionListener" and the actionPerformed methods and it didn't make a
    // difference. It still didn't work.
    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub

    }
}

【问题讨论】:

  • 那么你从哪个线程调用setText?请记住,Swing 组件的所有更新都必须在 EDT 上进行,如果您需要从另一个线程触发更新,请使用 SwingUtilities.invokeLater
  • 1) 使用逻辑一致的形式缩进代码行和块。缩进是为了让代码流更容易理解! 2) 曾经只需要源代码中的一个空白行。 { 之后或 } 之前的空行通常也是多余的。

标签: java swing jlabel settext


【解决方案1】:

SWUI 中的 draw 方法会创建一个全新的框架,而您的更新会转到从未真正设置为可见的初始框架。要解决这个问题,您的 draw 方法应该看起来更像这样。

public void draw() {

        System.out.println("draw started");         //To check that the method is getting invoked.

        setTitle("Sight Words Rock");

        WindowListener l = new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
           System.exit(0);
         }
      };
        addWindowListener(l);

        pack();
        setVisible(true);
    System.out.println("draw done");        //To check that the whole method went through. It's all working.

}

【讨论】:

  • 非常感谢 pvg 提供彻底而清晰的解释。效果很好。
  • System.exit(0);在 windowClosing == JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
  • 随时添加编辑@mKorbel。我并没有真正搞砸它,缩进是便便,最好不要从子类 JFrame 开始,有很多方法可以更好。
猜你喜欢
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 2014-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多