简体   繁体   English

Swing JLabel:强制重绘()

[英]Swing JLabel: Force repaint()

I am trying to repaint a JLabel dynamically and I can't for the life of me figure out how to do it. 我试图动态重绘一个JLabel,我不能为我的生活弄清楚如何做到这一点。 The code below will do as expected once I resize the screen but will not execute the code by itself. 一旦我调整屏幕大小,下面的代码将按预期执行,但不会自行执行代码。

The JLabel has a little circle to the left which is drawn in the border region to the left of the text. JLabel左侧有一个小圆圈,在文本左侧的边界区域绘制。 The color of the circle should change as a function of the health of an FTP connection (not shown). 圆的颜色应根据FTP连接(未显示)的健康状况而变化。 The thread monitoring the FTP connection calls the setStatus(int) method when the health changes. 监视FTP连接的线程在运行状况更改时调用setStatus(int)方法。

The circle is painted during initialization of the JLabel, and I am trying to re-execute this code using repaint() . 在JLabel初始化期间绘制圆圈,我试图使用repaint()重新执行此代码。

EDIT: I have also tried playing with revalidate() , invalidate() , and validate() to no avail. 编辑:我也尝试使用revalidate()invalidate()validate()无效。

EDIT: Thanks for pointing that out, I started by using paintComponent() and changed to paint() when that didn't work. 编辑:感谢您指出这一点,我开始使用paintComponent()并更改为paint()时,它不起作用。 So no glory for giving that as an answer (sorry, take it up with the Oracle) 因此没有荣耀作为答案(对不起,请与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;
        }
    }
}

Klong, your code works for me, so likely you have a bug elsewhere. Klong,你的代码适合我,所以你可能在其他地方有一个bug。 How I tested it, 我是如何测试的,

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

}

By the way, that's one small arc. 顺便说一句,这是一个弧。

You should override paintComponent and call super method before doing anything else: 在执行任何其他操作之前,您应该覆盖paintComponent并调用super方法:

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

}

我注意到的第一件事是你应该重写paintComponent而不是paint

Rather thanoverriding paint() , you probably just want to override paintComponent() . 您可能只想覆盖paintComponent() ,而不是覆盖paint() paintComponent()

Also, the call to super.paint(g) should be done at the beginning of your method, otherwise any painting you perform may be overwritten by the JLabel own painting. 此外,对super.paint(g)的调用应该在方法的开头进行,否则你执行的任何绘画都可能被JLabel自己的绘画覆盖。

If it doesn't repaint then the problem is likely that you are doing your FTP connection on the Event Dispatch Thread which is blocking and preventing the GUI from repainting. 如果它没有重新绘制,则问题很可能是您在事件调度线程上进行FTP连接,该线程阻塞并阻止GUI重新绘制。

You need to use a separate Thread for the FTP connection. 您需要为FTP连接使用单独的线程。 Read the section from the Swing tutorial on Concurrency for more information and a solution using a SwingWorker . 阅读有关并发的Swing教程中的部分以获取更多信息和使用SwingWorker的解决方案。

状态需要是volatile,以确保Event Dispatch Thread看到ftp线程设置的新值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM