我有一个带有 GridBagLayout 的 JFrame,其中包含一个 JLabel 和一个 JScrollPane。 JScrollPane 包含一个ScrollablePanel,而ScrollablePanel 又包含一定数量的DebugComponent。 DebugComponents 维护从 JScrollPane 的高度导出的纵横比。 JFrame 与 GridBagLayout 的布局一开始就很合适。
但是现在,我使用 MouseMotionListener 通过线程间接更改 JLabel 的文本。如果鼠标悬停在 DebugComponent 上,则会显示一条文本。否则该区域是空的。然而,当我移动到 DebugComponent 时,布局发生了变化。如果我在 DebugComponent 和 ScrollablePanel 之间来回移动鼠标,JScrollPane 使用的空间会变得越来越大。仅当只剩下 JLabel 文本的空间时,它才会停止。
代码是我的问题的抽象。除了 ScrollablePanel 的类(在此处获取)之外,代码已完成。
package de.franken.debug;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
public class DebugGUI {
private static JLabel label;
public static ScrollablePanel panel;
/** Main method + GUI configuration */
public static void main(String[] args) {
JFrame frame = new JFrame(); // JFrame
frame.setLayout(new GridBagLayout());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
GridBagConstraints c = new GridBagConstraints();
panel = new ScrollablePanel(new GridLayout(1, 0)); // Panel containing DebugItems
panel.setScrollableHeight(ScrollablePanel.ScrollableSizeHint.FIT);
for (int i = 0; i < 1; i++) {
panel.add(new DebugComponent(0.2));
}
c = new GridBagConstraints();
c.gridy = 1;
c.weighty = 0.6;
c.gridwidth = 1;
c.weightx = 1;
c.fill = GridBagConstraints.BOTH;
JScrollPane pane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); // ScrollPane containing Panel
new SlideThread(pane);
frame.add(pane, c);
label = new JLabel("PLACEHOLDER"); // Label displaying String
label.setHorizontalAlignment(SwingConstants.CENTER);
c = new GridBagConstraints();
c.gridy = 2;
c.weighty = 0.4;
c.fill = GridBagConstraints.BOTH;
c.gridwidth = 1;
c.weightx = 1;
frame.add(label, c);
frame.setSize(400, 400);
frame.setVisible(true);
}
/**
* Change text of JLabel beneath ScrollablePane. -> Called by SlideThread
*
* @param strg : the String to be displayed
*/
public static void setPreview(String strg) {
label.setText(strg);
}
static class DebugComponent extends JComponent {
private static final long serialVersionUID = -4770356342749347317L;
private double widthRatio;
/**
* JComponent as part of ScrollablePanel with constant dimension ratio
*
* @param widthRatio : the ratio to be multiplied with height to get width
*/
DebugComponent(double widthRatio) {
this.widthRatio = widthRatio;
}
@Override
public Dimension getPreferredSize() {
Dimension parent = super.getSize();
return new Dimension((int) (parent.height * widthRatio), parent.height);
}
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(0, 0, (int) getPreferredSize().getWidth() - 1, (int) getPreferredSize().getHeight() - 1);
}
}
static class SlideThread extends Thread {
private String strg = " ";
SlideThread(JScrollPane pane) {
pane.addMouseMotionListener(adapter);
this.start();
}
@Override
public void run() {
while (true) {
try {
sleep(45);
} catch (InterruptedException e) {
e.printStackTrace();
}
DebugGUI.setPreview(strg);
}
}
// Show String during hovering
MouseAdapter adapter = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
Component c = DebugGUI.panel.getComponentAt(e.getPoint());
if (c instanceof DebugComponent) {
strg = "Titel";
} else {
strg = " ";
}
}
};
}
}
GridBagLayout 仅考虑可见组件,因此当您的 JLabel 为空时,布局会将其视为无维度组件,并表现得好像它实际上不存在一样。
您可以尝试采取以下几项措施来避免此问题:
a) 将 JLabel 的文本设为空白,而不是空,例如
myLabel.setText(" ")
而不是 myLabel.setText("")
;
b) 当不应该有任何文本时,更改文本的颜色以匹配标签的背景颜色。
您可能会幸运地将标签放入 GridBagLayout 的一个单元格内的 BorderLayout 中,希望 BorderLayout 的“贪婪”性质扩展组件以占用尽可能多的可用空间,但我还没有尝试过我自己,所以我不能肯定。