1

我们的应用程序显示我们数据的 2D 视图(主要是地图),然后允许用户更改为 3D 视图。2D 和 3D 视图是由自定义 C++ 代码生成的,这些代码被 SWIG'ed 到我们的 Swing GUI 中并包装在JComponent. 这些JComponents 然后显示在另一个父 JComponent 中。

我们的问题是,当我们从 2D 视图更改为 3D 视图然后返回 2D 视图时,当我们调整窗口大小时,2D 视图不会调整大小。调整大小事件不会发送到 2D 视图。

我们的应用程序在 Linux (Fedora 11) 下运行。我们正在运行 Java 版本 1.6.0_12。

这是一些示例代码,其中我用两个 2 替换了 2D 视图和 3D 视图JButton,这会产生相同的行为。一旦您转到 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)andparent.add(view3D)并不是真正的解决方案,我们必须调用setVisible(false)and包含我们的 2D 和 3D 视图setVisible(true)JComponents 才能隐藏和显示它们。

任何帮助将不胜感激。

4

3 回答 3

2

为什么不使用 CardLayout 从 2D 组件切换到 3D 组件?在我的理解中,CardLayout 正是为了这种目的而完成的。另一个好处是它将简化您的代码。

于 2010-04-22T12:17:23.503 回答
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

JComponent#revalidate() 的 Javadoc

支持延迟自动布局。

调用 invalidate 然后将此组件的 validateRoot 添加到需要验证的组件列表中。验证将在所有当前挂起的事件都已调度后进行。换句话说,在调用此方法后,将验证在向上遍历此组件的包含层次结构时找到的第一个 validateRoot(如果有)。默认情况下,JRootPane、JScrollPane 和 JTextField 从 isValidateRoot 返回 true。

当属性值发生变化,导致此组件的大小、位置或内部布局受到影响时,将自动在此组件上调用此方法。这种自动更新与 AWT 不同,因为程序通常不再需要调用 validate 来获取要更新的 GUI 的内容。

于 2010-04-22T12:25:37.033 回答
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;
        }
    }
于 2010-04-22T10:55:43.163 回答