Правильный способ использования действий для создания меню, панелей инструментов и других компонентов в Java - PullRequest
8 голосов
/ 23 января 2009

Наивный способ написания построения меню в приложении Java Swing - сделать что-то вроде:

JMenu fileMenu = new JMenu("File");
JMenuItem openItem = new JMenuItem("Open...");
openItem.addActionListener(new ActionListener() { /* action listener stuff */ } )
fileMenu.addMenuItem(openItem);

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

Action openAction = new AbstractAction();
openAction.setName("Open...");
openAction.addActionListener(new ActionListener() { /* action listener stuff */ } )
...
JMenuItem openItem = new JMenuItem(openAction);

Мой вопрос: Каков наилучший способ управления этими объектами Action, чтобы их можно было использовать в меню, панелях инструментов и т. Д.?

  • Создать фабричный класс, который возвращает определенные действия?
  • Объявить все действия как private static final Action в некотором служебном классе?
  • Воспользуйтесь преимуществами инфраструктуры приложений Java?
  • Что-то еще?

Ответы [ 6 ]

4 голосов
/ 23 января 2009

Разработанные мной приложения, которым необходимо использовать те же действия в меню, панелях инструментов и других кнопках, были выполнены с помощью Swing Application Framework.

Платформа приложений Swing

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

Сайт стоит прочитать.

1 голос
/ 23 января 2009

Вы можете сгруппировать все ваше abstractAction, используя выделенную карту javax.swing.actionmap. Смотри http://java.sun.com/javase/6/docs/api/javax/swing/ActionMap.html

Более того, каждый JComponent имеет внутреннюю actionMap (getActionMap ()).

class MyComponent
extends JPanel
{
public static final String ACTION_NAME1="my.action.1";

public MyComponent()
 {
 AbstractAction action= new AbstractAction() { ... }
 getActionMap().put(ACTION_NAME1,action);
...

 menu.add(getActionMap().get(ACTION_NAME1));
 }

}

Надеюсь, это поможет

0 голосов
/ 23 января 2009
  1. Создать базовое действие для вашего приложения; это поможет вам НЕМЕДЛЕННО позже
  2. Создавайте действия, которые есть в вашем коде, вместо этого отдавайте предпочтение подклассам вашего базового действия

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

То, что вы хотите - это иметь последовательный способ найти / создать действие в вашем коде.

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

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

0 голосов
/ 23 января 2009

Редактировать: у меня было чувство, что люди не верят, что это возможно или просто, поэтому я сделал это - заняло около часа с нуля - потребовалось бы 40 минут, если бы я просто использовал один метод как цель вместо того, чтобы отражать ее для разделения методов для каждого пункта меню.

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

--- оригинальный пост

Прежде всего, не забудьте отделить ваш код от данных. Это означает, что вы никогда не должны печатать:

new Menu("File...");

Строка "Файл ..." является данными. Если вы начнете думать так, вы обнаружите, что ваш вопрос отвечает сам на себя.

Сначала вам нужно собрать некоторые данные. Вы должны получить «Файл ...» и «Сохранить» в меню. Я обычно начинаю со строкового массива (который вы можете легко переместить в файл)

new String[]{"File...","+Save","Load"...} 

Это один из самых простых шаблонов, с которых я начинал. Затем вы можете разобрать знак + и использовать его для обозначения «Выпадающий уровень в меню при добавлении этого» * ​​1017 *

Это просто глупое соглашение, придумайте свое, если оно вам не нравится.

Следующий шаг - это привязка к коду для запуска. Вы могли бы заставить их всех вызывать один и тот же метод, но какая боль в заднице (оператор Giant switch). Одной из возможностей является использование отражения для привязки имени метода во время чтения данных. Вот одно из решений (опять же, оно может не соответствовать вашим вкусам)

new String[]{"File...[fileMenu]","+Save[saveMenu]","Load[loadMenu]"...} 

Затем вы разбираете вещь в квадратных скобках, рефлексивно подключаете ее к методу в вашем текущем классе, и вы настроены.

В этот момент у меня всегда есть искушение, и я научился бороться с ним, потому что он НИКОГДА не срабатывает. Искушение состоит в том, чтобы использовать первый набор данных («Файл ...») и манипулировать им, чтобы он соответствовал некоторому шаблону и автоматически связывался с вашим кодом (в этом случае удалите все не-альфа-символы, сделайте первую букву строчной и добавьте «Меню», чтобы получить правильное имя метода). Не стесняйтесь попробовать это, это очень привлекательно и кажется гладким, но будьте готовы отказаться от него, когда он не удовлетворяет некоторой потребности (например, два пункта меню с одинаковым именем в разных подменю).

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

В любом случае, как только вы начнете кодировать, как это, вы обнаружите, что ВСЕ ваше построение меню выполняется одним методом из 10 строк, и вы можете изменить его в соответствии со своими потребностями. У меня был случай, когда мне пришлось изменить набор меню на иерархию кнопок, и я сделал это за 2 минуты.

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

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

редактировать:

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

Я мог бы сделать то, что предложил выше, менее чем за полчаса (возможно, час, чтобы сделать отражающую версию). Это почти всегда так же долго, как если бы вы использовали незарегистрированную версию, и с тех пор ваши сбережения увеличиваются при каждом изменении.

Это очень похоже на то, что людям нравится в ruby, за исключением того, что с помощью ruby ​​они, кажется, вставляют еще больше данных в свой код (что делает чрезвычайно сложным полное извлечение данных из кода, что всегда является хорошей целью для интернационализации ).

Хм, я уже говорил, что если вы умеете извлекать данные таким образом, i18n практически бесплатен?

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

0 голосов
/ 23 января 2009

Также см. этот вопрос , который в значительной степени совпадает с тем, что вы спрашиваете.

0 голосов
/ 23 января 2009

Action - плохая абстракция - ActionListener, приваренный к Map бедного человека.

Конечно, не присваивайте их static, так как они изменчивы и также нуждаются в некотором контексте для полезной работы.

Мой общий совет по программированию с графическим интерфейсом состоит в том, что он фактически такой же, как и любая другая область программирования. Следуйте обычной хорошей практике. В частности, разделение по слоям, разделение задач, использование (внедрение) наследования редко и не пишут большой шарик грязи.

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