|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
Шаблоны проектирования для смены языка программы.08.02.2011, 10:43. Показов 5241. Ответов 22
Метки нет (Все метки)
Требуется создать библиотеку для смены языка пользовательского интерфейса программ.
В принципе, решается это логко - берется интерфейс Observer и класс Observable и на их основе делается смена языка. Только вот слишком уж геморройно для каждого визуального компонента создавать наследника, реализующего интерфейс Observer. Хотя это наиболее гибкое и универсальное решение. Можно пойти по другому пути, и вместо реализации интерфейса сделать отдельный класс, который по типу изменяемого обьекта (и, возможно, передаваемым параметрам) будет определять, что именно в обьекте изменить. Однако такой подход требует серьезного обдумывания, поскольку библиотека должна быть стандартной. Кто сталкивался с проблемой изменения языка программы и имеет готовое и удобное решение?
0
|
|
| 08.02.2011, 10:43 | |
|
Ответы с готовыми решениями:
22
Шаблоны проектирования Шаблоны проектирования Шаблоны проектирования (литература для изучения) |
|
paradise
|
|
| 08.02.2011, 11:07 | |
|
Как насчет Localization и Internationalization?
|
|
|
3 / 3 / 0
Регистрация: 25.08.2010
Сообщений: 213
|
|
| 08.02.2011, 16:32 | |
|
ResourceBundle + все в файлы вынести.
0
|
|
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 09.02.2011, 09:54 [ТС] | |
|
А если язык надо менять в процессе работы программы, когда все визуальные компоненты уже созданы?
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|||||||||||
| 09.02.2011, 12:52 | |||||||||||
|
Если стоит требование смены языка во время работы программы, придется работать с look & feel. А именно, есть два пути:
1. Написать look & feel warpper, который будет почти все операции делегировать тому look & feel, который в нем завернут, но переопределит методы, отвечающие за прорисовку, в UI всех компонентов, где возможно появление текста. В переопределенных методах использовать заданный пользователем текст в качестве ключа, а отображать то, что будет по этому ключу вынуто из ResourceBundle. В таком случае можно будет использовать произвольный look & feel и при этом останется возможность 'перелокализации' на лету. 2. Написать subclass какого-нибудь look & feel, опять же переопределив методы, рисующие компонент. Первый подход мне нравится больше, но он требует некоторой дополнительной проработки, поэтому приведу пример использования второго подхода. В BasicLabelUI.java имеем:
0
|
|||||||||||
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 09.02.2011, 15:52 [ТС] | |
|
Проще написать для каждой компоненты с текстом потомка, реализующего интерфейс Languageable (или что-то типа того)
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 09.02.2011, 18:51 | |
|
А еще проще - вообще ничего не менять
На самом деле в каких-то случаях действительно такой подход с натяжкой сработает, но сложности возникнут в следующих ситуациях:1. Стандартная библиотека содержит композитные компоненты, типа FileChooser или диалогов, которые показывает JOptionPane. В них во всех уже используются JButton. Конечно, там все без проблем кастомизируется, но эту кастомизацию нужно будет каждый раз кодировать, т.к. localization framework, построенный на наследовании, таких случаев не покрывает. 2. Заголовки JTable. Опять же можно все лопатить ручками, но геморно и ясность кода страдает. 3. Любые библиотечные компоненты, начиная с какого-нибудь календарика, не будут работать с локализацией на базе subclassing. Наверное, вы там пользуетесь библиотеками? ![]() Ну и наконец, если вам просто написать подклассы для нескольких визуальных компонентов, то почему вместо этого не написать такое же количество подклассов для UI тех же самых компонентов?
0
|
|
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 10.02.2011, 10:12 [ТС] | |
|
Логично
![]() Однако и тут гемора достаточно. Как я понял, работать это будет следующим образом - компоненте в качестве текста дается определенный ключ, а ее UI по этому ключу извлекает нужный текст из базы данных и прорисовывает его. Если значения, соответствующего данному ключу, в базе нет, значит ключ и есть текст (чтобы не забивать базу данными, которые в любом используемом программой языке выглядят одинаково - например, цифры). Однако остаются две проблемы. Первая - как после изменения языка перерисовать все видимые компонеты и вторая - скорость прорисовки. Если изменять компонеты, скорость прорисовки остается прежней, поскольку каждый компонет знает свой текст, который при изменении языка меняется всего один раз. Если же изенять UI компонет, то текст прийдется извлекать из базы данных при каждой прорисовке.
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
||||||
| 10.02.2011, 15:18 | ||||||
|
Первая проблема - перерисовать весь GUI:
1. Каждый UI содержит map, где хранит все переводы, уже выбиравшиеся из БД Эти map сбрасываются тем же методом, который меняет язык GUI.Для текстов, не имеющих переводов, в map в качестве перевода кладется тот же самый текст. 2. Каждый компонент хранит свои значения. 2.1. Делаем класс, который управляет переключением языков. В нем статическая переменная - счетчик переключений языка. 2.2. Класс JComponent имеет методы putClientProperty/getClientProperty. Каждый компонент, который попадает в руки нашего UI, получает три свойства: исходный текст, перевод, текущее значение счетчика переключений языка. 2.3. UI, начиная обрабатывать компонент, проверяет 2.3.1. getClientProperty('text').equals(getText ); 2.3.2. getClientProperty('lang_switch_cnt').equ als(LangController.switchCnt); Если оба условия дают true, значение свойства 'перевод' актуально. В противном случае все свойства переприсваиваются. Каждый из подходов имеет очевидные сильные/слабые стороны, но оба существенно быстрее, чем выборка из БД. Тут, правда, нужно не забыть, что есть еще tooltips.
0
|
||||||
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 10.02.2011, 18:06 [ТС] | |
|
А если нужно LookAndFeel поменять?
))
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 10.02.2011, 18:21 | |
|
В моем исходном посте в качестве решения №1 значится 'написать look&feel wrapper'. Это будет работать равно при смене языка и нижележащего look&feel. Правда, усилий потребует немного больше, но не кардинально :0
0
|
|
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 10.02.2011, 19:46 [ТС] | |
|
А пару строчек кода можно?
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 13.02.2011, 08:23 | |
|
Ну, блин... Хорошо, наковыряю на досуге.
0
|
|
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 13.02.2011, 09:06 [ТС] | |
|
Все-таки, вариант с LookAndFeel не совсем хорош. Он работает только со стандартными свойствами компонент (setText(), setToolTipText(), setTitle(), setPage() и т.д.). Зачастую же бывает необходимо поменять другой параметр. Например, у нас есть таблица. Заносить в базу данных текст каждой ячейки? Гораздо удобнее передать таблице ссылку на какой-либо файл, пусть она на его основе меняет свое содержимое. Как реализовать это через LookAndFeel?
По-моему, нужно действовать через наследование компонет. Либо комбинировать наследование с LookAndFeel.
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 13.02.2011, 10:54 | |
|
Пример с таблицей мне не вполне понятен, потому что здесь выбор наиболее удобного варианта зависит от природы источника данных. Но в общем можно сказать, что контент таблицы действительно нужно переводить, оседлав каким-то образом ее модель. Как седлать и как переводить - зависит, как уже говорилось, от обстоятельств.
На самом деле, под термином 'локализация' сосуществуют две отдельные проблемы: локализация GUI и контента. Здесь обсуждалась локализация GUI. А впрочем, я никого за уши в светлое завтра не тяну )
0
|
|
|
3 / 3 / 7
Регистрация: 19.10.2009
Сообщений: 225
|
|
| 14.02.2011, 09:04 [ТС] | |
|
Дмитрий, если не лень, подключитесь ко мне по ICQ - 82347216 мой номер.
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 15.02.2011, 08:11 | |
|
Обещанная пара строчек кода. Это Look&Feel wrapper, который локализует JLabels. Каждый файл буду отправлять отдельным постом.
Просьба не расчитывать на то, что в присланном материале нет багов (по крайней мере один точно есть, с определением preferred size).
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 15.02.2011, 08:12 | |
|
[code]
package ru.podolsk.pryadm.localization; import javax.swing.*; import java.awt.Component; import java.awt.Frame; import java.util.*; /** */ public class TranslatingLookAndFeel extends LookAndFeel { public final static String PROP_LABEL_KEY = 'label_key'; public final static String PROP_LABEL_TEXT = 'label_text'; public final static String PROP_CHANGE_COUNT = 'change_count'; private UIDefaults uiDefaults; public String getName() { return underlyingLaF.getName(); } public String getID() { return underlyingLaF.getID(); } public String getDescription() { return underlyingLaF.getDescription(); } public boolean isNativeLookAndFeel() { return underlyingLaF.isNativeLookAndFeel(); } public boolean isSupportedLookAndFeel() { return underlyingLaF.isSupportedLookAndFeel(); } public void initialize() { uiDefaults = underlyingLaF.getDefaults(); // String labelUI = TranslatingLabelUI.class.getName(); uiDefaults.put('LabelUI', labelUI); } public UIDefaults getDefaults() { return uiDefaults; } public void provideErrorFeedback(Component component) { underlyingLaF.provideErrorFeedback(compo nent); } public boolean getSupportsWindowDecorations() { return underlyingLaF.getSupportsWindowDecoratio ns(); } public void uninitialize() { underlyingLaF.uninitialize(); } /////////////////////////////////////////////////////////////////////////////////// private static Locale locale; private static Translator translator; private static Set frames = new HashSet(); private static LookAndFeel underlyingLaF; private static Long changeCnt = new Long(0); static { ResourceBundleTranslator trans = new ResourceBundleTranslator(); trans.setResourceBundleName('translation s'); locale = Locale.ENGLISH; trans.setLocale(locale); setTranslator(trans); } public static Long getChangeCount() { return changeCnt; } public static synchronized void addFrame(JFrame frame) { frames.add(frame); } public static synchronized void removeFrame(JFrame frame) { frames.remove(frame); } public static synchronized Translator getTranslator() { return translator; } public static synchronized void setTranslator(Translator argTranslator) { updateChangeCnt(); translator = argTranslator; if (locale != null) { translator.setLocale(locale); updateUI(); } } public static synchronized void setLocale(Locale argLocale) { updateChangeCnt(); locale = argLocale; if (translator != null) { translator.setLocale(locale); updateUI(); } } public static synchronized Locale getLocale() { return locale; } public static synchronized void setUnderlyingLookAndFeel(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException { updateChangeCnt(); if (underlyingLaF != null) { underlyingLaF.uninitialize(); } underlyingLaF = (LookAndFeel) Class.forName(className).newInstance(); underlyingLaF.initialize(); try {
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
|
| 15.02.2011, 08:12 | |
|
[code]
package ru.podolsk.pryadm.localization; import javax.accessibility.Accessible; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.LabelUI; import javax.swing.table.TableCellRenderer; import java.awt.Dimension; import java.awt.Graphics; /** */ public class TranslatingLabelUI extends LabelUI { private LabelUI underlyingUI; public static ComponentUI createUI(JComponent c) { TranslatingLabelUI ui = new TranslatingLabelUI(); return ui; } public void installUI(JComponent c) { init(c); underlyingUI.installUI(c); } public void uninstallUI(JComponent c) { init(c); underlyingUI.uninstallUI(c); } public void paint(Graphics g, JComponent c) { init(c); checkLabels(c); underlyingUI.paint(g, c); } public void update(Graphics g, JComponent c) { init(c); checkLabels(c); underlyingUI.update(g, c); } public Dimension getPreferredSize(JComponent c) { init(c); return underlyingUI.getPreferredSize(c); } public Dimension getMinimumSize(JComponent c) { init(c); return underlyingUI.getMinimumSize(c); } public Dimension getMaximumSize(JComponent c) { init(c); return underlyingUI.getMaximumSize(c); } public boolean contains(JComponent c, int x, int y) { init(c); return underlyingUI.contains(c, x, y); } public int getAccessibleChildrenCount(JComponent c) { init(c); return underlyingUI.getAccessibleChildrenCount( c); } public Accessible getAccessibleChild(JComponent c, int i) { init(c); return underlyingUI.getAccessibleChild(c, i); } private void init(JComponent c) { Long changeCountShouldBe = (Long) c.getClientProperty(TranslatingLookAndFe el.PROP_CHANGE_COUNT); Long changeCountActual = TranslatingLookAndFeel.getChangeCount(); if (changeCountShouldBe == null || ! changeCountActual.equals(changeCountShou ldBe)) { underlyingUI = (LabelUI) TranslatingLookAndFeel.getUnderlyingLook AndFeel().getDefaults().getUI(c); } } private void checkLabels(JComponent c) { String key = (String) c.getClientProperty(TranslatingLookAndFe el.PROP_LABEL_KEY); String labelShouldBe = (String) c.getClientProperty(TranslatingLookAndFe el.PROP_LABEL_TEXT); String labelActual = ((JLabel)c).getText(); Long changeCountShouldBe = (Long) c.getClientProperty(TranslatingLookAndFe el.PROP_CHANGE_COUNT); Long changeCountActual = TranslatingLookAndFeel.getChangeCount(); // if (labelActual != null && !labelActual.equals('') && !(c instanceof TableCellRenderer)) { if (! labelActual.equals(labelShouldBe)) { key = labelActual; labelShouldBe = TranslatingLookAndFeel.getTranslator().t ranslate(key); labelActual = labelShouldBe; changeCountShouldBe = changeCountActual; // c.putClientProperty(TranslatingLookAndFe el.PROP_LABEL_KEY, key); c.putClientProperty(TranslatingLookAndFe el.PROP_LABEL_TEXT, labelShouldBe); c.putClientProperty(TranslatingLookAndFe el.PROP_CHANGE_COUNT, changeCountShouldBe); ((JLabel)c).setText(labelActual); } else if (! changeCountActual.
0
|
|
|
1 / 1 / 2
Регистрация: 07.01.2010
Сообщений: 128
|
||||||
| 15.02.2011, 08:13 | ||||||
0
|
||||||
| 15.02.2011, 08:13 | |
|
Помогаю со студенческими работами здесь
20
Подскажите необходимы паттерны (Шаблоны проектирования) необходимые для решения задачи
Шаблоны проектирования Шаблоны проектирования Шаблоны проектирования Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y
Z4Tv2zpXVVo
https:/ / github. com/ shumilovas/ med2. git
|
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа.
В качестве фильтра для отбора справочника служит группа номенклатуры.
Отбор по наименованию группы. . .
|
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
|
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс.
Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
|
|
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа.
В качестве фильтра для отбора служит значение перечислений.
/ / Событие "НачалоВыбора" реквизита на форме. . .
|
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
|
Оттенки серого
Argus19 18.03.2026
Оттенки серого
Нашёл в интернете 3 прекрасных модуля:
Модуль класса открытия диалога открытия/ сохранения файла на Win32 API;
Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
|
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога
Финальные проекты на Си и на C++:
finish-rectangles-sdl3-c. zip
finish-rectangles-sdl3-cpp. zip
|