Как удалить пустой значок значка из JMenuItem (Java Swing)?

TL;DR

Есть ли способ избавиться от разрыва значка между границей MenuItem и определенным текстом? Он появляется, как только я создаю пункт меню, даже если я не устанавливаю значок, а также если я устанавливаю значок на ноль.

Длинная версия

Java-приложение, которое мы разрабатываем в нашей компании, существует с 90-х годов. В 2000-х он подвергся рестайлингу и использовал одну из этих ужасных, эхм, я имею в виду причудливых и красочных тем Synthetica. Так что теперь пришло время стать немного более серьезным и авторитетным, создать более элегантный и современный L&F. Вот почему я перешел с SyntheticaLookAndFeel на встроенный SystemLookAndFeel.

Хорошо, это было не так просто, как я думал раньше, но в любом случае... Я на правильном пути ;)

Единственное, что я изо всех сил пытаюсь заставить работать должным образом, это эти MenuItems. Обычно в Java, если вы создаете простое меню или PopMenu и добавляете JMenuItem, оно должно выглядеть как обычное меню, содержащее только текст. В нашем приложении я могу делать все, что захочу, оно ВСЕГДА показывает пробел слева от каждого пункта меню.

Я обыскал все рабочее пространство в поисках (неправильной) предустановленной конфигурации. Я проверил UIManager и попробовал разные способы установки значков пунктов меню, но ничего полезного не нашел. Я даже создал новый класс EmptyIcon, который задает значок шириной 1 пиксель и устанавливает его в качестве предустановки в моем UIManager.

// The empty icon class
public class EmptyIcon implements Icon {
    private int width = 1, height = 0;

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {}

    @Override
    public int getIconWidth() {
        return width;
    }

    @Override
    public int getIconHeight() {
        return height;
    }
}

// set this config in the gui configuration file
UIManager.put("MenuItem.arrowIcon", new EmptyIcon());
UIManager.put("MenuItem.checkIcon", new EmptyIcon());

Пока ничего не помогло. Кто-нибудь знает, откуда такое поведение? Где я должен искать, чтобы найти эту неправильную конфигурацию?

Есть ли способ заставить пользовательский интерфейс избавиться от этих значков?

Чтобы получить лучшее представление, вы можете найти несколько фотографий ниже. Это строка главного меню:

ГлавноеМеню

Это простое всплывающее меню, которое я только что создал:

Всплывающее меню

И это код, который я пытался использовать, чтобы удалить пробел:

jMenuItem1.setIcon(null);
jMenuItem1.setHorizontalAlignment(JMenuItem.LEFT);
jMenuItem1.setHorizontalTextPosition(JMenuItem.LEFT);
jMenuItem1.setIconTextGap(0);
jMenuItem1.setMargin(new Insets(0, 0, 0, 0));
jMenuItem1.setPressedIcon(null);
jMenuItem1.setText("TEST TEST TEST");

person Iamnino    schedule 29.10.2020    source источник
comment
Обратите внимание, что вам не нужно добавлять JMenuItem объекты в JMenu. Вы можете добавить любой JComponent. См. этот ответ для примера.   -  person Abra    schedule 30.10.2020
comment
Спасибо @Abra за эту подсказку. На самом деле было бы намного больше работы, чтобы реализовать собственный тип пункта меню, который работал бы во всех ситуациях. Просто подумайте, например, есть ли у вас подменю. Как вы обрабатываете jmenu внутри самого верхнего jmenu? Для этого также необходимо создать собственный компонент. На данный момент я использовал обходной путь maloomeister самым простым способом: я создал собственный класс, который расширяет JMenuItem и всегда устанавливает его ориентацию, за исключением случаев, когда я хочу использовать иконку.   -  person Iamnino    schedule 30.10.2020


Ответы (1)


Я попытался воспроизвести это, и оказалось, что это на самом деле напрямую связано с LookAndFeel, когда оно изменено на SystemLookAndFeel (у меня Win10). Похоже, это ошибка (или была) — см. https://bugs.openjdk.java.net/browse/JDK-8152981 (ссылка взята из эта тема). Кажется, это сделано намеренно, и я не нашел способа полностью удалить интервал между значками.

Однако добавление этого к JMenuItem помогло:

menuItem.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);

Это изменит ориентацию компонента, тем самым удалив пространство с левой стороны. Отрицательный побочный эффект: он переместит пространство вправо. Тем не менее, возможно, это сработает для вас.

Еще один способ, который я нашел, который, я думаю, будет работать только в том случае, если вы никогда не используете значки в своем JMenuItem, выглядит следующим образом:

item.setMargin(new Insets(2, -20, 2, 2));

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

person maloomeister    schedule 29.10.2020
comment
Хорошо, это помогает. Прежде всего спасибо. Так что это означает, что нет никакого реального решения для этого. Только обходные пути... Я не в восторге от этого, но это лучше, чем ничего. Во всяком случае, я не понимаю, почему это так. Это не имеет смысла. В меню не всегда есть значок. Несмотря на то, что способ отображения меню изменился за последние годы... - person Iamnino; 29.10.2020
comment
Ну в теории да. Насколько я понял проблему, для данного конкретного L&F фикса нет. Вы можете проверить другие L & F, которые могут не вызывать этого, это, по крайней мере, удержит вас от использования этих неприятных обходных путей. - person maloomeister; 29.10.2020
comment
Ты прав. Большое спасибо за все подсказки и пояснения. Я не собираюсь использовать какие-либо другие L&F, потому что они будут стоить каждый раз, когда вы захотите их обновить, и потому что мне не хочется создавать свои собственные с нуля: D Я согласен с вашими обходными путями. Спасибо еще раз - person Iamnino; 30.10.2020