在ActionListener中调用时,JFrame不会绘制内容

时间:2015-05-07 20:59:02

标签: java swing actionlistener event-dispatch-thread

我正在尝试制作一组​​2个GUI:一个,当单击一个按钮时,调用另一个GUI,根据在第二个GUI中单击的按钮,将GUI返回到第一个GUI。不幸的是,当从第一个GUI的actionPerformed方法调用时,第二个GUI显示为空白。但是,当使用JOptionPane时,不会发生这种情况。

JOptionPane允许它在actionPerformed方法中工作的内容是什么,为什么我的示例代码在actionPerformed方法中不起作用?

调用第二个GUI的第一个GUI的代码如下:

public class OpeningGUI extends JFrame implements ActionListener {

private static final long serialVersionUID = 1L;

private Container container;
private JButton btn, btn2;

/**
 * Constructor for class OpeningGUI - establish the JFrame
 * Loads the window and moves it to the center of the screen.
 */
public OpeningGUI() {
    // when mama ain't happy, ain't nobody happy
    super("Dominion Launcher");

    //UI components get established here
    container = getContentPane();   // Container is the abstract concept of the area inside a window
    container.setLayout(new BorderLayout());
    container.add(getCenterPanel(), BorderLayout.CENTER);
    setSize(700, 300);
    pack();
    setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2 - this.getWidth()/2, 
            (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/2 - this.getHeight()/2);
    setVisible(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
}

/**
 * Sets the game mode based on which button is clicked.
 * Click stops return method from waiting.
 */
public void actionPerformed(ActionEvent e) {
    if(e.getSource() == btn)    {   
        SelectionDialog sd = new SelectionDialog("Select up to 3 buttons, then click done when selection complete", 3);
        System.out.println(sd.getSelectedIndex());
    }
    if(e.getSource() == btn2)   {   
        JOptionPane.showConfirmDialog(null, "See it works, right");
    }
}

/**
 * Sets up the center panel with buttons to select game mode.
 * @return the center panel.
 */
public JPanel getCenterPanel()  {
    JPanel temp = new JPanel();
    btn = new JButton("SelectionDialog tester");
    temp.add(btn);
    btn.addActionListener(this);
    btn2 = new JButton("JOptionPane tester");
    temp.add(btn2);
    btn2.addActionListener(this);
    return temp;
}

/**
 * Main method of OpeningGUI.  Used to run the program.
 * @param args command-line arguments. Unused.
 */
public static void main(String[] args) {
    new OpeningGUI();
}
} 

第二个GUI的代码如下:

public class SelectionDialog extends JFrame implements ActionListener {

private static final long serialVersionUID = 1L;

private Container container;
private JButton confirmBtn;
private JButton[] buttons;
private ArrayList<Integer> selectionIndecies;
private CountDownLatch wait;
private String message;
private int numNeeded;
private boolean isMaximum;


/**
 * Constructor for the SelectionDialog class.  
 * Selects from an ArrayList of buttons.
 * @param message Message to display.
 * @param num number to select.
 */
public SelectionDialog(String message, int num) {
    super("Please Select Buttons");

    this.message = message;
    numNeeded = num;
    isMaximum = false;

    setupUI();
}

/**
 * Establishes the JFrame and sets values for some fields.
 */
private void setupUI() {
    selectionIndecies = new ArrayList<Integer>();

    wait = new CountDownLatch(1);

    //UI components get established here
    container = getContentPane();   // Container is the abstract concept of the area inside a window
    container.setLayout(new BorderLayout());
    container.add(getTopPanel(), BorderLayout.NORTH);
    container.add(getCenterPanel());
    pack();
    setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2 - this.getWidth()/2, 
            (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/2 - this.getHeight()/2);
    setVisible(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);

}   

/**
 * Changes color of buttons and adds or removes them from the selected arrays.
 */
public void actionPerformed(ActionEvent e) {
    if(e.getSource() == confirmBtn) {   
        if((!isMaximum && selectionIndecies.size() <= numNeeded) 
                || selectionIndecies.size() == numNeeded) {
            wait.countDown();
            dispose();
        }
    }
    for(int i = 0; i < buttons.length; i++) {
        if(e.getSource() == buttons[i]) {
            if(!buttons[i].getBackground().equals(Color.ORANGE)) {
                buttons[i].setBackground(Color.ORANGE);
                buttons[i].setBorderPainted(false);
                selectionIndecies.add(new Integer(i));
                repaint();
            }
            else {
                buttons[i].setBackground(Color.LIGHT_GRAY);
                selectionIndecies.remove(new Integer(i));
                repaint();
            }
        }
    }
}

/**
 * Creates the top panel of the GUI. 
 * Contains the prosperity check box, the number of players selector, 
 * and the card counter and confirm button.
 * @return the top panel.
 */
private JPanel getTopPanel()    {
    JPanel topPanel = new JPanel();
    JLabel temp = new JLabel(message + "       ");
    topPanel.add(temp);
    confirmBtn = new JButton("Done");
    topPanel.add(confirmBtn);
    confirmBtn.addActionListener(this);
    return topPanel;
}

/**
 * Determines which buttons were selected.
 * Waits until Ok has been clicked and a proper number of buttons had been selected.
 * @return an array of indecies of the buttons selected.
 */
public ArrayList<Integer> getSelectedIndex() {
    try {
        wait.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Collections.sort(selectionIndecies); 
    return selectionIndecies;
}

/**
 * Sets up center panel with ArrayList of buttons, 
 * and panels of buttons.
 */
private JScrollPane getCenterPanel()    {
    JPanel centerPanel = new JPanel();
    buttons = new JButton[6];
    for(int i = 0; i < 6; i++) {
        JButton temp = new JButton("Button " + i);
        temp.addActionListener(this);
        temp.setVisible(true);
        centerPanel.add(temp);
        buttons[i] = temp;
    }
    return new JScrollPane(centerPanel);
}

/**
 * Main method of the SelectionDialog class.  For testing only.
 * @param args command line arguments.  Unused.
 */
public static void main(String[] args) {
    SelectionDialog sd = new SelectionDialog("Select up to 3 buttons, then click done when selection complete", 3);
    System.out.println(sd.getSelectedIndex());
}
}

此代码完全可以使用我发布的两个类和相应的import语句运行。第二个GUI也可以独立运行,以显示从第一个GUI调用时应该出现的内容,第一个GUI包含一个正常工作的示例JOptionPane

请帮我弄清楚为什么actionPerformed方法只停止渲染某些GUI,而其他GUI正常工作!

1 个答案:

答案 0 :(得分:1)

你正在阻止EDT! actionPerformed在EDT上执行,因此getSelectedIndex也会wait.await()阻止它。请注意,一旦发生这种情况,第一帧也不会响应(并且最小化和取消最小化帧甚至不会绘制它们)。即使第二帧显示,它也不会响应用户交互,因为第一个actionPerformed没有返回。

我不明白为什么你需要CountDownLatchgetSelectedIndex只能在按下confrimBtn后执行,因此只需在该点返回所选按钮。这不是唯一的解决方案 - 您的设计最终将决定类之间的交互。

SelectionDialog&#39; actionPerformed中写道:

if (e.getSource() == confirmBtn) {
    if ((!isMaximum && selectionIndecies.size() <= numNeeded) || selectionIndecies.size() == numNeeded) {
        Collections.sort(selectionIndecies);
        OpeningGUI.publishSelectedIndex(selectionIndecies);
        dispose();
    }
}

并删除getSelectedIndex方法。

OpeningGUI中,添加以下方法

public static void publishSelectedIndex(ArrayList<Integer> list) {

    System.out.println(list);
}

并从actionPerformed getSelectedIndex移除setLocation

备注:

  • 您可以使用setLocationRelativeTo(null)
  • 代替setSize的屏幕尺寸计算
  • 在第一次通话冗余后立即致电pack时,请致电selectionIndecies = new ArrayList<>();
  • 无需在右侧指定泛型类型:

    JFrame
  • 应该在EDT上开始摆动(参见here)。

  • 您可能会使用对话框而不是其他ActionListener来做得更好。
  • 对于功能不同的按钮使用不同的Session["Fulldata"] = data; ,而不是每次调用都检查来源。