2016-08-06 13 views
0

我正在编写一个充当服务器和客户端的Java程序。排除不相关的位,它有三个类:Main,Server和Client。 Main只设置一个菜单并包含主要方法。服务器和客户端分别保存服务器和客户端的算法。如何从JButton调用繁重的算法ActionListener

我想要做的是从服务器和客户端类和它们的GUI调用算法,具体取决于按下按钮。该代码调用服务器目前看起来是这样的:

serverButton = new JButton(); 
serverButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent e) { 
     server.showGUI(); 
     server.run(); 
    } 
}); 

的问题是,server.run()连续运行了相当长的一段时间,是很多繁重的工作。这错误地出现了GUI,这从我的理解是因为我正在从EDT调用该方法。

如何从主线程调用此方法?我是否需要创建一个SwingWorker并将其留在server.run()的末尾?

+1

['SwingWorker'](https://docs.oracle .com/javase/tutorial/uiswing/concurrency/worker.html)是一种方法;另一种方法显示[这里](http://stackoverflow.com/a/3245805/230513)。 – trashgod

回答

3

如何从主线程调用此方法?

这是它通常在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,从我的理解是,因为我 呼吁从美国东部时间的方法。

是的,因为动作是由事件触发的,所以actionPerformed()被EDT调用。我不知道你在做什么server.run(),但我想这不应该在美国东部时间。

我需要创建一个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 
    }); 
    } 
} 
0

确保服务器对象引用是final,然后在actionPerformed方法的新线程中调用该方法。

Runnable task =() -> {server.run();}; 
Thread thread = new Thread(task); 
thread.start(); 
0

这取决于你的需求,如果你想用户什么都不想做,直到服务器返回,最好是做一个Busyindicator,如:

public void actionPerformed(ActionEvent e) 
{ 

    BusyIndicator.showWhile(Display.getCurrent(), new Runnable() 
    { 
     @Override 
     public void run() 
     { 
      server.run(); 
     } 
    }); 
} 

这将显示用户当服务器运行正在进行并且用户被阻止使用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() 
      { 
      } 
     }); 
    } 
}); 

请注意,这不是线程监听器的完整代码,只是为了方便起见。