2010-04-22 50 views
1

我們的應用程序顯示我們數據的2D視圖(主要是地圖),然後允許用戶切換到3D視圖。二維和三維視圖由定製的C++代碼生成,該代碼被SWIG加入到我們的Swing GUI中幷包裝在JComponent中。這些JComponent然後顯示在另一個父JComponent中。如何在調用`setVisible(true)`後調用JComponent?

我們的問題是,當我們從2D切換到3D視圖,然後回到2D視圖時,當我們調整窗口大小時,2D視圖不會調整大小。調整大小事件不會發送到2D視圖。

我們的應用程序在Linux(Fedora 11)下運行。我們正在運行Java版本1.6.0_12。

下面是一些示例代碼,我用兩個2 JButton代替了2D視圖和3D視圖,它們產生相同的行爲。一旦進入3D然後回到2D,調整窗口大小不會導致調整2D視圖的大小。

/* TestFrame.java 
* Compile with: $ javac TestFrame.java 
* Run with: $ java TestFrame 
*/ 

import java.awt.BorderLayout; 
import java.awt.Container; 
import java.awt.event.ComponentEvent; 
import java.awt.event.ComponentListener; 
import javax.swing.JButton; 

public class TestFrame extends javax.swing.JFrame { 

    private boolean mode2D = true; 
    private JButton view2D = null; 
    private JButton view3D = null; 
    private Container parent = null; 

    public TestFrame() { 
     initComponents(); 
     containerPanel.setLayout(new BorderLayout()); 
     view2D = new JButton("2D View"); 
     view2D.addComponentListener(new MyListener("2D VIEW")); 
     containerPanel.add(view2D); 
    } 

    private void changerButtonActionPerformed(java.awt.event.ActionEvent evt) {   
     if (parent == null) { 
      parent = view2D.getParent(); 
     } 
     if (mode2D) { 
      System.out.println("Going from 2D to 3D"); 

      view2D.setVisible(false); 

      if (view3D != null) { 
       view3D.setVisible(true); 
      } else { 
       view3D = new JButton("3D View"); 
       view3D.addComponentListener(new MyListener("3D VIEW")); 
       parent.add(view3D); 
      } 

      ((JButton) evt.getSource()).setText("Change to 2D"); 
      mode2D = false; 
     } else { 
      System.out.println("Going from 3D to 2D"); 
      view3D.setVisible(false); 
      view2D.setVisible(true); 
      ((JButton) evt.getSource()).setText("Change to 3D"); 
      mode2D = true; 
     } 
    } 

    public static void main(String args[]) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       new TestFrame().setVisible(true); 
      } 
     }); 
    } 
    private javax.swing.JPanel containerPanel; 
    private javax.swing.JButton changerButton; 

    private class MyListener implements ComponentListener { 
     private String name; 
     public MyListener(String name) { 
      this.name = name; 
     } 
     @Override 
     public void componentHidden(ComponentEvent event) { 
      System.out.println("@@@ [" + name + "] component Hidden"); 
     } 
     @Override 
     public void componentResized(ComponentEvent event) { 
      System.out.println("@@@ [" + name + "] component Resized"); 
     } 
     @Override 
     public void componentShown(ComponentEvent event) { 
      System.out.println("@@@ [" + name + "] component Shown"); 
     } 
     @Override 
     public void componentMoved(ComponentEvent event) { 
      System.out.println("@@@ [" + name + "] component Moved"); 
     } 
    }; 

    @SuppressWarnings("unchecked") 
    private void initComponents() { 
     containerPanel = new javax.swing.JPanel(); 
     changerButton = new javax.swing.JButton(); 
     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
     containerPanel.setBorder(new javax.swing.border.MatteBorder(null)); 
     javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel); 
     containerPanel.setLayout(containerPanelLayout); 
     containerPanelLayout.setHorizontalGroup(
      containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGap(0, 374, Short.MAX_VALUE) 
     ); 
     containerPanelLayout.setVerticalGroup(
      containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGap(0, 239, Short.MAX_VALUE) 
     ); 
     changerButton.setText("Change to 3D"); 
     changerButton.addActionListener(new java.awt.event.ActionListener() { 
      public void actionPerformed(java.awt.event.ActionEvent evt) { 
       changerButtonActionPerformed(evt); 
      } 
     }); 
     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addContainerGap() 
       .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
        .addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 
        .addComponent(changerButton)) 
       .addContainerGap()) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addContainerGap() 
       .addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 
       .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 
       .addComponent(changerButton) 
       .addContainerGap()) 
     ); 
     pack(); 
    } 
} 

