BorderFactory 和 Metal L&F 问题
BorderFactory and Metal L&F issues
我看到了一个奇怪的行为。 L&F 套装是金属。
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
如果我在 JPanel 上设置了 Border border1,然后我在同一个 JPanel 上将 Border 更改为 border2,当工具提示在 border2 上传递时,重绘会重绘 border1。这仅发生在 L&F Metal 上,带有 LineBorder、TitledBorder....
public class BorderTest {
private JFrame jFrame;
private Container contentPane;
private ColorsBoard colorsBoard;
public BorderTest() {
super();
ToolTipManager.sharedInstance().setInitialDelay(10);
ToolTipManager.sharedInstance().setDismissDelay(1500);
jFrame = new JFrame();
contentPane = jFrame.getContentPane();
contentPane.setLayout(new BorderLayout());
jFrame.setPreferredSize(new Dimension(700, 500));
colorsBoard = new ColorsBoard();
contentPane.add(colorsBoard, BorderLayout.CENTER);
JLabel label = new JLabel(""
+ "<html>Click two or three small squares. <br/>"
+ "LineBorder's are set. <br/>"
+ "Then pass the tooltips over the red borders. <br/>"
+ "The red LineBorders' are back to blue. <br/>"
+ "This phenomen appears only in Metal L&F. </html>");
contentPane.add(label, BorderLayout.EAST);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
new BorderTest();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ColorsBoard extends JPanel {
private int squareSize = 315;
private int horizontal = 8; //number of squares H
private int vertical = 8; //number of squares V
private SquaredPanel[] squarePanels;
int index = 0;
public int lastClickedSquare = -1;
// the chess board like JPanel.
public ColorsBoard() {
squarePanels= new SquaredPanel[horizontal * vertical];
this.setPreferredSize(new Dimension(squareSize, squareSize));
setLayout(null);
}
// fill with squares (SquaredPanel)
protected synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
int tileSizeH = squareSize / horizontal;
int tileSizeV = squareSize / vertical;
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
for(int i = 0; i < horizontal*vertical; i++) {
squarePanels[i] = new SquaredPanel(this);
}
index = 0;
for (int i = 0; i < horizontal; i++) {
for (int j = 0; j < vertical; j++) {
if(index == horizontal * vertical) break;
squarePanels[index].setBackground(Color.gray);
squarePanels[index].setSize(tileSizeH - 1, tileSizeV - 1);
squarePanels[index].setLocation(i * tileSizeH, j * tileSizeV);
squarePanels[index].setName("index " + index);
squarePanels[index].setIndex(index);
add(squarePanels[index]);
index++;
}
}
}
public void eraseLastBlueBorder(int lastClickedSquare2) {
if (lastClickedSquare == -1) {
lastClickedSquare = lastClickedSquare2;
return;
}
if(!squarePanels[lastClickedSquare].isRed)(squarePanels[lastClickedSquare]).cleanBorder();
lastClickedSquare = lastClickedSquare2;
}
}
class SquaredPanel extends JPanel {
private String name;
protected Boolean isRed = false;
private int index;
private Border theBorder = (new LineBorder(Color.gray, 2));
protected Border getTheBorder() {
return theBorder;
}
public SquaredPanel(ColorsBoard colorsBoard) {
super();
addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
colorsBoard.eraseLastBlueBorder(index);
setTitleBorder("RED");
}
public void mouseEntered(MouseEvent e) {
setToolTipText(name);
}
public void mouseExited(MouseEvent e) {
setToolTipText(null);
}
});
}
// the setBorder call
protected void setTitleBorder(String title) {
theBorder = (new LineBorder(title == "BLUE" ? Color.red : Color.blue, 2));
setBorder(theBorder);
}
public synchronized void cleanBorder() {
setTitleBorder("BLUE");
}
public void setName(String name) {
this.name = name;
}
public void setIndex(int k) {
index = k;
}
}
happens in Metal L&F only.
即使你没有专门设置LAF,你还是有问题。
If I set a Border border1 on a JPanel, then I change the Border to border2 on the same JPanel, when a tooltip passes on border2, repaint redraws border1
与工具提示无关。
只需点击几个方块,然后调整框架大小,所有边框都会重新涂成蓝色。
问题出在你的ColorsBoard
class.
您不应覆盖 paintComponent()
方法来创建组件。
一个画法只用于画画
只要 Swing 确定需要重新绘制组件,就会调用 paintComponent() 方法。这就是调整框架大小也会导致问题的原因。您正在重新创建所有组件。
解决方法:
- 不要覆盖 paintComponent() 方法!
- 在 class
的构造函数中创建所有组件
- 不要使用空布局。而是在面板上使用 GridLayout 并将您的方块添加到网格中。
- 在构造函数中使用
setBackground(Color.LIGHT_GRAY)
设置背景
还有:
- 删除方法中的所有
synchronized
关键字。不需要它们。
- 不要使用“==”来比较对象。使用
equals(...)
方法。
我看到了一个奇怪的行为。 L&F 套装是金属。
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
如果我在 JPanel 上设置了 Border border1,然后我在同一个 JPanel 上将 Border 更改为 border2,当工具提示在 border2 上传递时,重绘会重绘 border1。这仅发生在 L&F Metal 上,带有 LineBorder、TitledBorder....
public class BorderTest {
private JFrame jFrame;
private Container contentPane;
private ColorsBoard colorsBoard;
public BorderTest() {
super();
ToolTipManager.sharedInstance().setInitialDelay(10);
ToolTipManager.sharedInstance().setDismissDelay(1500);
jFrame = new JFrame();
contentPane = jFrame.getContentPane();
contentPane.setLayout(new BorderLayout());
jFrame.setPreferredSize(new Dimension(700, 500));
colorsBoard = new ColorsBoard();
contentPane.add(colorsBoard, BorderLayout.CENTER);
JLabel label = new JLabel(""
+ "<html>Click two or three small squares. <br/>"
+ "LineBorder's are set. <br/>"
+ "Then pass the tooltips over the red borders. <br/>"
+ "The red LineBorders' are back to blue. <br/>"
+ "This phenomen appears only in Metal L&F. </html>");
contentPane.add(label, BorderLayout.EAST);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
new BorderTest();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ColorsBoard extends JPanel {
private int squareSize = 315;
private int horizontal = 8; //number of squares H
private int vertical = 8; //number of squares V
private SquaredPanel[] squarePanels;
int index = 0;
public int lastClickedSquare = -1;
// the chess board like JPanel.
public ColorsBoard() {
squarePanels= new SquaredPanel[horizontal * vertical];
this.setPreferredSize(new Dimension(squareSize, squareSize));
setLayout(null);
}
// fill with squares (SquaredPanel)
protected synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
int tileSizeH = squareSize / horizontal;
int tileSizeV = squareSize / vertical;
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
for(int i = 0; i < horizontal*vertical; i++) {
squarePanels[i] = new SquaredPanel(this);
}
index = 0;
for (int i = 0; i < horizontal; i++) {
for (int j = 0; j < vertical; j++) {
if(index == horizontal * vertical) break;
squarePanels[index].setBackground(Color.gray);
squarePanels[index].setSize(tileSizeH - 1, tileSizeV - 1);
squarePanels[index].setLocation(i * tileSizeH, j * tileSizeV);
squarePanels[index].setName("index " + index);
squarePanels[index].setIndex(index);
add(squarePanels[index]);
index++;
}
}
}
public void eraseLastBlueBorder(int lastClickedSquare2) {
if (lastClickedSquare == -1) {
lastClickedSquare = lastClickedSquare2;
return;
}
if(!squarePanels[lastClickedSquare].isRed)(squarePanels[lastClickedSquare]).cleanBorder();
lastClickedSquare = lastClickedSquare2;
}
}
class SquaredPanel extends JPanel {
private String name;
protected Boolean isRed = false;
private int index;
private Border theBorder = (new LineBorder(Color.gray, 2));
protected Border getTheBorder() {
return theBorder;
}
public SquaredPanel(ColorsBoard colorsBoard) {
super();
addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
colorsBoard.eraseLastBlueBorder(index);
setTitleBorder("RED");
}
public void mouseEntered(MouseEvent e) {
setToolTipText(name);
}
public void mouseExited(MouseEvent e) {
setToolTipText(null);
}
});
}
// the setBorder call
protected void setTitleBorder(String title) {
theBorder = (new LineBorder(title == "BLUE" ? Color.red : Color.blue, 2));
setBorder(theBorder);
}
public synchronized void cleanBorder() {
setTitleBorder("BLUE");
}
public void setName(String name) {
this.name = name;
}
public void setIndex(int k) {
index = k;
}
}
happens in Metal L&F only.
即使你没有专门设置LAF,你还是有问题。
If I set a Border border1 on a JPanel, then I change the Border to border2 on the same JPanel, when a tooltip passes on border2, repaint redraws border1
与工具提示无关。
只需点击几个方块,然后调整框架大小,所有边框都会重新涂成蓝色。
问题出在你的ColorsBoard
class.
您不应覆盖 paintComponent()
方法来创建组件。
一个画法只用于画画
只要 Swing 确定需要重新绘制组件,就会调用 paintComponent() 方法。这就是调整框架大小也会导致问题的原因。您正在重新创建所有组件。
解决方法:
- 不要覆盖 paintComponent() 方法!
- 在 class 的构造函数中创建所有组件
- 不要使用空布局。而是在面板上使用 GridLayout 并将您的方块添加到网格中。
- 在构造函数中使用
setBackground(Color.LIGHT_GRAY)
设置背景
还有:
- 删除方法中的所有
synchronized
关键字。不需要它们。 - 不要使用“==”来比较对象。使用
equals(...)
方法。