Как я могу воспроизвести отключенный внешний вид для JCheckBox? - PullRequest
0 голосов
/ 28 июня 2010

Возьмите следующий пример кода.В Swing есть ошибка, из-за которой отключенные компоненты не отображаются как отключенные, если компонент содержит HTML.Помимо сообщения о проблеме, о которой, я надеюсь, коллега уже позаботился, есть ли хороший способ обойти эту проблему?

Какое бы решение я ни принял, я хочу, чтобы это было глобальным решением, а нечто-то, что нужно взломать в каждом флажке приложения.

Я попытался создать пользовательский интерфейс для флажка, который вызывает setForeground до и после рисования, но получается, вызывая setForeground, он запускает событие, которое в конечном итоге приводит к вызову repaint(), который вызывает средство визуализации, ...

import java.awt.GridLayout;
import java.util.Arrays;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class TestCheckBoxes extends JFrame
{
    public TestCheckBoxes()
    {
        JCheckBox checkBox1 = new JCheckBox("Enabled, plain text");
        JCheckBox checkBox2 = new JCheckBox("<html><p>Enabled, HTML");
        JCheckBox checkBox3 = new JCheckBox("Disabled, plain text");
        checkBox3.setEnabled(false);
        JCheckBox checkBox4 = new JCheckBox("<html><p>Disabled, HTML");
        checkBox4.setEnabled(false);

        setLayout(new GridLayout(4, 1));

        for (JCheckBox checkBox : Arrays.asList(checkBox1, checkBox2, checkBox3, checkBox4))
        {
            checkBox.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
            add(checkBox);
        }

        ((JComponent) getContentPane()).setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
        pack();
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                TestCheckBoxes frame = new TestCheckBoxes();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}

Ответы [ 3 ]

1 голос
/ 28 июня 2010

Вы можете разделить флажок и метку на их собственные компоненты и просто сделать флажок без метки. Вы также можете добавить их на собственную панель и переопределить метод панели setEnabled(), чтобы просто включить / отключить флажок и изменить цвет метки. Возьмите этот фрагмент кода, например:

final JCheckBox checkbox = new JCheckBox();
final JLabel label = new JLabel();
JPanel panel = new JPanel() {
    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        checkbox.setEnabled(enabled);
        if (enabled)
            label.setForeground(Color.BLACK);
        else
            label.setForeground(Color.GRAY);
    }
};
panel.add(checkbox);
panel.add(label);

Обратите внимание, что checkbox и метка должны быть окончательными, чтобы использовать их в методе setEnabled () `нашей панели. В зависимости от того, как часто вы вставляете HTML-код в свои флажки, вы всегда можете создать собственный класс компонента, чтобы сделать это.

public class HTMLCheckBox extends JPanel {
    private JCheckBox checkbox = new JCheckBox();
    private JLabel label = new JLabel();
    private Color disabledColor = Color.GRAY;
    private Color enabledColor = Color.BLACK;

    public HTMLCheckBox(String text) {
        label.setText(text);
        add(checkbox);
        add(label);
    }

    public boolean isSelected() {
        return checkbox.isSelected();
    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        checkbox.setEnabled(enabled);
        if (enabled)
            label.setForeground(enabledColor);
        else
            label.setForeground(disabledColor);
    }
}

А затем добавьте свои собственные конструкторы и методы по своему желанию. Например, переопределите setBackground(), чтобы установить фон для панели, флажок и метку. setText() метод для изменения текста метки, вероятно, также будет удобен. Все, что вы хотели бы сделать. И, возможно, даже сеттеры для enabledColor и disabledColor, чтобы вы могли изменить их по своему желанию.

0 голосов
/ 29 июня 2010

Я должен перестать отвечать на свои собственные вопросы ... должно быть, что-то связано с часовыми поясами, и у меня есть время подумать об этом во время сна.

Где-то еще в приложении ...

UIManager.put("CheckBoxUI", "package.for.CustomisedWindowsCheckBoxUI");

И затем это реализация, но она все еще довольно хакерская, и она использует служебный метод для генерации строки цвета HTML, который не очень удобен для публикации здесь.

Обратите внимание, что это исправляет только для Windows L & F. Metal L & F также был свидетелем проблемы, но решение то же самое, вместо этого просто подкласс BasicCheckBoxUI.

import java.awt.Graphics;

import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View;

import com.sun.java.swing.plaf.windows.WindowsCheckBoxUI;

import com.blah.util.ColourUtils;

/**
 * Customisation of Windows check box UI to fix bugs.
 */
public class CustomisedWindowsCheckBoxUI extends WindowsCheckBoxUI {
    /**
     * Factory method called from Swing.
     *
     * @param b the check box.
     * @return the UI.
     */
    public static ComponentUI createUI(JComponent b) {
        // TODO: Sun have an AppContext they use to store these once per app.
        //  Might be more sociable to use something like that.
        return new CustomisedWindowsCheckBoxUI();
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        AbstractButton b = (AbstractButton) c;

        // Works around a bug in BasicButtonUI where a disabled button with HTML markup in the text will
        // not appear to be disabled.

        // TODO: Find a way to fix this globally for HTML rendering.  It seems odd that it isn't working.
        // I can see the code in BasicHTML.createHTMLView which uses the foreground colour, which is
        // obviously why setForeground() works as a workaround.

        if (b.getForeground() instanceof ColorUIResource) {
            View view = (View) c.getClientProperty(BasicHTML.propertyKey);
            if (view != null) {
                // Ensure that we don't update the renderer if the value hasn't changed.
                String cachedHtmlFor = (String) c.getClientProperty("cachedHtmlFor");
                String key = String.format("%s:%s", c.isEnabled(), b.getText());
                if (!key.equals(cachedHtmlFor)) {
                    c.putClientProperty("cachedHtmlFor", key);
                    if (c.isEnabled()) {
                        BasicHTML.updateRenderer(c, b.getText());
                    } else {
                        BasicHTML.updateRenderer(c, String.format("<html><div style='color: %s'>%s",
                                                                  ColourUtils.toHtmlColour(b.getBackground().darker()),
                                                                  b.getText()));
                    }
                }
            }
        }

        super.paint(g, c);
    }
}
0 голосов
/ 28 июня 2010

Я бы предложил вместо этого использовать рендеры.Вы можете использовать HTML внутри рендерера (например, JLabel), и ваша проблема исчезнет сама собой:)

Больше информации на http://java.sun.com/docs/books/tutorial/uiswing/components/combobox.html#renderer

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...