我的Netbeans的道歉生成的GUI代碼

我應該指出,當我們調用parent.remove(view2D)parent.add(view3D)改變看法的我們的3D視圖變化的X Windows ID和我們無法取回我們的3D視圖。因此parent.remove(view2D)parent.add(view3D)不是真正的解決方案,我們必須在JComponent上調用setVisible(false)setVisible(true),其中包含我們的2D和3D視圖以隱藏和顯示它們。

任何幫助將不勝感激。

回答

0

我找到了解決方案。您需要添加/刪除佈局管理器中的組件:

private void changerButtonActionPerformed(java.awt.event.ActionEvent evt) {   
     if (parent == null) { 
      parent = view2D.getParent(); 
     } 

     LayoutManager layoutMgr = parent.getLayout(); 

     if (mode2D) { 
      System.out.println("Going from 2D to 3D"); 

      view2D.setVisible(false); 
      layoutMgr.removeLayoutComponent(view2D); 

      if (view3D != null) { 
       view3D.setVisible(true);     
       if (layoutMgr != null && layoutMgr instanceof LayoutManager2) { 
        ((LayoutManager2) layoutMgr).addLayoutComponent(view3D, null); 
       } 

      } else { 
       view3D = new JButton("3D View"); 
       view3D.addComponentListener(new MyListener("3D VIEW")); 
       parent.add(view3D); 
      } 

      ((JButton) evt.getSource()).setText("Change to 2D"); 
      mode2D = false; 
     } else { 
      System.out.println("Going from 3D to 2D"); 
      view3D.setVisible(false); 
      layoutMgr.removeLayoutComponent(view3D); 

      view2D.setVisible(true);    
      if (layoutMgr != null && layoutMgr instanceof LayoutManager2) { 
       ((LayoutManager2) layoutMgr).addLayoutComponent(view2D, null); 
      } 

      ((JButton) evt.getSource()).setText("Change to 3D"); 
      mode2D = true; 
     } 
    } 
+2

這聽起來過於複雜,它應該是足以只是從/到'父母'中刪除和添加組件。或者使用其他回覆中建議的CardLayoutManager。 – fish 2010-04-22 13:46:12

2

爲什麼不使用CardLayout從2D切換到3D組件?根據我的理解,CardLayout正是爲這種目的而完成的。 另一個好處是它會簡化你的代碼。

+0

即使顯示較小的卡片,卡片佈局也會保持最大元素的大小。如果尺寸非常不同,可能會很煩人。然而,這是基於我記得的,也許我在嘗試時做錯了什麼。 – Gnoupi 2010-04-22 13:43:13

+1

是的,但我想這是一個正常的行爲。每當我從一個視圖切換到另一個視圖時,我不想讓我的窗口重新維護。即使一個組件小於另一個組件(我指的是不同的卡片),我更喜歡將其集中或粘貼在頂部(或其他地方)。 – 2010-04-22 14:35:38

2

remove()add()方法來改變組件後,你應該叫:

parent.revalidate(); //To make the layout manager do its work. 
parent.repaint(); //This could be necessary, to suggest a repaint of the panel 

Javadoc for JComponent#revalidate()

支持延遲自動佈局。

調用無效,然後將此 組件的validateRoot添加到需要驗證的 組件的列表中。 驗證將發生在所有 當前未決事件已被調度 。換句話說,在調用此方法之後,將驗證在驗證該組件的第 號行爲時驗證的第一個 validateRoot(如果有)。 默認情況下,JRootPane,JScrollPane, 和JTextField從 isValidateRoot返回true。

此方法將被自動調用 此組件上時該 分量的 屬性值改變,使得大小, 位置,或內部佈局有所影響。此 自動更新不同於 AWT,因爲程序通常不需要調用驗證以獲取 要更新的GUI的內容。

相關問題