Swing JLabel: принудительная перекраска()

Я пытаюсь динамически перерисовать JLabel, и я не могу понять, как это сделать. Приведенный ниже код будет работать, как и ожидалось, как только я изменю размер экрана, но не будет выполнять код сам по себе.

JLabel имеет небольшой кружок слева, который нарисован в области границы слева от текста. Цвет круга должен меняться в зависимости от работоспособности FTP-соединения (не показано). Поток, отслеживающий FTP-соединение, вызывает метод setStatus(int) при изменении работоспособности.

Круг рисуется во время инициализации JLabel, и я пытаюсь повторно выполнить этот код, используя repaint().

EDIT: я также пытался играть с revalidate(), invalidate() и validate() безрезультатно.

EDIT: Спасибо, что указали на это, я начал с использования paintComponent() и перешел на paint(), когда это не сработало. Так что нет славы за то, что дал это как ответ (извините, примите это с Оракулом)

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

person klonq    schedule 13.09.2011    source источник
comment
Я настоятельно рекомендую вам использовать enum, а не interface для FTPConnectionListenable.   -  person jfpoilpret    schedule 13.09.2011


Ответы (6)


Клонг, ваш код у меня работает, так что, скорее всего, у вас есть ошибка в другом месте. Как я это тестировал,

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

}

Кстати, это одна маленькая дуга.

person Hovercraft Full Of Eels    schedule 13.09.2011

Вы должны переопределить paintComponent и вызвать суперметод, прежде чем делать что-либо еще:

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

}
person Heisenbug    schedule 13.09.2011
comment
@klong: но это не работает, ничего нам не говорит. Что происходит, когда вы пытаетесь это сделать? Ошибки? Нет дисплея? Делает сальто назад? - person Hovercraft Full Of Eels; 13.09.2011
comment
@Heisenburg Причина явного вызова repaint() заключается в том, чтобы выполнить метод paintComponent с новым значением статуса. Что не работает, так это то, что круг не меняет цвет. Единственный способ, которым я могу заставить paintComponent выполняться с новым статусом, — это изменить размер экрана. - person klonq; 13.09.2011
comment
@klonq: извините .. Я не видел этого метода. Немного подумаю, в чем может быть проблема. - person Heisenbug; 13.09.2011
comment
@klong, у вас есть ошибка в другом месте, потому что ваш код отлично работает для меня. - person Hovercraft Full Of Eels; 13.09.2011
comment
@klong: убедитесь, что значение статуса эффективно отличается от 0 - person Heisenbug; 13.09.2011

Первое, что я заметил, это то, что вы должны переопределять paintComponent, а не paint.

person mre    schedule 13.09.2011
comment
@klonq, когда у меня будет больше времени, я посмотрю на это поближе. Спасибо за ответ. - person mre; 13.09.2011

Если он не перерисовывается, проблема, скорее всего, в том, что вы используете FTP-соединение в потоке отправки событий, который блокирует и предотвращает перерисовку графического интерфейса.

Вам нужно использовать отдельный поток для FTP-соединения. Прочтите раздел руководства Swing по Параллелизм для получения дополнительной информации и решение с использованием SwingWorker.

person camickr    schedule 13.09.2011

Вместо переопределения paint() вы, вероятно, просто захотите переопределить paintComponent().

Кроме того, вызов super.paint(g) должен выполняться в начале вашего метода, иначе любое рисование, которое вы выполняете, может быть перезаписано собственным рисунком JLabel.

person jfpoilpret    schedule 13.09.2011

Состояние должно быть изменчивым, чтобы гарантировать, что поток отправки событий увидит новое значение, установленное потоком ftp.

person Michael Krussel    schedule 13.09.2011