Java 不知怎的,当我点击按钮执行方法调用时,我的GUI卡住了
我想通过点击JButton更新电路板配置。但是,有时图像会显示在框架上。有时候不是。每次我点击按钮后都会有明显的延迟。我试着调试,发现在:EventDispatchThread.class中可能有一个无止境的循环Java 不知怎的,当我点击按钮执行方法调用时,我的GUI卡住了,java,multithreading,swing,user-interface,event-dispatch-thread,Java,Multithreading,Swing,User Interface,Event Dispatch Thread,我想通过点击JButton更新电路板配置。但是,有时图像会显示在框架上。有时候不是。每次我点击按钮后都会有明显的延迟。我试着调试,发现在:EventDispatchThread.class中可能有一个无止境的循环 (this is the class from java library) void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) { addEventFilter(filter);
(this is the class from java library)
void pumpEventsForFilter(int id, Conditional cond, EventFilter filter) {
addEventFilter(filter);
doDispatch = true;
while (doDispatch && cond.evaluate()) {
if (isInterrupted() || !pumpOneEventForFilters(id)) {
doDispatch = false;
}
}
removeEventFilter(filter);
}
无止境的循环是上面的while循环
下面是我的listener类:
public class PlaceListener implements ActionListener{
private JTextField _text1;
private Board board;
private JTextField _text2;
private ArrayList<NewGUI> _guiList;
private int _numOfPlayer;
public PlaceListener(JTextField text1, JTextField text2, Board b,ArrayList<NewGUI> guiList, int numOfPlayer,NewGUI gui)
{
_text1 = text1;
_text2 = text2;
board = b;
_guiList = guiList;
_numOfPlayer = numOfPlayer;
}
@Override
public void actionPerformed(ActionEvent e) {
int x = Integer.parseInt(_text1.getText());
int y = Integer.parseInt(_text2.getText());
board.Place(y, x);
for(int j = 0;j<_numOfPlayer;j++)
{
NewGUI gui = _guiList.get(j);
gui.updateBoard();
gui.updateCurrTile();
gui.updateScore();
gui.updateTurn();
}
}
公共类PlaceListener实现ActionListener{
私有JTextField_text1;
私人董事会;
私有JTextField_text2;
私人律师事务所;
私人球员;
PublicPlaceListener(JTextField text1、JTextField text2、Board b、ArrayList guiList、int numOfPlayer、NewGUI)
{
_text1=text1;
_text2=text2;
董事会=b;
_guiList=guiList;
_numOfPlayer=numOfPlayer;
}
@凌驾
已执行的公共无效操作(操作事件e){
intx=Integer.parseInt(_text1.getText());
int y=Integer.parseInt(_text2.getText());
板。位置(y,x);
对于(int j=0;j,您的代码可能就是这里的问题所在。EventDispatchThread再次使用无休止的循环来处理事件,这是显而易见的,可以忽略为实际问题。您的问题来自于使用removeAll(),并在每次单击按钮时实例化数千个标签(13 x 13 x 89-65是多少?4056!)。这将导致大量不必要的重画和重新显示。因此,您看到的暂停是代码的性能,因为它效率不高。不要相信,请尝试以下方法:
public void updateBoard() {
long start = System.currentTimeInMillis();
// existing code goes here
long duration = System.currentTimeMillis() - start;
System.out.printf("UpdateBoard timing: %,d ms%n", duration );
}
如果你的代码超过10-100毫秒,你会觉得有问题。事实上,100毫秒是慢的,人类可以检测到100毫秒的延迟
您可能需要重新评估您的设计,或者重用现有标签,然后简单地调用setImage()来更改它们。毕竟,这就是使用持久化UI组件模型而不是使用原始绘制调用的全部意义。将它们实例化一次并重用
您还使用新的ImageIcon()调用创建了数千个图像。您可能只需要一个图标,并且所有标签都指向同一个图像,这也将大大减少内存使用量。事实上,如果您遵循我的建议,我想您会看到速度和内存的显著提高
如果找不到合适的方法来重用JLabor,那么可以考虑通过子类jbor或JPanel(如果您计划使用容器)并重写PrimtCuttoTeNe()来编写自己的组件。。我知道你没有使用布局管理器,而是选择使用绝对定位来完成所有操作。如果你要做绝对定位,你可能只想自己绘制。绘制是较低级别的界面,但你有完全的控制权。你必须自己处理定位、文字包装。但是,这将非常重要高效,并且可以从数据模型中重新绘制
由于您所做的一切都是以网格模式绘制图像,我认为使用Java2D api绘制图像比实例化那么多JLabel和ImageIcons要好。如果您将JPanel子类化,您可以向面板中添加JComponents,例如score等。但是,使用paintComponent()方法绘制网格。什么是“线路板配置”?是EventDispatchThread.class您的类?您能显示执行此方法调用的JButton的ActionListener吗?好,这意味着cond
始终为true,isInterrupted()
始终为false,pumpOneEventForFilters(id)
总是错误的。试着在循环中中断它,看看它是否有效。是的,当然在事件分派线程中有一个无止境的循环!这就是工作原理——在事件到达时以无止境的循环分派事件。您正在向我们展示Swing代码,那么您的代码呢?好的,我不确定,但请尝试重新绘制()在您的UI上。但我很确定错误不在Swing代码中。@Thomashrig我尝试重新绘制它,但它仍然拒绝在面板上显示标签…所有更新方法都有效,除了这个。我尝试计算时间结果如下:平铺放置在(1,1)中UpdateBoard计时:0毫秒UpdateBoard计时:0毫秒提交成功UpdateBoard计时:16毫秒UpdateBoard计时:0毫秒,因此问题不在于removeAll()。我有一个与电路板相反的类[][]数组,如果为空,则面板上不会放置任何内容。因此它不会生成那么多标签。我仍然不知道问题是什么…将计时代码包装在整个actionPerformed代码周围。如果您看到一个大跳跃,您可以将其隔离。请记住,updateBoard是为每个玩家调用的,因此有多个13*13*(89-65)*numberOfPlayers。这是一种潜力,当你的棋盘开始有更多的项目时,它会变得越来越慢。事实上,这比我们想象的更糟。+1CellRenderPane
,可能会用作渲染器。
public void updateBoard() {
long start = System.currentTimeInMillis();
// existing code goes here
long duration = System.currentTimeMillis() - start;
System.out.printf("UpdateBoard timing: %,d ms%n", duration );
}