【问题标题】:MigLayout causes exception in JOption pane when JTextArea is used. FlowLayout is just fine使用 JTextArea 时,MigLayout 会导致 JOption 窗格中出现异常。 FlowLayout 很好
【发布时间】:2013-03-08 20:19:46
【问题描述】:

下面的示例程序显示了一个带有两个按钮的框架。按下使用 MigLayout 的第二个按钮会导致异常。第一个使用FlowLayout 的按钮工作得很好。似乎是MigLayout 中的错误?

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

public class Main extends JPanel {

static private JFrame frame = new JFrame("Test MigLayout");

public Main() {
    JButton flowLayoutButton = new JButton("FlowLayout");
    JButton miglayoutButton = new JButton("MigLayout");
    add(flowLayoutButton);
    add(miglayoutButton);
    flowLayoutButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent actionEventIn) {
            showDialog(false);
        }
    });
    miglayoutButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent actionEventIn) {
            showDialog(true);
        }
    });
}

public static void main(String[] args) {
    Main main = new Main();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(main);
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            frame.pack();
            frame.setVisible(true);
            frame.setBounds(200, 200, 200, 200);
        }
    });
}
private void showDialog(boolean useMidgLayoutIn) {
    JPanel panel = new JPanel(useMidgLayoutIn ? new MigLayout() : new FlowLayout());
    JTextArea topTextArea = new JTextArea("Here is some junk text to fill up the Text Area.");
    panel.add(topTextArea);
    panel.add(new JButton("Button"));

    JOptionPane optionPane = new JOptionPane(panel, JOptionPane.ERROR_MESSAGE);
    JDialog dialog = optionPane.createDialog(frame, "Application  Error");
    dialog.setResizable(true);
    dialog.pack();
    dialog.setVisible(true);
}
}

【问题讨论】:

    标签: java swing joptionpane miglayout


    【解决方案1】:

    NPE 的原因是一些与 JTextArea/JEditorPane 相关的 mig 内部魔法(详情如下)。这可能会导致嵌套容器出现问题,一些父级有一个保持内部状态的管理器,f.i.在 BoxLayout 中。

    最简单的出路:不要嵌套 - MigLayout 旨在控制一个大面板。在添加到像 optionPane 这样的预制特殊情况容器的情况下,这不是一个选项:这里它有助于将 textArea/editorPane 包装在 JScrollPane 中。

    不完全确定这是否是一个错误,尽管仅在 getter (preferredLayouutSize) 中向上操作容器层次结构看起来很可疑。

    NPE 发生原因的详细信息:magic 的作用是强制父容器布局查询 prefSize:

    public Dimension preferredLayoutSize(Container parent) {
        synchronized (parent.getTreeLock()) {
            if (lastParentSize == null
                    || !parent.getSize().equals(lastParentSize)) {
                for (ComponentWrapper wrapper : ccMap.keySet()) {
                    Component c = (Component) wrapper.getComponent();
                    if (c instanceof JTextArea
                            || c instanceof JEditorPane
                            || (c instanceof JComponent && Boolean.TRUE
                                    .equals(((JComponent) c)
                                            .getClientProperty("migLayout.dynamicAspectRatio")))) {
                        layoutContainer(parent);
                        break;
                    }
                }
            }
    
            lastParentSize = parent.getSize();
            return getSizeImpl(parent, LayoutUtil.PREF);
        }
    }
    

    这又重新查询顶级容器的 prefSize(在 adjustWindowSize 中向下):

    private void adjustWindowSize(ContainerWrapper parent) {
        BoundSize wBounds = lc.getPackWidth();
        BoundSize hBounds = lc.getPackHeight();
    
        if (wBounds == null && hBounds == null)
            return;
    
        Window win = ((Window) SwingUtilities.getAncestorOfClass(Window.class,
                (Component) parent.getComponent()));
        if (win == null)
            return;
    
        Dimension prefSize = win.getPreferredSize();
        ....
    }
    

    当嵌套在 BoxLayout 中时,这会导致重新输入 checkTarget:

    public Dimension preferredLayoutSize(Container target) {
        Dimension size;
        synchronized(this) {
            checkContainer(target);
            // checkRequests initializes all internal book-keeping
            checkRequests();
            // here's the NPE in the second round
            size = new Dimension(xTotal.preferred, yTotal.preferred);
        }
        ...
     }
    
    void checkRequests() {
        // config only if not yet done earlier
        if (xChildren == null || yChildren == null) {
            // The requests have been invalidated... recalculate
            // the request information.
            int n = target.getComponentCount();
            //JW: first time around the arrays of sz are initialized
            xChildren = new SizeRequirements[n];
            yChildren = new SizeRequirements[n];
            for (int i = 0; i < n; i++) {
                Component c = target.getComponent(i);
                ....
                Dimension min = c.getMinimumSize();
                Dimension typ = c.getPreferredSize();
                ....
            }
            .... 
            // JW: never reached if c.getPref re-enters, that is xTotal remains null
            if (absoluteAxis == X_AXIS) {
                xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
                yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
            } else {
                xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
                yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
            }
    
         }
     }   
    

    【讨论】:

      【解决方案2】:

      MigLayout 5.0 对此进行了补偿。如果你想测试它,它就在 Google Code 的后备箱中。

      干杯, 迈克尔

      【讨论】:

      • @MikaelGrev:你们计划什么时候发布 MigLayout 5.0?找不到任何计划或联系信息。
      猜你喜欢
      • 2012-02-12
      • 2011-08-26
      • 2017-11-24
      • 2022-07-14
      • 2016-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多