【问题标题】:How to automatically execute a task after JFrame is displayed, from within it?如何在显示 JFrame 后从其中自动执行任务?
【发布时间】:2016-09-19 04:39:30
【问题描述】:

如何在(类扩展)JFrame 显示后立即自动执行任务(使用工作线程),同时尽可能在扩展 JFrame 的类中维护该任务的起始代码?

我找到的所有示例,以及到目前为止我自己是如何使用它的,仅显示 GUI 类扩展,其代码在启动和显示 GUI 后对输入作出反应,任何自动启动和显示 GUI 的代码之外进行的进一步操作;换句话说,我(做/不做)看到的是下面示例代码中的注释:

public static void main(String args[]) {
    //Set the Look and Feel
    //...

    //Create and display the form
    java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            new MyFrame().setVisible(true); //<--- I never see automatic stuff happening
            //...within here (class). I realize it can be done overriding setVisible(), but
            //...that would be cheating in regards to the intent of this question.
        }
    });

    //In the examples I found, and the way I have done it myself, automatic
    //..."after GUI is displayed" actions, such as a starting a worker that will load
    //...something heavy on startup, while the GUI displays a progressar, are started here.
}

是否可以在MyFrameJFrame 的任何扩展)内执行任务,例如触发事件、启动工作程序或以其他方式执行一些不相关的代码,而无需在setVisible() 或组件的其他初始化方法(以其他方式无法完成的方式)?

如果可以的话,怎么做?


额外的小问题: 假设有可能,对于 NetBeans 的 GUI-builder 自动生成的代码或类似结构的代码,是否有任何建议?

【问题讨论】:

    标签: java swing user-interface netbeans task


    【解决方案1】:

    是的,有可能。


    想到了几种可能的解决方案,用于处理这两种情况;如果您只需要在第一次(例如启动时)或多次(每次显示窗口或组件时)执行任务:

    • 在其中添加一个WindowListenerJFrame,并让它在windowOpened(WindowEvent e) 中启动操作/工作人员,这是“在第一个显示监听窗口之后调用时间”
    • 在其中添加一个ComponentListenerJFrame,并让它在componentShown(ComponentEvent) 中启动操作/worker,这是“在侦听组件变得可见后调用正在调用 setVisible 方法”

    other listeners 的类似解决方案也是可能的,但这些可能是最好的方法,对于任何奇怪的情况,从这两个中,您应该了解如何实现其他变体。


    奖励答案: 添加侦听器的最佳位置是在其他组件初始化之后。在 NetBeans 中,初始化代码是自动生成的,包含在方法 (initComponents()) 中,并且大部分是锁定的(可能是为了避免修补会破坏与可视 GUI 构建器相关的内容)。

    由于侦听器与任何组件(除了框架本身;或您正在扩展的“基础”组件)无关,因此将这个侦听器添加与其余初始化代码(包括其他负责操作 GUI 子组件的侦听器),因此 NetBeans 锁定初始化代码是这种分离的一种方便的实施方式,实际上有助于保持代码的清洁和可读性。

    在这种情况下,我们仍然在初始化之后立即添加侦听器,但在构造函数中而不是在initComponents() 方法中;并且由于“addSomeListener()”方法是可重写的,并且至少在这个例子中,我们不想在扩展上意外“忘记”这段代码,我们与自动生成的代码类似,并包装我们的自指向“ addSomeListener()" 方法(和其他操作,如果需要)在我们自己的 initSomething() 方法中!

    这是一个代码示例:

    //Within -> public class MyFrame extends javax.swing.JFrame {
    
    //This is a mockup worker to simulate some time-consiming loading task that would be performed at startup, with the GUI providing a loading screen...
    SwingWorker<Integer, Integer> StartupLoader = new SwingWorker<Integer, Integer>() {
        @Override
        protected Integer doInBackground() throws Exception {
            for (int i = 0; i < 100; i++) {
                System.out.println("Some time consuming task is at " + i + "%...");
            }
            return 100;
        }
    };
    
    //This method is used to avoid calling an overridable method ('addWindowListener()') from within the constructor.
    private void initSelfListeners() {
        WindowListener taskStarterWindowListener = new WindowListener() {
            @Override
            public void windowOpened(WindowEvent e) {
                System.out.println("Performing task..."); //Perform task here. In this case, we are simulating a startup (only once) time-consuming task that would use a worker.
                StartupLoader.execute();
            }
    
            @Override
            public void windowClosing(WindowEvent e) {
                //Do nothing...Or something...You decide!
            }
    
            @Override
            public void windowClosed(WindowEvent e) {
                //Do nothing...Or drink coffee...NVM; always drink coffee!
            }
    
            @Override
            public void windowIconified(WindowEvent e) {
                //Do nothing...Or do EVERYTHING!
            }
    
            @Override
            public void windowDeiconified(WindowEvent e) {
                //Do nothing...Or break the law...
            }
    
            @Override
            public void windowActivated(WindowEvent e) {
                //Do nothing...Procrastinate like me!
            }
    
            @Override
            public void windowDeactivated(WindowEvent e) {
                //Do nothing...And please don't notice I have way too much free time today...
            }
        };
    
        //Here is where the magic happens! We make (a listener within) the frame start listening to the frame's own events!
        this.addWindowListener(taskStarterWindowListener);
    }
    
    //The method that adds the listeners that perform the tasks is added in the constructor,
    //right after initializing the components (auto-generated method in NetBeans).
    public MyFrame() {
        initComponents();
        initSelfListeners(); //
    }
    

    【讨论】:

    • 代替Do nothing cmets,您可以从WindowAdapter 扩展而不是WindowListener
    • 顺便说一句,addWindowListener 仍然在构造函数中调用,只是现在间接调用。尽管MyFrame 是一个有效的最终类,但关于这种情况的警告是毫无意义的。当您将 MyFrame 声明为 final 时,警告应该会消失,如果警告仍然存在,则 linter 是错误的。 (是 FindBugs 还是 PMD?)
    • @RolandIllig 感谢您的反馈!我不知道WindowAdapter。在过去的 2 年左右的时间里,我没有用 Java 编程过任何东西,但是如果我再次开始使用它,这将很方便! --- 与我的 Java 不活动和 linter 相关;我不认为是其中任何一个(?),但我不记得了。无论哪种方式,也欢迎使用final 的提示!但为了防患于未然,您将如何处理非最终案例?
    • 非final case确实有问题。当基本构造函数调用在子类中被覆盖的方法时,可能不涉及该方法,或者您必须处理未初始化的字段。我不记得它是哪一个了,我必须在 Java 语言规范中查找它,在关于创建和初始化对象的章节中的某个地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 2010-09-06
    • 1970-01-01
    • 2015-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多