MigLayout - componentResized() 调用次数过多
MigLayout - componentResized() called too many times
我有以下情况 - 我有一个面板,它在另一个面板中包含一个组件(在本例中为标签) - 全部用 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);
}
}
当我通过拖动右边缘来放大它来调整框架的大小时 - 它工作得很好,但是,当我试图通过拖动右边缘的左侧来减小它的大小时,应用程序运行缓慢,结果是不会立即反映在 GUI 中。请运行看看我的意思。
你知道我如何改进这段代码才能顺利工作吗?
更新:我添加了一些日志记录,我观察到当增加宽度时它工作正常,但是当减小面板宽度时我看到 componentResized( ) 方法比放大时调用了很多次。
问题的原因似乎是 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(width, height)]
,首先尝试 (size - 9)/2
,如果它适合在范围 [(size - 9)/2 - size]
中搜索。如果不适合在 [9 - (size - 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);
}
});
}
我有以下情况 - 我有一个面板,它在另一个面板中包含一个组件(在本例中为标签) - 全部用 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);
}
}
当我通过拖动右边缘来放大它来调整框架的大小时 - 它工作得很好,但是,当我试图通过拖动右边缘的左侧来减小它的大小时,应用程序运行缓慢,结果是不会立即反映在 GUI 中。请运行看看我的意思。
你知道我如何改进这段代码才能顺利工作吗?
更新:我添加了一些日志记录,我观察到当增加宽度时它工作正常,但是当减小面板宽度时我看到 componentResized( ) 方法比放大时调用了很多次。
问题的原因似乎是 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(width, height)]
,首先尝试 (size - 9)/2
,如果它适合在范围 [(size - 9)/2 - size]
中搜索。如果不适合在 [9 - (size - 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);
}
});
}