我有一个扩展JLabel的自定义类。对于该类的特定实例,我想在左侧的文本中添加一些间距。我需要间距,因为我正在设置此JLabel的背景,我不希望文本在彩色背景边缘旁边碰到。我钓了很多并实现了这个(在paint函数内):
if (condition) {
bgColor = Color.red;
setBackground(bgColor);
setOpaque(true);
// This line merely adds some padding on the left
setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
}
else {
setOpaque(false);
}
这看起来有用,因为它增加了我想要的间距,但它有一个不幸的副作用,因为它似乎打破了重新绘制整个应用程序的其余部分......似乎只有那个特定的组件重新绘制而不是申请的其余部分。我最终将它追溯到setBorder调用...具体设置任何类型的边界似乎都会导致相同的破坏行为。我们有两个不同版本的应用程序,一个在Java 1.5中运行,另一个在Java 1.6中运行,Java 1.6版本似乎可以正常工作,而Java 1.5版本则没有。无法将旧版本升级到Java 1.6 ...我需要一些适用于Java 1.5的东西。另外,我试过这个(只是为了看看它是什么样的):
setHorizontalTextPosition(JLabel.CENTER);
这也似乎以完全相同的方式打破重画。我浏览了我们的应用程序的源代码,找到了我们设置边框的其他地方(包括空边框),但在JLabel上找不到任何地方(只有面板,按钮等)。以前有人看到过这样的事吗?知道如何解决它吗?或者也许另一种方法来获得我需要的间距可以解决bug?感谢。
答案 0 :(得分:3)
问题是你在paint方法中调用了那段代码。你不应该这样做,因为它会在摆动绘画管道中用不需要的循环冻结EDT。
您应该将该代码放在构造函数上,并在应用程序生命周期的其他位置更改组件设计状态。
如果您想了解更多关于Swing绘画的信息,请阅读push-pixels.org上的“Swing绘画管道”帖子。
请注意,您可以使用BorderFactory.createCompoundBorder组合任意两个边框。然后,您可以使用emptyBorder和任何其他设置间距来绘制外边框。
编辑:添加了示例。
package com.stackoverflow.swing.paintpipeline;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.Border;
public class JLabelSetBorderPaintProblem extends JLabel {
public JLabelSetBorderPaintProblem(String text) {
super(text);
}
/*
* @see javax.swing.JComponent paint(java.awt.Graphics)
*/
@Override
public void paint(Graphics g) {
super.paint(g);
// You can not call setBorder here.
// Please check javadoc.
}
/*
* @see javax.swing.JComponent paintBorder(java.awt.Graphics)
*/
@Override
protected void paintBorder(Graphics g) {
super.paintBorder(g);
// Here is where the Swing painting pipeline draws the current border
// for the JLabel instance.
// Please check javadoc.
}
// Start me here!
public static void main(String[] args) {
// SetBorder will dispatch an event to Event Dispatcher Thread to draw the
// new border around the component - you must call setBorder inside EDT.
// Swing rule 1.
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
// Inside EDT
JFrame frame = new JFrame("JLabel setBorder example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add the JLabel
final JLabelSetBorderPaintProblem label = new JLabelSetBorderPaintProblem("Just press or wait...");
frame.add(label);
// And change the border...
label.addMouseListener(new MouseAdapter() {
@Override public void mousePressed(MouseEvent e) {
label.setBorder(BORDERS.get(new Random().nextInt(BORDERS.size())));
}
});
// ...whenever you want
new Timer(5000, new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
label.setBorder(BORDERS.get(new Random().nextInt(BORDERS.size())));
}
}).start();
frame.pack();
frame.setVisible(true);
}
});
}
public static final List<Border> BORDERS;
static {
BORDERS = new ArrayList<Border>();
BORDERS.add(BorderFactory.createLineBorder(Color.BLACK));
BORDERS.add(BorderFactory.createLineBorder(Color.RED));
BORDERS.add(BorderFactory.createEtchedBorder());
BORDERS.add(BorderFactory.createTitledBorder("A border"));
}
}