2011-09-07 181 views
3

我在java框架中有一個按鈕,當它按下時,它從文本框中讀取一個值,並將該字符串用作嘗試連接到串行設備的端口名稱。Java:Swing:按下按鈕後隱藏框架

如果此連接成功,則方法返回true,否則返回false。如果它返回true,我希望框架消失。然後在其他類中指定的一系列其他框架將顯示控制串行設備的選項。

我的問題是:按鈕被連接到一個動作監聽器,當按下這個方法時被調用。如果我嘗試使用frame.setVisible(true);方法java拋出一個抽象按鈕錯誤,因爲我有效地告訴它在按鈕按下方法退出之前消失了包含按鈕的框架。刪除frame.setVisible(true);允許程序正常運行,但我留下了一個不再有用的延續的連接框架。

如何在按下按鈕時使框架消失?

package newimplementation1; 

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 


/** 
* 
* @author Zac 
*/ 

public class ConnectionFrame extends JPanel implements ActionListener { 


private JTextField textField; 
private JFrame frame; 
private JButton connectButton; 
private final static String newline = "\n"; 

public ConnectionFrame(){ 

    super(new GridBagLayout()); 

    textField = new JTextField(14); 
    textField.addActionListener(this); 
    textField.setText("/dev/ttyUSB0"); 

    connectButton = new JButton("Connect"); 

    //Add Components to this panel. 
    GridBagConstraints c = new GridBagConstraints(); 
    c.gridwidth = GridBagConstraints.REMAINDER; 

    c.fill = GridBagConstraints.HORIZONTAL; 
    add(textField, c); 

    c.fill = GridBagConstraints.BOTH; 
    c.weightx = 1.0; 
    c.weighty = 1.0; 
    add(connectButton, c); 



    connectButton.addActionListener(new ActionListener() { 

     public void actionPerformed(ActionEvent e) 
     { 

      boolean success = Main.mySerialTest.initialize(textField.getText()); 

      if (success == false) {System.out.println("Could not connect"); return;} 

      frame.setVisible(false); // THIS DOES NOT WORK!! 

      JTextInputArea myInputArea = new JTextInputArea(); 
      myInputArea.createAndShowGUI(); 

      System.out.println("Connected"); 


     } 
    }); 

} 

    public void actionPerformed(ActionEvent evt) { 

      // Unimplemented required for JPanel 

    } 

    public void createAndShowGUI() { 

    //Create and set up the window. 
    frame = new JFrame("Serial Port Query"); 
    frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 


    //Add contents to the window. 
    frame.add(new ConnectionFrame()); 
    frame.setLocation(300, 0); 


    //Display the window. 
    frame.pack(); 
    frame.setVisible(true); 

      frame.addComponentListener(new ComponentAdapter() { 
     @Override 
     public void componentHidden(ComponentEvent e) { 
      System.out.println("Exiting Gracefully"); 
      Main.mySerialTest.close(); 
      ((JFrame)(e.getComponent())).dispose(); 
      System.exit(0); 
     } 
    }); 


} 

} 
+2

這是不可能的應用程序。應該使用多個'JFrame'。小型用戶界面元素可能會彈出在「JDialog」或「JOptionPane」中,而「CardLayout」或各種Swing組件可用於在容器中包含多個UI(或「屏幕」)。 –

+1

