【问题标题】:Swing JLabel: Force repaint()Swing JLabel:强制重绘()
【发布时间】: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。

标签: java swing components repaint


【解决方案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 线程设置的新值。

        【讨论】:

          猜你喜欢
          • 2019-04-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-09
          • 1970-01-01
          • 1970-01-01
          • 2021-03-15
          • 1970-01-01
          相关资源
          最近更新 更多