Java MigLayout-ComponentResistized()调用次数过多

Java MigLayout-ComponentResistized()调用次数过多,java,swing,miglayout,Java,Swing,Miglayout,我有以下场景-我有一个面板,它在另一个面板中包含一个组件(本例中为标签)-所有这些都是用MigLayout定义的 调整面板大小时,我想调整JLabel的字体大小,以适合整个区域 我把代码精简到最低限度 public class TestClass { private JPanel panel; private JLabel displayLabel; private TestClass() { panel = new JPanel(new MigLay

我有以下场景-我有一个面板,它在另一个面板中包含一个组件(本例中为标签)-所有这些都是用
MigLayout
定义的

调整面板大小时,我想调整
JLabel
的字体大小,以适合整个区域

我把代码精简到最低限度

public class TestClass {

    private JPanel panel;
    private JLabel displayLabel;

    private TestClass() {
        panel = new JPanel(new MigLayout(new LC().fill().gridGap("0", "0").insetsAll("0").hideMode(3)));

        displayLabel = new JLabel("some text goes here");
        displayLabel.setFont(new Font("Dialog", Font.BOLD, 9));
        panel.add(displayLabel, new CC().grow().push());

        panel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                scale(displayLabel);
            }
        });
    }

    private void scale(JLabel component) {
        Integer lastWidth = (Integer) component.getClientProperty("width");
        Integer lastHeight = (Integer) component.getClientProperty("height");
        if (lastWidth != null && lastHeight != null && lastWidth == component.getWidth() && lastHeight == component.getHeight()) {
            return;
        }

        component.putClientProperty("width", component.getWidth());
        component.putClientProperty("height", component.getHeight());

        int minFontSize = 9;
        Font oldFont = component.getFont();
        float size = oldFont.getSize();
        Font newFont = oldFont.deriveFont(size);
        FontMetrics fm = component.getFontMetrics(newFont);

        int availWidth = component.getWidth() - 2;
        int availHeight = component.getHeight() - 2;

        boolean found = false;
        boolean increased = false;
        boolean decreased = false;
        while (!found) {
            int stringWidth = fm.stringWidth(component.getText());
            int stringHeight = fm.getHeight();
            if (!decreased && stringWidth < availWidth && stringHeight < availHeight) {
                size++;
                increased = true;
            } else if (stringWidth > availWidth || stringHeight > availHeight) {
                size--;
                decreased = true;
            } else {
                found = true;
            }
            if (increased && decreased) {
                found = true;
            }
            newFont = oldFont.deriveFont(size);
            fm = component.getFontMetrics(newFont);
        }

        if (size < minFontSize) {
            size = minFontSize;
            newFont = oldFont.deriveFont(size);
        }

        component.setFont(newFont);
    }


    public JPanel getPanel() {
        return panel;
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("");
        JPanel pnl = new JPanel(new MigLayout(new LC().fill()));
        pnl.add(new TestClass().getPanel(), new CC().grow().push());
        frame.add(pnl, BorderLayout.CENTER);
        frame.setSize(1024, 700);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
公共类TestClass{
私人JPanel小组;
专用JLabel显示标签;
私有TestClass(){
panel=newJPanel(新的MigLayout(新的LC().fill().gridGap(“0”,“0”).insetsAll(“0”).hideMode(3));
displayLabel=newjlabel(“此处有一些文本”);
displayLabel.setFont(新字体(“对话框”,Font.BOLD,9));
panel.add(displayLabel,new CC().grow().push());
panel.addComponentListener(新的ComponentAdapter(){
@凌驾
公共无效组件已恢复(组件事件e){
刻度(显示标签);
}
});
}
专用空隙比例(JLabel组件){
整型lastWidth=(整型)组件。getClientProperty(“宽度”);
整型lastHeight=(整型)组件。getClientProperty(“高度”);
如果(lastWidth!=null&&lastHeight!=null&&lastWidth==component.getWidth()&&lastHeight==component.getHeight()){
返回;
}
component.putClientProperty(“width”,component.getWidth());
component.putClientProperty(“height”,component.getHeight());
int minFontSize=9;
Font oldFont=component.getFont();
float size=oldFont.getSize();
Font newFont=oldFont.deriveFont(大小);
FontMetrics fm=component.getFontMetrics(newFont);
int availWidth=component.getWidth()-2;
int availHeight=component.getHeight()-2;
布尔值=false;
布尔值增加=假;
布尔值=假;
而(!found){
int stringWidth=fm.stringWidth(component.getText());
int stringHeight=fm.getHeight();
如果(!减小和&stringWidth可用宽度| | stringHeight>可用高度){
大小--;
下降=真;
}否则{
发现=真;
}
如果(增加和减少){
发现=真;
}
newFont=oldFont.deriveFont(大小);
fm=component.getFontMetrics(newFont);
}
如果(大小
当我通过拖动右边缘来放大框架时,效果很好,但是,当我尝试通过拖动右边缘的左侧来减小框架的大小时,应用程序运行缓慢,结果不会立即反映在GUI中。请运行它以了解我的意思

你知道我如何改进这段代码以使其顺利工作吗

更新:我添加了一些日志记录,并观察到当增加面板宽度时效果良好,但当减小面板宽度时,我看到ComponentResistized()方法的调用次数要比扩大面板时多得多

问题的原因似乎是MigLayout与grow()的组合。我已经用BorderLayout替换了所有的布局,看起来效果不错


然而,在我的例子中,我不能真正做到这一点,因为我需要我的面板在布局中增长。

由于该方法被多次调用,请尝试只计算一次值。您可以将上次计算的宽度和高度存储在组件中,并在其中一个值更改时计算尺寸:

private void scale(JLabel component) {
    int minFontSize = 9;
    float size = Float.MAX_VALUE;
    size = Math.min(size, component.getWidth());
    size = Math.min(size, component.getHeight());

    Integer lastWidth = (Integer) component.getClientProperty("width");
    Integer lastHeight = (Integer) component.getClientProperty("height");
    if (lastWidth != null && lastHeight != null && lastWidth.intValue() == component.getWidth() && lastHeight.intValue() == component.getHeight()) {
        return;
    }

    component.putClientProperty("width", component.getWidth());
    component.putClientProperty("height", component.getHeight());

    component.putClientProperty("lastSize", new Integer((int) size));

    Font oldFont = component.getFont();
    Font newFont = oldFont.deriveFont(size);
    FontMetrics fm = component.getFontMetrics(newFont);

    int availWidth = component.getWidth() - 2;
    int availHeight = component.getHeight() - 2;

    while ((size > minFontSize) && ((fm.stringWidth(component.getText()) >= availWidth) || (fm.getHeight() >= availHeight))) {
        newFont = oldFont.deriveFont(--size);
        fm = component.getFontMetrics(newFont);
    }

    component.setFont(newFont);
}
此外,您还可以尝试像二进制搜索一样查找
size
变量,而不是逐个递减。对于范围
[9-size=min(宽度、高度)]
首先尝试
(size-9)/2
,如果它适合范围
[(size-9)/2-size]
中的搜索。如果它不适合在
[9-(大小-9)/2]
之间搜索

以下是一个不断增长的GridBagLayout备选方案:

private TestClass() {
    panel = new JPanel(new GridBagLayout());

    displayLabel = new JLabel("some text goes here");
    displayLabel.setFont(new Font("Dialog", Font.BOLD, 9));
    GridBagConstraints gc = new GridBagConstraints();
    gc.fill = GridBagConstraints.BOTH;
    gc.weightx = 1;
    gc.weighty = 1;
    panel.add(displayLabel, gc);

    panel.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            scale(displayLabel);
        }
    });
}

我不知道为什么,但似乎为JLabel设置最小大小可以解决问题

private TestClass() {
    panel = new JPanel(new MigLayout(new LC().fill().gridGap("0", "0").insetsAll("0").hideMode(3)));

    displayLabel = new JLabel("some text goes here");
    displayLabel.setFont(new Font("Dialog", Font.BOLD, 9));
    displayLabel.setMinimumSize(new Dimension(30, 10));
    panel.add(displayLabel, new CC().grow().push());

    panel.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentResized(ComponentEvent e) {
            scale(displayLabel);
        }
    });
}

嗨,hkn,谢谢你花时间回答我的问题。不幸的是,你的解决方案是不够的。实际上,我已经尝试用二进制搜索和替换我原来的while循环,以及一个算法,该算法将使用最后一个字体大小,并尝试增加/减少它,直到它适合,以提高效率,但问题仍然重现。你能试一下只计算一次值的代码吗?我试过了。我还用我目前使用的方法更新了scale方法。请看一看。问题似乎再次出现在MigLayout(fill+grow)上,将其替换为BorderLayout,如前所述,将两个面板的LayoutManager更改为另一个(非MigLayout)将是一个有效的解决方法。然而,在我的情况下,我真的不想这样做,因为所有的进一步的影响。我尝试了这一点,认为“好吧,这不会很难解决”,但。。。是的,嗯。在我看来,MigLayout在内部会对组件大小进行某种“摆动”:当组件变小时,它会尝试“迭代”调整所有包含组件的大小,直到它就位并适合为止。但是我还没有找到一种预防的方法