Как заставить JPopupMenu показывать заголовок, даже если интерфейс Look and Feel диктует иное? - PullRequest
2 голосов
/ 17 декабря 2011

Конструктор Javadoc для JPopupMenu сообщает следующее:

JPopupMenu

общедоступное JPopupMenu (метка строки)

Constructs a JPopupMenu with the specified title.

Parameters:
    label - the string that a UI **may** use to display as a title for the popup menu.

Ключевое слово "май". Очевидно, что в пользовательском интерфейсе по умолчанию такие заголовки игнорируются при создании всплывающего меню. Я очень хочу, чтобы такие заголовки использовались в некоторых из моих всплывающих меню, независимо от того, думает ли мне L & F или нет. Я не могу найти крючок, чтобы сделать это так. Очевидно, это где-то глубоко скрыто в коде пользовательского интерфейса. Есть ли способ переопределить это значение по умолчанию?

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

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

Ответы [ 3 ]

5 голосов
/ 03 февраля 2013

У меня была похожая проблема (я имею в виду оригинальный вопрос). Я решил это так:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;

public class LabeledPopupMenu extends JPopupMenu
{
    private String originalLabelText = null;
    private final JLabel label;

    private static String replaceHTMLEntities(String text)
    {
        if (-1 != text.indexOf("<") ||
            -1 != text.indexOf(">") ||
            -1 != text.indexOf("&"))
        {
            text = text.replaceAll("&", "&amp;");
            text = text.replaceAll("<", "&lt;");
            text = text.replaceAll(">", "&gt;");
        }
        return text;
    }

    public LabeledPopupMenu()
    {
        super();
        this.label = null;
    }

    public LabeledPopupMenu(String label)
    {
        super();
        originalLabelText = label;
        this.label = new JLabel("<html><b>" +
            replaceHTMLEntities(label) + "</b></html>");
        this.label.setHorizontalAlignment(SwingConstants.CENTER);
        add(this.label);
        addSeparator();
    }

    @Override public void setLabel(String text)
    {
        if (null == label) return;
        originalLabelText = text;
        label.setText("<html><b>" +
            replaceHTMLEntities(text) +
            "</b></html>");
    }

    @Override public String getLabel()
    {
        return originalLabelText;
    }
}

Я протестировал его только на Mac с L & F по умолчанию, но у меня это сработало:

public static void main(String[] args)
{
    JFrame frame = new JFrame();
    frame.setSize(100, 100);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocation(100, 100);
    frame.setVisible(true);

    LabeledPopupMenu myPopup = new LabeledPopupMenu("Say & <something>");
    myPopup.add(new JMenuItem("Sample item"));
    myPopup.show(frame, 50, 50);
}
2 голосов
/ 20 декабря 2011

Даже не знал об этой функции: -)

Копая немного, оказывается, что MotifLookAndFeel - единственный из основных LAF, которые поддерживают заголовок во всплывающем окне. Это реализуется по пользовательской границе. Что вы можете сделать также:

    JPopupMenu popup = new JPopupMenu("My Label");
    popup.add("dummy menu item");
    Border titleUnderline = BorderFactory.createMatteBorder(1, 0, 0, 0, popup.getForeground());
    TitledBorder labelBorder = BorderFactory.createTitledBorder(
            titleUnderline, popup.getLabel(),
            TitledBorder.CENTER, TitledBorder.ABOVE_TOP, popup.getFont(), popup.getForeground());
    popup.setBorder(BorderFactory.createCompoundBorder(popup.getBorder(),
            labelBorder));
    JComponent comp = new JPanel();
    comp.setComponentPopupMenu(popup);

Примечание: насколько я вижу, нет безопасного способа определить, обрабатывает ли LAF сам заголовок (что привело бы к его удвоению)

1 голос
/ 17 декабря 2011

JPopup - очень странный контейнер, у меня не сработало

1) public JPopupMenu(String label)

2) не сработало выравнивание для JLabel, возможно, кто-нибудь может проверить выравнивание текста, используя HTML

3) невозможно, показывает, что выпадающее меню JComboBox совпадает с JPopup (не имеет значения, является ли JPopup полутяжелым или тяжелым весом)

4) и еще один (не важно для базового Swing) протестированный Java5 и 6 с различными LaF

enter image description here

import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.event.*;
import javax.swing.plaf.*;
import org.pushingpixels.substance.api.skin.SubstanceOfficeSilver2007LookAndFeel;

class MyPopupMenuListener implements PopupMenuListener {

    public void popupMenuCanceled(PopupMenuEvent popupMenuEvent) {
        System.out.println("Canceled");
    }

    public void popupMenuWillBecomeInvisible(PopupMenuEvent popupMenuEvent) {
        System.out.println("Becoming Invisible");
    }

    public void popupMenuWillBecomeVisible(PopupMenuEvent popupMenuEvent) {
        System.out.println("Becoming Visible");
    }
}

public class PopupMenuListenerDemo {

    public static void main(final String args[]) {
        final JFrame frame = new JFrame("PopupSample Example");
        /*SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                try {
                    UIManager.setLookAndFeel(new SubstanceOfficeSilver2007LookAndFeel());
                    SwingUtilities.updateComponentTreeUI(frame);
                } catch (UnsupportedLookAndFeelException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                System.out.println(info.getName());
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (UnsupportedLookAndFeelException e) {
            // handle exception
        } catch (ClassNotFoundException e) {
            // handle exception
        } catch (InstantiationException e) {
            // handle exception
        } catch (IllegalAccessException e) {
            // handle exception
        }
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        UIResource res = new BorderUIResource.LineBorderUIResource(Color.red);
        UIManager.put("PopupMenu.border", res);

        JPopupMenu popupMenu = new JPopupMenu("Title");

        //force to the Heavyweight Component or able for AWT Components
        popupMenu.setLightWeightPopupEnabled(false); 

        PopupMenuListener popupMenuListener = new MyPopupMenuListener();
        popupMenu.addPopupMenuListener(popupMenuListener);

        JLabel lbl1 = new JLabel("My Title");
        lbl1.setHorizontalAlignment(SwingConstants.CENTER);
        popupMenu.add(lbl1);

        JTextField text = new JTextField("My Title");
        text.setHorizontalAlignment(SwingConstants.CENTER);
        popupMenu.add(text);

        String[] list = {"1", "2", "3", "4",};
        JComboBox comb = new JComboBox(list);
        popupMenu.add(comb);

        JMenuItem pasteMenuItem = new JMenuItem("Paste");
        pasteMenuItem.setEnabled(false);
        popupMenu.add(pasteMenuItem);
        popupMenu.addSeparator();
        JMenuItem findMenuItem = new JMenuItem("Find");
        popupMenu.add(findMenuItem);
        JButton btn = new JButton();
        JLabel lbl = new JLabel("My Title");
        lbl.setHorizontalAlignment(SwingConstants.CENTER);
        btn.setComponentPopupMenu(popupMenu);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(btn, BorderLayout.CENTER);
        frame.add(lbl, BorderLayout.NORTH);
        frame.setSize(350, 150);
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                frame.setVisible(true);
            }
        });
    }
}

5 и ужасное выравнивание для JLabel, если там добавлен JComboBox :-) бррррр !!!!

enter image description here

...