Метод setBorder для JLabel, вызывающий проблему с краской - PullRequest
0 голосов
/ 30 мая 2009

У меня есть собственный класс, который расширяет 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 (только панели, кнопки и т. Д.). Кто-нибудь видел что-нибудь подобное раньше? Знаете, как это исправить? Или, может быть, другой способ получить требуемый интервал, который может обойти ошибку? Спасибо.

1 Ответ

3 голосов
/ 30 мая 2009

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

Вы должны поместить этот код в конструктор и изменить состояние разработки компонента в другом месте жизненного цикла приложения.

Если вы хотите узнать немного больше о живописи Swing, пожалуйста, прочитайте пост "конвейер рисования Swing" на pushing-pixels.org.

Обратите внимание, что вы можете использовать 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"));
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...