![](/img/trans.png)
[英]How to remove JButton from JFrame from inside JButton's ActionListener?
[英]How to call a heavy algorithm from JButton ActionListener
我正在編寫一個既充當服務器又充當客戶端的Java程序。 忽略不相關的位,它具有三個類別:Main,Server和Client。 Main只是設置一個菜單並包含main方法。 服務器和客戶端分別持有服務器和客戶端的算法。
我想要做的是根據所按下的按鈕從服務器和客戶端類及其GUI調用算法。 當前調用服務器的代碼如下:
serverButton = new JButton();
serverButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
server.showGUI();
server.run();
}
});
問題是server.run()
連續運行了很長一段時間,而且繁重。 這使GUI出錯,據我了解,這是因為我正在從EDT調用該方法。
如何從主線程調用此方法? 我是否需要創建一個SwingWorker
並將其保留到server.run()結束?
如何從主線程調用此方法?
這是通常在Swing中完成的方式。
public class WhatEverServer {
private UserInterface userInterface;
[...]
private static void createAndShowGUI() {
if( GraphicsEnvironment.isHeadless() )
logger.log( Level.FATAL, "This system seems to be 'headless'. Aborting now." );
else {
userInterface = UserInterface.getInstance();
userInterface.createAndShowUI();
}
}
public static void main( String[] args ) {
// schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater( new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
public class UserInterface {
...
public void createAndShowUI() {
// make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
// create and set up the window.
JFrame frame = new JFrame( "Whatever Server" );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set UI components, i.e
// set main menu bar
frame.setJMenuBar( this.mainMenuBar );
// set layout
frame.getContentPane().setLayout( new BorderLayout() );
// add UI components
// display the window.
frame.pack();
frame.setVisible(true);
}
}
這使GUI出錯,據我了解,這是因為我正在從EDT調用該方法。
是的,由於操作是由事件觸發的,因此EDT(或在EDT上)會調用actionPerformed()。 我不知道您在server.run()中做什么,但是我想這不應該在EDT上結束。
我是否需要創建一個SwingWorker並將其保留到server.run()結束?
在這種情況下,我將使用SwingWorker或SwingUtilities。 您可以以這種方式編寫ActionHandler,使用兩個線程,一個用於執行某些“繁重的工作”,一個用於設置UI:
public void actionPerformed(ActionEvent e) {
new Thread(new Runnable {
public void run() {
...
// do some 'heavy lifting' here ...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
server.setupUI();
}
)
...
// or do some 'heavy lifting' here
});
}
}
確保服務器對象引用是最終的,然后在actionPerformed方法的新線程中調用該方法。
Runnable task = () -> {server.run();};
Thread thread = new Thread(task);
thread.start();
這取決於您的要求,如果您希望用戶在服務器返回之前不希望做任何事情,最好在Busyindicator
中執行Busyindicator
:
public void actionPerformed( ActionEvent e )
{
BusyIndicator.showWhile(Display.getCurrent(), new Runnable()
{
@Override
public void run()
{
server.run();
}
});
}
這將在服務器運行進行中向用戶顯示一個沙漏,並且阻止用戶使用UI。
要么
如果希望UI響應,則需要在單獨的線程中調用server.run()
。
MyThread t = new MyThread()
{
public void run()
{
server.run();
}
}
t.start();
最好在線程中添加偵聽器以通知服務器響應完成,以便UI可以執行其操作。
t.addListener( new MyThreadListener()
{
public void serverDone()
{
Display.getDefault().asyncExec( new Runnable()
{
public void run()
{
}
});
}
});
請注意,出於主意考慮,這不是用於線程偵聽器的完整代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.