【发布时间】:2020-08-27 15:06:14
【问题描述】:
我编写了一些 Java Swing 代码来收集一些输入,进行一些计算,然后显示结果。
预期结果:
- 对于每个用户输入:
- 用户转到文件 -> 新建 -> 输入一些数据。
- 计算计算时鼠标光标变成微调器。
- 显示结果。
- 鼠标光标恢复默认值。
实际结果:
- 对于第一个用户输入:
- 用户转到文件 -> 新建 -> 输入一些数据。
- 计算计算时鼠标光标保持不变。
- 显示结果。
- 对于每个后续使用,结果都是上述预期结果。
我对 Swing 还很陌生,我一直在尝试深入了解这一点,但运气不佳。我已将错误范围缩小到代码的特定行。如果我注释掉该行
JOptionPane.showConfirmDialog(null, null, "Enter new maze parameters", JOptionPane.OK_CANCEL_OPTION); 在代码中,然后微调器按预期第一次出现。如果我把线路留在里面,那么我就会遇到所描述的问题。
请注意,为了消除实际程序中的大量 U/I 流,我已大幅缩减此示例,但此示例确实如所述那样中断。我无法进一步简化示例代码。
简化代码
package ca.pringle.maze.ui;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import ca.pringle.maze.logic.Edge;
import ca.pringle.maze.logic.MazeConfig;
import ca.pringle.maze.logic.MazeMaker;
import ca.pringle.maze.logic.PathFinder;
import ca.pringle.maze.util.Pair;
public final class MazeDrawer extends JFrame {
private final MazePanel mazePanel;
public MazeDrawer() {
mazePanel = new MazePanel();
}
public void init() {
final JScrollPane scrollPane = new JScrollPane(mazePanel);
final JMenuBar menuBar = createMenuBar((actionEvent) -> generateNewMaze());
setJMenuBar(menuBar);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(scrollPane, BorderLayout.CENTER);
setSize(100, 100);
setVisible(true);
repaint();
}
void generateNewMaze() {
// if I comment out this line below, then the spinner appears on the first run as expected.
// if I leave this line in, then the spinner does not appear on the first run, only on subsequent runs
JOptionPane.showConfirmDialog(null, null, "Enter new maze parameters", JOptionPane.OK_CANCEL_OPTION);
final MazeConfig mazeConfig = new MazeConfig(1000, 1000, 1);
final MazeMaker mazeMaker = new MazeMaker(mazeConfig);
final PanelDimensions panelDimensions = new PanelDimensions(mazeConfig.getRows(), mazeConfig.getColumns(), 15, 15);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// the two lines below can take a long time depending on the inputs. I tried removing
// them and replacing with a sleep to simulate and simplify the problem, but no luck,
// so I left them in, even if I did not include the code.
final Set<Edge> edges = mazeMaker.generateUndirectedMazeEdges();
final Pair<Integer, Integer> startAndEndNodes = new PathFinder().findLongestPath(edges, mazeConfig);
mazePanel.update(edges, startAndEndNodes, panelDimensions);
mazePanel.setPreferredSize(new Dimension(panelDimensions.panelWidth, panelDimensions.panelHeight));
mazePanel.repaint();
setSize(Math.min(1200, panelDimensions.panelWidth + 11), Math.min(700, panelDimensions.panelHeight + 53));
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
private JMenuBar createMenuBar(final ActionListener menuListener) {
final JMenuBar bar = new JMenuBar();
final JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
final JMenuItem newMenuItem = new JMenuItem("New", KeyEvent.VK_N);
newMenuItem.addActionListener(menuListener);
fileMenu.add(newMenuItem);
bar.add(fileMenu);
return bar;
}
}
感谢任何帮助。请假设我是一个完整的 Swing 菜鸟,所以一个更具体的答案/解释比假设我对 Swing 有所了解的高级答案更有可能有所帮助。当然,我会阅读任何建议的文档。
如果有任何问题或需要澄清,请告诉我,我很乐意根据需要多次更新帖子。
【问题讨论】:
-
第一次执行代码时,GUI 甚至还不可见,所以我猜没有组件关注 setCursor() 方法什么都不做。我猜你应该先创建一个使框架可见,然后再开始执行其他代码以获取用户输入。
-
@camickr 听起来很合理。我确实有 setVisible(true);和重绘();在我的init方法中,它被称为第一件事。我想另一个问题是您的理论能否解释为什么删除该提示会导致代码按预期工作(除非我显然想要提示)。
-
长时间运行的任务在你改变光标后执行,但仍在事件派发线程内;您需要在光标更改生效之前从更改光标的方法返回。您需要将迷宫计算移动到另一个线程,然后,当它完成后,您使用 SwingUtilities.invokeLater 将光标改回。