爲了更快提供更好的幫助,請發佈[SSCCE](http://pscode.org/sscce.html)。 –

回答

4

你的問題是這一行:

frame.add(new ConnectionFrame()); 

你正在創建一個新的ConnectionFrame對象,從而顯示了一個你的按鈕嘗試關閉的框架是不一樣的,這是你問題的根源。

如果將其更改爲,

//!! frame.add(new ConnectionFrame()); 
    frame.add(this); 

使兩個JFrames是同一個,事情可能會更加順暢。但是話說回來,你的整個設計聞起來很糟糕,我會以更多的面向對象和更不靜態的方式重新考慮它。此外,使用對話框需要對話框,而不是框架,而不是對話框考慮通過CardLayout交換視圖(JPanels)作爲更好的選擇。我爲此創建了一個「啞巴」GUI,創建一個JPanel(在我的例子中,爲了簡單起見,它擴展了一個JPanel,但如果不是必要的話,我會避免擴展),而且我會讓任何調用此代碼的人決定如何通過某種控制來處理這些信息。

public interface ConnectionPanelControl { 

    void connectButtonAction(); 

} 
:對於如

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class ConnectionPanel extends JPanel { 

    private JTextField textField; 
    private JButton connectButton; 
    private ConnectionPanelControl control; 

    public ConnectionPanel(final ConnectionPanelControl control) { 
     super(new GridBagLayout()); 
     this.control = control; 

     ActionListener listener = new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      if (control != null) { 
       control.connectButtonAction(); 
      } 
     } 
     }; 

     textField = new JTextField(14); 
     textField.addActionListener(listener); 
     textField.setText("/dev/ttyUSB0"); 

     connectButton = new JButton("Connect"); 

     GridBagConstraints c = new GridBagConstraints(); 
     c.gridwidth = GridBagConstraints.REMAINDER; 

     c.fill = GridBagConstraints.HORIZONTAL; 
     add(textField, c); 

     c.fill = GridBagConstraints.BOTH; 
     c.weightx = 1.0; 
     c.weighty = 1.0; 
     add(connectButton, c); 

     connectButton.addActionListener(listener); 
    } 

    public String getFieldText() { 
     return textField.getText(); 
    } 

} 

再次,簡單的GUI之外的東西會在如何處理文本字段包含文本和什麼做是顯示此JPanel的GUI做決策

此外,您可能會在後臺線程中進行任何連接,以免凍結GUI,可能是SwingWorker。也許這樣的事情:

