Rab*_*Guy 1 java swing multithreading
也许我只是不知道在哪里看或不完全理解线程如何工作,但我有两个不同的JFrame(J1,J2).J1是主JFrame,它有一个选择J2的下拉菜单.当这个J2变得可见时,我需要J1等待J2的foobar值变为-1以外的值.我试图用几种不同的方式给这只猫上皮而没有成功.
我现在正在尝试...
// located in J1
J2 otherFrame = new J2();
....
private synchronized void getNum() {
try {
while (otherFrame.returnNum() == -1) wait();
}
catch (Exception e) {}
Long myResult = otherFrame.returnNum();
...
}
// located in J2
public synchronized Long returnNum() {
try {
while (someNum == -1) wait();
}
catch (Exception e) {}
notify();
return someNum;
}
Run Code Online (Sandbox Code Playgroud)
我确信这看起来很愚蠢,但是我需要J1等到J2有一个赋值给someNum的值.用户单击"提交"时将分配该值.它没有做好这项工作.我在这里做错了什么(更重要的是),如果这是一个线程的事情,我的线程概念在哪里失败?
解决方案不是将JFrame用于第二个窗口,而是使用模态对话框,例如模态JDialog.这正是为此类型的顶级窗口构建的.
这个问题是为什么人们应该避免编写扩展JFrame的Swing类的另一个原因,因为这样做会将编码器描绘成一个角落并限制他们的选择.更好的是创建扩展或构建用于创建JPanel的类,从那时起JPanel可以放在JFrame或模态JDialog中,如果需要,或者放在另一个JPanel中,或者在CardLayout中交换,或者......
请注意,除了一些差异之外,使用JDialog与JFrame非常相似.你应该在对话框中传入一个对调用窗口的引用(这里是你的第一个JFrame),你应该使用使对话框模态化的构造函数,但API可以帮助你完成所有这些.
当您使模态窗口可见时,调用代码中的代码流将停止,并且在JDialog不再可见之前不会恢复.那时你可以查询JDialog的组件的状态,并在调用代码中使用它.
例如:
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class DialogEg {
private static void createAndShowGui() {
// create JFrame for application
JFrame frame = new JFrame("Dialog Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class MainPanel extends JPanel {
private JTextField valueField = new JTextField(5);
public MainPanel() {
valueField.setFocusable(false); // so user can't interact with it
add(new JLabel("Value:"));
add(valueField);
add(new JButton(new GetValueAction("Get Value")));
}
private class GetValueAction extends AbstractAction {
private SecondPanel secondPanel = new SecondPanel();
public GetValueAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
// get JPanel's top level window
Window win = SwingUtilities.getWindowAncestor(MainPanel.this);
// create jdialog that is modal
JDialog dialog = new JDialog(win, "Get Value", ModalityType.APPLICATION_MODAL);
dialog.add(secondPanel);
// so the submit button will be activated when enter pressed:
dialog.getRootPane().setDefaultButton(secondPanel.getSubmitButton());
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true); // **** code flow stops here
// and resumes here once dialog is no longer visible
int value = secondPanel.getSpinnerValue();
valueField.setText("" + value);
}
}
}
@SuppressWarnings("serial")
class SecondPanel extends JPanel {
private SpinnerModel spinModel = new SpinnerNumberModel(-1, -1, 100, 1);
private JSpinner spinner = new JSpinner(spinModel);
private JButton submitButton = new JButton(new SubmitAction("Submit"));
public SecondPanel() {
add(spinner);
add(submitButton);
}
public int getSpinnerValue() {
return (Integer) spinner.getValue();
}
public JButton getSubmitButton() {
return submitButton;
}
private class SubmitAction extends AbstractAction {
public SubmitAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
int value = getSpinnerValue();
// get JPanel's top level window
Window win = SwingUtilities.getWindowAncestor(SecondPanel.this);
if (value < 0) {
String msg = "Submitted value must cannot be negative. Please try again";
JOptionPane.showMessageDialog(win, msg, "Invalid Entry", JOptionPane.ERROR_MESSAGE);
spinner.requestFocusInWindow(); // bring focus back to spinner
} else {
spinner.requestFocusInWindow();
win.dispose(); // get rid of dialog
}
}
}
}
Run Code Online (Sandbox Code Playgroud)