java - JLabel 的 setBorder 方法导致绘画问题

标签 java swing awt

我有一个扩展 JLabel 的自定义类。对于该类的特定实例,我想在左侧的文本中添加一些间距。我需要间距,因为我正在设置此 JLabel 的背景,并且我不希望文本在彩色背景边缘旁边凸起。我摸索了很多并实现了这个(在绘制函数内):

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);

这似乎也以完全相同的方式破坏了重新绘制。我查看了我们应用程序的源代码,发现了我们设置边框的其他地方(包括空边框),但在 JLabels 上找不到任何设置(只有面板、按钮等)。有人以前见过这样的事情吗?知道如何解决吗?或者也许有另一种方法来获得我需要的间距,可以解决该错误?谢谢。

最佳答案

问题是您在 Paint 方法中调用该代码。您不应该这样做,因为它会卡住 EDT,并在 swing 绘画管道中出现不需要的循环。

您应该将该代码放在构造函数中,并在应用生命周期的其他位置更改组件设计状态。

如果您想了解有关 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"));
    }
}

关于java - JLabel 的 setBorder 方法导致绘画问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/928453/

相关文章:

java - JTabbedPane 的问题

java - 在 JPanel 上绘制多条线时出错

java - 如何在圆内画圆?

java - 不显示 Jtable 上数据库中的列名

java - 无法打开流式文件附件

java - Spring Boot 应用程序无法热插拔更改

java - 将读/写类合并到基本 GUI 登录中

java - 如何使用 JButton 单击事件关闭基于 JFrame 的窗口

java - Scala 中的端口扫描 : Application hangs for a closed port on the remote host

java - 在scala中,如何提取DynamicVariable中的值?