如何在显示(类扩展)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.
}
是否有可能在MyFrame
(JFrame
的任何扩展)中执行任务,例如触发事件,启动工作,或以其他方式执行一些不相关的代码片段,而不需要在setVisible()
的覆盖或组件的其他初始化方法中执行(以一种否则不会做的方式)?
如果可能的话,怎么做?
附加小问题:假设这是可能的,对于NetBeans的gui构建器自动生成的代码或类似结构的代码,有什么建议吗?
是的,这是可能的。
我想到了两个可能的解决方案来处理这两个问题;如果您希望该任务仅在第一次执行(例如,在启动时)或多次执行(每次显示该窗口或组件时):
- 从
JFrame
中添加WindowListener
,并在windowOpened(WindowEvent e)
中启动动作/worker,这是"在侦听窗口第一次显示后调用"。 - 从
JFrame
中添加一个ComponentListener
,并在componentShown(ComponentEvent)
中启动动作/worker,这是"在被监听的组件变得可见之后调用,因为setVisible方法被调用"。
其他侦听器的类似解决方案也是可能的,但这些可能是最好的方法,对于任何奇怪的情况,从这两种方法中,您应该了解如何实现其他变体。
奖金答:添加侦听器的最佳位置是在其他组件初始化之后。在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(); //
}