从另一个类的事件运行新的GUI窗口

时间:2015-01-18 15:11:12

标签: java swing

我有2节课。两个实现都可以运行以创建GUI。第一个是主要的,第二个是次要的。

我希望在主类的actionlistener中启动辅助类。

这是代码(两个类是分开的文件):

public class Main implements Runnable
{
    private JTextField txt1, txt2;
    private JLabel lbl1, lbl2;

    public void run() 
    {
        JFrame frame = new JFrame("Secondary");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Container pane = frame.getContentPane();

        JPanel background = new JPanel();
        background.setLayout(new BoxLayout(background, BoxLayout.LINE_AXIS));

        ......... 

        // Horizontally adding the textbox and button in a Box
        Box box = new Box(BoxLayout.Y_AXIS);
        ......

        background.add(box);
        pane.add(background);

        frame.pack();
        frame.setVisible(true);
    }

    private class SListener implements ActionListener 
    {
        public void actionPerformed(ActionEvent a)
        {
            Secondary s = new Secondary();
        }
    } 

    public static void main (String[] args) 
    {
        Main gui = new Main();
        SwingUtilities.invokeLater(gui);
    }

}


public class Secondary implements Runnable
{
    private JTextField txt1, txt2;
    private JLabel lbl1, lbl2;

    public Secondary()
    {
      Secondary gui = new Secondary();
      SwingUtilities.invokeLater(gui);
    }

    public void run() 
    {
        JFrame frame = new JFrame("Secondary");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Container pane = frame.getContentPane();

        JPanel background = new JPanel();
        background.setLayout(new BoxLayout(background, BoxLayout.LINE_AXIS));

        ......... 

        // Horizontally adding the textbox and button in a Box
        Box box = new Box(BoxLayout.Y_AXIS);
        ......

        background.add(box);
        pane.add(background);

        frame.pack();
        frame.setVisible(true);
    }   
}

我想将代码保存在两个文件中,我不想将这两个类混合在一个文件中。 从代码中可以看出,在Secondary类中,在它的构造函数中,我创建了一个Secondary类的实例,并运行了gui,这样当在Main类中创建此类的实例时,运行gui。

不幸的是,这种技术无效。

有什么想法吗? 感谢

2 个答案:

答案 0 :(得分:2)

以下行是完全错误的:

public Secondary(){
  Secondary gui = new Secondary();
  SwingUtilities.invokeLater(gui);
}

每次在代码中的某个地方拨打new Secondary()时,都会触发上述代码,然后又会再次调用new Secondary(),然后再次调用......并且您的程序被阻止。

您可能希望通过

替换它
public Secondary(){
      SwingUtilities.invokeLater(this);
}

这将避免循环,但这是构造函数的奇怪行为。

切换到空构造函数(或一起删除它)更有意义

public Secondary(){
}

并将您的监听器重写为

public void actionPerformed(ActionEvent a){
  Secondary s = new Secondary();
  SwingUtilities.invokeLater( s );
}

答案 1 :(得分:2)

我建议你完全重新设计你的程序。我发现将GUI设置为创建JPanels是最有帮助的,而不是像JFrame这样的顶级窗口,然后可以将其置于JFrames或JDialogs,或JTabbedPanes中,或者在需要时通过CardLayouts交换。我发现这大大增加了我的GUI编码的灵活性,正是我建议你做的。所以......

  • 您的第一个类创建一个JPanel,然后将其放入JFrame。
  • 在第一个类的ActionListener中,创建第二个类的实例,将其放入JDialog(不是JFrame),然后显示它。

例如,

import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.*;

public class TwoWindowEg {
   public TwoWindowEg() {
      // TODO Auto-generated constructor stub
   }

   private static void createAndShowGui() {
      GuiPanel1 mainPanel = new GuiPanel1();

      JFrame frame = new JFrame("Main GUI");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class GuiPanel1 extends JPanel {
   private static final int PREF_W = 800;
   private static final int PREF_H = 650;
   private GuiPanel2 guiPanel2 = new GuiPanel2(); // our second class!
   private JDialog dialog = null;  // our JDialog

   public GuiPanel1() {
      setBorder(BorderFactory.createTitledBorder("GUI Panel 1"));
      add(new JButton(new LaunchNewWindowAction("Launch New Window")));
      add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class LaunchNewWindowAction extends AbstractAction {
      public LaunchNewWindowAction(String name) {
         super(name);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         if (dialog == null) {
            // get the Window that holds this JPanel
            Window win = SwingUtilities.getWindowAncestor(GuiPanel1.this);
            dialog = new JDialog(win, "Second Window", ModalityType.APPLICATION_MODAL);
            dialog.add(guiPanel2);
            dialog.pack();
         }
         dialog.setVisible(true);
      }
   }
}

class GuiPanel2 extends JPanel {
   public GuiPanel2() {
      setBorder(BorderFactory.createTitledBorder("GUI Panel 1"));
      add(new JLabel("The second JPanel/Class"));
      add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
   }
}

class DisposeAction extends AbstractAction {
   public DisposeAction(String name, int mnemonic) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      Component comp = (Component) e.getSource();
      Window win = SwingUtilities.getWindowAncestor(comp);
      win.dispose();
   }
}

或者,您可以使用CardLayout交换JPanel“视图”,但不管怎样,您都希望避免显示两个JFrame。请查看The Use of Multiple JFrames, Good/Bad Practice?