Swing JLabel:强制重绘()

Posted

技术标签:

【中文标题】Swing JLabel:强制重绘()【英文标题】:Swing JLabel: Force repaint() 【发布时间】:2011-11-16 06:15:24 【问题描述】:

我正在尝试动态地重新绘制 JLabel,但我终其一生都无法弄清楚如何去做。一旦我调整屏幕大小,下面的代码将按预期执行,但不会自行执行代码。

JLabel 左侧有一个小圆圈,绘制在文本左侧的边框区域。圆圈的颜色应根据 FTP 连接(未显示)的健康状况而变化。监控FTP连接的线程在健康发生变化时调用setStatus(int)方法。

圆圈是在 JLabel 初始化期间绘制的,我正在尝试使用 repaint() 重新执行此代码。

编辑:我也试过玩revalidate()invalidate()validate(),但无济于事。

编辑:感谢您指出这一点,我从使用 paintComponent() 开始,然后在不起作用时更改为 paint()。因此,将其作为答案并不荣耀(抱歉,请与 Oracle 讨论)

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.BorderFactory;
import javax.swing.JLabel;

import com.my.package.io.ftp.FTPConnectionListenable;

class StatusLabel extends JLabel implements FTPConnectionListenable 

    private Integer status;

    // Constructor
    StatusLabel(final String text) 
        super(text);
        setFont(new Font("Dialog", Font.PLAIN, 10));
        setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
    

    @Override
    public void paintComponent(final Graphics g) 
        super.paintComponent(g);
        g.setColor(getColor());
        g.fillArc(0, this.getHeight()/4, 8, 8, 0, 360);
    

    @Override
    public void setStatus (final int status) 
        this.status = status;
        if (status !=0) 
        repaint(); // Doesn't work :(
    

    private Color getColor () 
        switch (status) 
        case FTPConnectionListenable.STATUS_OK:
            return Color.GREEN;
        case FTPConnectionListenable.STATUS_WARNING:
            return Color.ORANGE;
        case FTPConnectionListenable.STATUS_ERROR:
            return Color.RED;
        default: 
            return Color.PINK;
        
    

【问题讨论】:

我强烈建议您使用enum 而不是interface 来代替FTPConnectionListenable 【参考方案1】:

Klong,你的代码对我有用,所以很可能你在其他地方有错误。我是如何测试它的,

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;


class StatusLabel extends JLabel implements FTPConnectionListenable 

    private Integer status;

    // Constructor
    StatusLabel(final String text) 
        super(text);
        setFont(new Font("Dialog", Font.PLAIN, 10));
        setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
    

    @Override
    public void paintComponent(final Graphics g) 
        super.paintComponent(g);
        g.setColor(getColor());
        g.fillArc(0, this.getHeight()/4, 8, 8, 0, 360);
    

    @Override
    public void setStatus (final int status) 
        this.status = status;
        if (status !=0) 
        repaint(); 
    

    private Color getColor () 
        switch (status) 
        case FTPConnectionListenable.STATUS_OK:
            return Color.GREEN;
        case FTPConnectionListenable.STATUS_WARNING:
            return Color.ORANGE;
        case FTPConnectionListenable.STATUS_ERROR:
            return Color.RED;
        default: 
            return Color.PINK;
        
    

    public static void main(String[] args) 
      final StatusLabel statusLabel = new StatusLabel("Foo");
      statusLabel.setStatus(FTPConnectionListenable.STATUS_OK);
      new Timer(1000, new ActionListener() 
         int counter = 0;
         @Override
         public void actionPerformed(ActionEvent e) 
            counter++;
            counter %= 4;
            statusLabel.setStatus(counter);
         
      ).start();

      JOptionPane.showMessageDialog(null, statusLabel);
   


interface FTPConnectionListenable 

   static final int STATUS_ERROR = 0;
   static final int STATUS_WARNING = 1;
   static final int STATUS_OK = 2;
   void setStatus(int status);


顺便说一句,这是一个弧线。

【讨论】:

【参考方案2】:

你应该在做任何事情之前重写paintComponent并调用super方法:

@Override
public void paintComponent(Graphics g) 
    super.paintComponent(g);
    g.setColor(getColor());
    g.fillArc(0, this.getHeight()/4, 8, 8, 0, 360);


【讨论】:

@klong:“但它不起作用”什么也没告诉我们。当你尝试它时会发生什么?错误?没有显示?会后空翻吗? @Heisenburg 显式调用 repaint() 的原因是使用新的 status 值执行 paintComponent 方法。不起作用的是圆圈不会改变颜色。我可以强制paintComponent以新状态执行的唯一方法是调整屏幕大小。 @klonq:对不起..我没有看到那个方法。让我想想可能是什么问题。 @klong,你在别处遇到了一个错误,因为你的代码对我来说很好。 @klong: 检查状态值是否有效地不同于 0【参考方案3】:

我注意到的第一件事是您应该覆盖paintComponent,而不是paint

【讨论】:

@klonq,当我有更多时间时,我会仔细看看这个。感谢您的反馈。【参考方案4】:

如果它没有重新绘制,那么问题可能是您在事件调度线程上进行 FTP 连接,该线程阻塞并阻止 GUI 重新绘制。

您需要为 FTP 连接使用单独的线程。阅读 Concurrency 上的 Swing 教程部分,了解更多信息和使用 SwingWorker 的解决方案。

【讨论】:

【参考方案5】:

您可能只想覆盖paintComponent(),而不是覆盖paint()

另外,对super.paint(g) 的调用应该在你的方法开始时完成,否则你执行的任何绘画都可能被JLabel 自己的绘画覆盖。

【讨论】:

【参考方案6】:

状态需要是可变的,以确保事件调度线程看到 ftp 线程设置的新值。

【讨论】:

以上是关于Swing JLabel:强制重绘()的主要内容,如果未能解决你的问题,请参考以下文章

JAVA学习Swing章节标签JLabel中图标的使用

防止带有 html 的 JLabel 换行

如何在 Java Swing 中的 JLabel 中设置行距/高度?

如何让 Swing 将我自己的 HTMLEditorKit 用于 JLabel/JButton/等

将 JLabel 数组导入 JComponent

Java Swing JLabel、HTML 和自定义字体