簡體   English   中英

調用`setVisible(true)`后如何讓JComponent調整大小?

[英]How do I get a JComponent to resize after calling `setVisible(true)`?

我們的應用程序顯示我們數據的2D視圖(主要是地圖),然后允許用戶更改為3D視圖。 2D和3D視圖由自定義C ++代碼生成,這些代碼SWIG進入我們的Swing GUI並包裝在JComponent 然后,這些JComponent將顯示在另一個父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)實際上不是一個解決方案,我們必須在包含我們的2D和3D視圖的JComponent上調用setVisible(false)setVisible(true)才能隱藏和顯示他們。

任何幫助將不勝感激。

為什么不使用CardLayout從2D切換到3D組件? 在我的理解中,CardLayout正是為了這種目的而完成的。 另一個好處是它將簡化您的代碼。

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

JComponent的Javadoc#revalidate()

支持延遲自動布局。

調用無效,然后將此組件的validateRoot添加到需要驗證的組件列表中。 在調度所有當前掛起的事件之后將進行驗證。 換句話說,在調用此方法之后,將驗證在向上遍歷此組件的包含層次結構時找到的第一個validateRoot(如果有)。 默認情況下,JRootPane,JScrollPane和JTextField從isValidateRoot返回true。

當屬性值發生更改以使此組件的大小,位置或內部布局受到影響時,將自動在此組件上調用此方法。 這種自動更新與AWT不同,因為程序通常不再需要調用validate來獲取GUI的內容以進行更新。

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

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;
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM