10 шагов к тому, чтобы сделать ваше приложение достойным

May 30, 2011
java swing
Share on:

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

1 – Выберите подходящий внешний вид

Время идет, версии Java обновляются, появляются новые компоненты Swing и новые возможности при создании интерфейсов Java-приложений, не меняется лишь одно – отвратительный внешний вид Swing, используемый по умолчанию. Все так же он вызывает оправданный ужас и попытку вспомнить, как давно такие интерфейсы были современными. Так было и с первым вариантом, внешним видом с именем Metal, так остается и сейчас, с используемым по умолчанию внешним видом Ocean.

Проблема состоит в том, что Sun пришлось обеспечить для Java некий независимый от платформы и ни на что не похожий внешний вид приложений, однако разработка такого вида – дело нешуточное и требует многих лет, как это и происходило с интерфейсами современных операционных систем. При создании Java и Swing этого времени не было, и приходится довольствоваться довольно быстрым вариантом, который не вызывает ощущения красоты или гармонии, да к тому же разработан он был программистами, а не дизайнерами.

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

К примеру, окно входа в систему, которое было спроектировано в книге о Swing, в стандартном внешнем виде выглядит так:

Оставим в стороне «порку» цветов, шрифтов и тому подобных деталей внешнего вида по умолчанию для художников, правда, один вопрос все равно так и срывается с языка – зачем же все надписи сделаны жирными, хотя всем известно что жирной делается та надпись, что несет в себе большую смысловую нагрузку, в сравнении с остальными. Не будем углубляться в детали, а будем считать что жирные шрифты применяются по умолчанию в силу исторических причин и совместимости с первыми версиями Swing.

Теперь, для примера, возьмем великолепный внешний вид Substance и нейтральную тему SubstanceBusinessLookAndFeel. Ссылки на его GitHub есть на сайте. Получим мы следующее:

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

Если вам захочется популярное в среде программистов “темное ощущение”, можно выбрать одну из темных тем Substance, например SubstanceGraphiteLookAndFeel:

Ну а смену внешнего вида лучше всего провести еще до того, как будет создан какой-либо компонент Swing, чтобы избежать ненужной работы. Делается это простым вызовом в классе UIManager:

UIManager.setLookAndFeel(new org.pushingpixels.substance.api.skin.SubstanceBusinessLookAndFeel());

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

-Dswing.defaultlaf=<имя класса внешнего вида>

К подобранному внешнему виду нелишне также подобрать и значки, цвета и стиль сообщений, если они содержат цветной текст или разные шрифты. Хороший дизайнер (который с программистом в одном флаконе сочетается редко) здесь будет весьма кстати. Для полноты картины вы также можете отключить системные заголовки окон и использовать внешний вид окон из выбранного вами внешнего вида Swing, именнjavaо так мы и поступили в примерах здесь, это тоже просто:

JDialog.setDefaultLookAndFeelDecorated(true);
JFrame.setDefaultLookAndFeelDecorated(true);

2 – Соблюдайте рекомендации для своего внешнего вида

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

Начать можно с изучения рекомендаций для интерфейсов от Microsoft и Apple, а в книге мы кратко просмотрели что рекомендует Sun для интерфейсов, написанных с применением внешнего вида Ocean, применяемого по умолчанию в приложениях Swing. Даже следуя этим нехитрым советам, вы многократно увеличите гармонию во внешнем виде своего приложения.

Самый простой способ следовать рекомендациям – применять менеджер расположения, который автоматически вставляет между компонентами рекомендованные расстояния – к примеру, GroupLayout (даже с помощью визуального дизайнера NetBeans Matisse) или MigLayout, или вручную пользоваться классам LayoutStyle, который сообщает эти расстояния. Все это мы затрагивали во втором издании книги.

3 – Удостоверьтесь в отзывчивости интерфейса

Неакуратно скроенное Swing-приложение сразу легко заметить по подвисающему и вовремя не перерисовывающемуся интерфейсу, когда так и хочется в бешенстве молотить по клавишам Control-Alt-Del. Это верный признак выполнения тяжелых вычислений в потоке рассылки графических событий, который является единственным двигателем событий от пользователя к приложению. Загружать его любой работой кроме обновления экрана совершенно недопустимо.

При создании приложений Swing действуйте по следующим простым правилам:

Помочь лучше структурировать код и не загромождать его витиеватыми вызовами Runnable/SwingUtilities.invokeLater() сможет прекрасно известный инструмент SwingWorker. Не забывайте, что выполнение задач в параллельных потоках означает работу в многозадачном окружении, где стоит заботиться не только о синхронизации, но и о проблемах чрезмерного разрастания количества потоков. Вы можете прочитать мою заметку об управлении SwingWorker, где мы частично решаем эти проблемы.

4 – Обеспечьте доступ с клавиатуры

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

Пока не придумано ничего более ускоряющего работу, чем клавиатурные сокращения. Классические Control-S чтобы сохранить работу, Control-C чтобы скопировать выделенные данные и многое другое экономят уйму времени. Чем важнее действие, тем быстрее оно должно исполняться на клавиатуре (выбирайте рядом стоящие клавиши).

Реализация клавиатурных сокращений в Swing проста, расширяема, легко меняется через файлы настроек или свойств, и встроена в базовый класс JComponent. Все происходит через карты входных событий (InputMap) и реакций на них (ActionMap). В карту входных событий вы кладете объект, описывающий клавиатурное сокращение (KeyStroke) и указываете, в каком случае оно работает – когда компонент владеет фокусом или в более общем случае. В карте реакций будет хранится действие Action, которое исполняется в случае нажатия нужного сочетания клавиш. Действия Action великолепно применяются многократно в системе меню, панелях инструментов, обычных компонентах и клавиатурных сокращениях, так что вам не придется писать одно и то же много раз.

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

5 – Включите поддержку Drag’n’Drop

С выходом Java 6 и появлением в компонентах Swing такого элементарного метода как setDragEnabled() и вспомогательного классаTransferHandler жизнь стала прекрасна как никогда и встроить поддержку технологии Drag’n’Drop стало очень просто. Достаточно просто включить ее и определить что же будет выдавать компонент когда пользователь что-то «вытаскивает» и куда он будет определять новые данные когда пользователь «бросает» что-то на него.

Сама философия Drag’n’Drop очень естественна для людей, однако как правило быстрее все сделать на клавиатуре, если приложение профессиональное и не терпит никаких временных задержек. Нельзя сказать чтобы манипуляторы (мыши и тачпады, как правило) отличались хорошим разрешением, да и наши руки неточно передают желание попасть в точку на экран. Однако для визуальных конструкторов из достаточно крупных блоков данная технология подходит как нельзя кстати.

Впрочем, включайте ее всегда – это красиво и украшает скучный быт, даже если работа намного быстрее выполняется с клавиатуры. Ваше приложение в любом случае получит жирный плюс, а работа по включению Drag’n’Drop в Swing совсем не сложна. Детали мы рассматривали в последней главе второго издания книги.

6 – Подсказывайте везде где только можно

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

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

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

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

Если места нет, используйте многоуровневую панель и компонент JXLayer для организации интерактивной, появляющейся и исчезающей по желанию пользователя, помощи и подсказки.

7 – Побольше эффектов и анимации с Java2D и J(X)Layer

Деловые приложения, рассчитаные на работу с данными предприятий и учитываюшие специфику их работы, бывают довольно скучны. И хотя сам факт того, что приложение удобно и позволяет намного ускорить производственные процессы, является самым привлекательным в нем для пользователей, факт остается фактом – люди любят красоту и наслаждаются анимацией и красивыми цветами. Опять же вспомним продукций компании Apple, которая может во многом не блистать новейшими функциями, но привлекает внимание своим отточенным внешним видом и приятными эффектами.

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

При встраивании графических эффектов необходимо четко понимать процесс рисования в Swing. Второе издание сделало на этом особый упор, и мы обсуждаем процесс рисования в отдельной главе, касаясь всех его аспектов, однако по умолчанию все рисование происходит в пределах одного компонента. Использование прозрачной панели (glass pane) как правило малоперспективно, а layered pane ограничивает ваши возможности по встраиванию спецэффектов, так как не предназначена для динамически меняющих свои размеры интерфейсов. Здесь на передний план выступает компонент JXLayer, способный разместить в себе ваш интерфейс и при этом дать вам возможность покуражиться над его внешним видом. Мы также кратко описали возможности JXLayer во втором издании.

8 – Копирование и вставка

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

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

9 – Обеспечьте путь к отступлению (Undo/Redo)

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

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

К сожалению, нельзя сказать чтобы Swing обеспечивал нам встроенную мощную систему отката изменений (undo/redo). Есть базовые классы для хранения истории изменений и их манипуляции (все это можно видеть в классе javax.swing.undo), однако ничем конкретным они нам не помогут, по сути это достаточно простые контейнеры специализированных данных. Только лишь текстовые компоненты обладают некоторым уровнем отката изменений по умолчанию.

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

10 – Мгновенная реакция на изменения

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

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

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

Еще более дружественно предоставлять некий промежуточный результат вычислений, который хотя бы примерно показывает будущий конечный результат. Как только данные будут готовы или операция завершится, его можно плавно заменить на настоящий, используя при этом какие-нибудь графические эффекты, плавное проявление, полупрозрачнось и так далее. Даже приложение с большим временем задержки на любую операцию (latency) может быть очень дружественным, используя подобные техники – и таким образом намного улучшить намного более важную для пользователей характеристику системы – незамедлительное время ответа, хотя бы визуальное (responsiveness).

И – Правильно распределите пространство

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

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

Однако в большинстве случаев проблема места на экране требует творческого подхода и не решается использованием нескольких дополнительных панелей и прокрутки. Как правило, стоит заново обдумать принцип расположения компонентов на экране и их функциональную нагрузку, прежде чем решать разместить их во вкладках или панели прокрутки. Однотипные данные лучше всего разместить в таблицах, вместо списков или текстовых полей – они покажут такие данные более компактно. Вместо больших обычных кнопок JButton можно применить панели инструментов. Наконец, часть менее значимых частей интерфейса можно скрыть в сворачиваемых панелях (есть множество реализаций, к примеру, в библиотеке SwingX - JXCollapsiblePane), и скрыть их по умолчанию. Пользователь сможет открыть их в случае необходимости, ну а в большинстве случаев это не понадобится и освободит немало места.

Итоги

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