import java.awt.event.ActionEvent; 
import java.util.concurrent.ExecutionException; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class MyMain extends JPanel { 
    public MyMain() { 
     add(new JButton(new ConnectionAction("Connect", this))); 
    } 

    private static void createAndShowGui() { 
     JFrame frame = new JFrame("My Main"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(new MyMain()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

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

@SuppressWarnings("serial") 
class ConnectionAction extends AbstractAction { 
    private MyMain myMain; 
    private ConnectionPanel cPanel = null; 
    private JDialog dialog = null; 

    public ConnectionAction(String title, MyMain myMain) { 
     super(title); 
     this.myMain = myMain; 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (dialog == null) { 
     dialog = new JDialog(SwingUtilities.getWindowAncestor(myMain)); 
     dialog.setTitle("Connect"); 
     dialog.setModal(true); 
     cPanel = new ConnectionPanel(new ConnectionPanelControl() { 

      @Override 
      public void connectButtonAction() { 
       final String connectStr = cPanel.getFieldText(); 
       new MySwingWorker(connectStr).execute(); 
      } 
     }); 
     dialog.getContentPane().add(cPanel); 
     dialog.pack(); 
     dialog.setLocationRelativeTo(null); 
     } 
     dialog.setVisible(true); 
    } 

    private class MySwingWorker extends SwingWorker<Boolean, Void> { 
     private String connectStr = ""; 

     public MySwingWorker(String connectStr) { 
     this.connectStr = connectStr; 
     } 

     @Override 
     protected Boolean doInBackground() throws Exception { 
     // TODO: make connection and then return a result 
     // right now making true if any text in the field 
     if (!connectStr.isEmpty()) { 
      return true; 
     } 
     return false; 
     } 

     @Override 
     protected void done() { 
     try { 
      boolean result = get(); 
      if (result) { 
       System.out.println("connection successful"); 
       dialog.dispose(); 
      } else { 
       System.out.println("connection not successful"); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } catch (ExecutionException e) { 
      e.printStackTrace(); 
     } 
     } 
    } 
} 
+1

再次來不及:-) – kleopatra

+1

謝謝所有人誰非常迅速地回覆。我發佈了這個問題,然後走了15分鐘,認爲如果我運氣好的話可能會有1個回覆......而且有4個! – Zac

+0

@Zac:請參閱上面的編輯我的答案。用於'windowForComponent'的 –

5

運行您的片段(在刪除/調整自定義類的周圍後),會拋出一個NPE。原因是你所訪問的框架是空的。那是因爲它從未設置。最好不要依賴於任何領域,讓按鈕找到它的頂層祖先和隱藏,像

 public void actionPerformed(final ActionEvent e) { 

      boolean success = true; 
      if (success == false) { 
       System.out.println("Could not connect"); 
       return; 
      } 

      Window frame = SwingUtilities.windowForComponent((Component) e 
        .getSource()); 
      frame.setVisible(false); //no problem :-) 

     } 
+0

+1。應該被接受爲答案 –

1

你的代碼將更具可讀性,如果你命名的JFrame實例xxxFrame和JPanel的實例xxxPanel。命名JPanel實例xxxFrame使事情非常混亂。

如果粘貼了異常的堆棧跟蹤,它也會有所幫助。

我懷疑問題來自frame爲null的事實。這是由於這樣的事實,所述幀字段在createAndShowGUI方法僅初始化,但此方法並不顯示當前連接面板,但是一個新的,因此具有空幀字段:

ConnectionFrame firstPanel = new ConnectionFrame(); 
// The firstPanel's frame field is null 
firstPanel.createAndShowGUI(); 
// the firstPanel's frame field is now not null, but 
// the above call opens a JFrame containing another, new ConnectionFrame, 
// which has a null frame field 

createAndShowGUI的代碼應該包含

frame.add(this); 

而不是

frame.add(new ConnectionFrame()); 
1

的Swing GUI的是更好地創造一次JFrame和另一Top-Level ContainersJDialogJWindow(默認情況下未飾),

簡單的在這裏例如

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class SuperConstructor extends JFrame { 

    private static final long serialVersionUID = 1L; 

    public SuperConstructor() { 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setPreferredSize(new Dimension(300, 300)); 
     setTitle("Super constructor"); 
     Container cp = getContentPane(); 
     JButton b = new JButton("Show dialog"); 
     b.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent evt) { 
       FirstDialog firstDialog = new FirstDialog(SuperConstructor.this); 
      } 
     }); 
     cp.add(b, BorderLayout.SOUTH); 
     JButton bClose = new JButton("Close"); 
     bClose.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent evt) { 
       System.exit(0); 
      } 
     }); 
     add(bClose, BorderLayout.NORTH); 
     pack(); 
     setVisible(true); 
    } 

    public static void main(String args[]) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       SuperConstructor superConstructor = new SuperConstructor(); 
      } 
     }); 
    } 

    private class FirstDialog extends JDialog { 

     private static final long serialVersionUID = 1L; 

     FirstDialog(final Frame parent) { 
      super(parent, "FirstDialog"); 
      setPreferredSize(new Dimension(200, 200)); 
      setLocationRelativeTo(parent); 
      setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
      setModalityType(Dialog.ModalityType.DOCUMENT_MODAL); 
      JButton bNext = new JButton("Show next dialog"); 
      bNext.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent evt) { 
        SecondDialog secondDialog = new SecondDialog(parent, false); 
       } 
      }); 
      add(bNext, BorderLayout.NORTH); 
      JButton bClose = new JButton("Close"); 
      bClose.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent evt) { 
        setVisible(false); 
       } 
      }); 
      add(bClose, BorderLayout.SOUTH); 
      pack(); 
      setVisible(true); 
     } 
    } 
    private int i; 

    private class SecondDialog extends JDialog { 

     private static final long serialVersionUID = 1L; 

     SecondDialog(final Frame parent, boolean modal) { 
      //super(parent); // Makes this dialog unfocusable as long as FirstDialog is visible 
      setPreferredSize(new Dimension(200, 200)); 
      setLocation(300, 50); 
      setModal(modal); 
      setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
      setTitle("SecondDialog " + (i++)); 
      JButton bClose = new JButton("Close"); 
      bClose.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent evt) { 
        setVisible(false); 
       } 
      }); 
      add(bClose, BorderLayout.SOUTH); 
      pack(); 
      setVisible(true); 
     } 
    } 
} 

更好纔可以重新使用頂層容器,如在運行時創造了大量頂層容器的(可能的內存不足)