从另一个 Runnable 内部运行 Runnable 的 Java 将不起作用



为什么下面的代码不能工作?基本上,这是一个更困难的程序的简化版本,我试图使一个可运行的初始屏幕与选择,然后有按钮链接到不同的可运行的,但这并没有像我预期的那样运行。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Runnables {
    static Runnable runone;
    static Runnable runtwo;
    static JFrame frame = new JFrame();
    static JButton button1 = new JButton("Initial screen");
    static JButton button2 = new JButton("After button click screen");
    public static void main(String[] args) {
        runone = new Runnable() {
            @Override
            public void run() {
                frame.removeAll();
                frame.revalidate();
                frame.repaint();
                frame.add(button2);
            }
        };
        runtwo = new Runnable() {
            @Override
            public void run() {
                frame.setSize(800, 600);
                frame.setVisible(true);
                button1.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        runone.run();
                        System.out
                                .println("This is performed, but the button doesnt change");
                    }
                });
                frame.add(button1);
            }
        };
        runtwo.run();
    }
}

Runnable没有什么特别的东西会阻止它工作。正如您的代码样例所示,以下是等价的:

public void actionPerformed(ActionEvent arg0) {
    runone.run();
    System.out.println("This is performed, but the button doesnt change");
}

public void actionPerformed(ActionEvent arg0) {
    frame.removeAll();
    frame.revalidate();
    frame.repaint();
    frame.add(button2);
    System.out.println("This is performed, but the button doesnt change");
}

拿出你的代码,在runone.run中添加一个System.out.println调试语句,显示它实际上正在执行。

我假设你的代码样本是你的问题的简化演示;你可能想让它首先作为一个"普通函数"做你想做的事情(我上面的第二个例子,其中Runnables是组合的),然后将其分离成不同的Runnables。

编辑 -让你的例子工作,要记住的是,JFrame使用一个contentPane来托管它的孩子- frame.add的存在是为了方便添加到contentPane(基于javadoc for JFrame),但removeAll不这样做(基于我刚才玩它)。此外,在添加按钮后调用validate将再次正确地重新布局子组件,以使第二个按钮出现。

runone的定义替换为下面的定义,您的示例将正常工作:

runone = new Runnable() {
    @Override
    public void run() {
        frame.getContentPane().removeAll();
        frame.add(button2);
        frame.validate();
    }
};

您应该首先将Runnable对象封装在Thread对象中,然后通过调用start()来启动线程。例如:

Runnable r = ...;
Thread thread = new Thread(r);
thread.start();


编辑:

您应该确保从EDT调用您的Runnable。例如:

SwingUtilties.invokeLater(r);

或者您可以使用SwingWorker来处理swing代码中涉及的密集操作。

最新更新