Cодержание
Программирование приложения Java Desktop с использованием SWT
View more Tutorials:
Статья основана на:
-
Eclipse 4.6, 47 (NEON, OXYGEN)
В данной статье я ознакомлю вас с программированием приложения Desktop с SWT.
Вопросом является, есть ли в Java способ выбора технологии для программирования приложения Desktop, или какая технология помогает программировать веб приложение с интерфейсом похожим на приложение Desktop.
Смотрите так же:
RCP (Rich Client Platform) - Это платформа (Platform) разработанная на основе SWT, используется для программирования приложений Desktop и еще дальше он построил для вас платформу, позволяющую вас разрабатывать приложения Desktop вида Workbench, похоже на Eclipse IDE, или программировать Plugin которые могут интегрировать в Eclipse IDE.
Но даже если вы хотите использовать только SWT для программирования не использовать то, что предоставлено RCP-ом вам так же нужно создать приложение RCP.
Но даже если вы хотите использовать только SWT для программирования не использовать то, что предоставлено RCP-ом вам так же нужно создать приложение RCP.

SWT:

Workbench Application:

Чтобы создать приложение Desktop используя SWT. В Eclipse мы создадим RCP Plugin project. У вас есть 2 варианта.
- Использовать только свойства SWT
- Использовать платформу предоставленную RCP для программирования приложения RCP Workbench.

В данной статье я покажу вам как ознакомиться с программированием стандартного SWT, используя WindowBuilder чтобы перетаскивать компоненты в интерфейс.
Есть необходимые настройки, которые нужно сделать перед тем, как начать:
Вам нужно иметь Eclipse самой новой версии. Сейчас это Eclipse 4.7 (Код OXYGEN).
Вам нужно иметь Eclipse самой новой версии. Сейчас это Eclipse 4.7 (Код OXYGEN).
По-моему вам нужно скачать пакет: "Eclipse IDE for Java EE Developers". Пакеты отличаются колличеством Plugin, для разных целей программирования. В процессе программирования можно установить дополнительно Plugin для других целей.

Установка Plugin WindowBuilder, это 1 Plugin позволяющий вас сделать интерфейс дизайна приложения SWT с помощью перетаскивания, очень удобно.
Смотрите инструкцию установки по ссылке:
Смотрите инструкцию установки по ссылке:

Класс Display и Shell являются ключевыми компонентами приложения SWT.
- org.eclipse.swt.widgets.Shell описывает окно (Window)
- org.eclipse.swt.widgets.Display отвечает за управление цикла события (event loops), шрифт, цвет и контролирует информацию коммуникации между потоками интерфкйса пользователя (UI Thread) и другими потоками (other Thread). Display это основа для всех способностей свойств SWT.
Каждое приложение SWT требует минимум один Display и один или более объектов Shell.
- org.eclipse.swt.widgets.Shell описывает окно (Window)
- org.eclipse.swt.widgets.Display отвечает за управление цикла события (event loops), шрифт, цвет и контролирует информацию коммуникации между потоками интерфкйса пользователя (UI Thread) и другими потоками (other Thread). Display это основа для всех способностей свойств SWT.
Каждое приложение SWT требует минимум один Display и один или более объектов Shell.
Пример:
Display display = new Display(); Shell shell = new Shell(display); shell.open(); // run the event loop as long as the window is open while (!shell.isDisposed()) { // read the next OS event queue and transfer it to a SWT event if (!display.readAndDispatch()) { // if there are currently no other OS event to process // sleep until the next OS event is available display.sleep(); } } // disposes all associated windows and their components display.dispose();
SWT widget установлены в пакетах org.eclipse.swt.widgets и org.eclipse.swt.custom. Этом widget расширен из класса Widget или Control. Некоторые widget иллюстрированы в изображении ниже.
Детали вы можете просмотреть в SWT widget homepage.

В Eclipse выбрать:
- File/New/Other...


- Так как нет надобности создать приложение Workbench поэтому мы не выбираем (1) как в изображении ниже.
- Выбрать Yes в области (2) чтобы Eclipse создал RCP Application (Работающий на Desktop), напротив он создаст RAP Application (Работающий на Web).


Project создан:

Добавить библиотеку swt: org.eclipse.swt
Если вы программируете приложение RAP, соответствующей библиотекой является org.eclipse.rap.rwt



Это простой пример, не используя инструмент перетаскивания WindowBuilder.
HelloSWT.java
package org.o7planning.tutorial.swt.helloswt; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class HelloSWT { public static void main(String[] args) { // Create Display Display display = new Display(); // Create Shell (Window) from diplay Shell shell = new Shell(display); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } }
Нажмите на правую кнопку мыши на HelloSWT.java и выберите Run As/Java Application.

Результаты запуска примера:

Далее, мы создадим пример с перетаскиванием на WindowBuilder.
- File/New/Other ..



Это окно дизайна в WindowBuilder. Оно позволяет вам легко перетаскивать Widget.

You can watch the video below:
Это иерарзия Widget в SWT.

Вы можете посмотреть демо (demo) про Control по ссылке ниже, это RWT Control, но на самом деле они похожи на SWT control.
Demo:


Проще говоря, Layout это способ распорядка компонентов на интерфейсе.

Стандартные Layout в SWT это:
- FillLayout – Выравнивает размер Widget в строке или столбце
- RowLayout – Связывает Widget в строке или заполненной строке (Fill), обернутой (Wrap), и с вариантами пробела (space).
- GridLayout – Связывает Widget в сети
Это пример онлайн, позволяющий вам увидеть действия Layout.

- TODO Link?
FillLayout это простой класс layout. н расставляет виджет (Widget) в одной строке или столбце, заставляя их иметь один размер. Сначала Widget иметь высоту как самый высокий Widget, и широту как самый широкий widget. FillLayout не wrap (обертывает) Widget, и вы не можете определить грань (margin) или расстояние (space).
FillLayout fillLayout = new FillLayout(); fillLayout.type = SWT.VERTICAL; shell.setLayout(fillLayout);
Сначала | После изменения размера | |
fillLayout.type = SWT.HORIZONTAL (Mặc định) | ![]() | ![]() |
fillLayout.type = SWT.VERTICAL | ![]() | ![]() |
Video:
FillLayoutExample.java
package org.o7planning.tutorial.swt.layout; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class FillLayoutExample { public static void main(String[] args) { Display display = new Display(); final Shell shell = new Shell(display); shell.setLayout(new FillLayout()); // Composite parent = new Composite(shell, SWT.NONE); FillLayout fillLayout= new FillLayout(); fillLayout.type= SWT.VERTICAL; parent.setLayout(fillLayout); Button b1 = new Button(parent, SWT.NONE); b1.setText("B1"); Button b2 = new Button(parent, SWT.NONE); b2.setText("B2"); Button button3 = new Button(parent, SWT.NONE); button3.setText("Button 3"); // Windows back to natural size. shell.pack(); // shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } // tear down the SWT window display.dispose(); } }
Результаты запуска примера:

RowLayout используются больше чем FillLayout так как он имеет способность wrap (обертывать), и потому что он поддерживает margin и spacing. RowLayout имеет некоторые поля (field) конфигурации. Помимо этого, высота и ширина каждого widget в каждом RowLayout может быть определен созданием объекта RowData для widget используя setLayoutData
The field configuration:
Wrap, Pack, Justify:
Сначала | После изменения размера | |
wrap = true pack = true justify = false (По умолчанию) | ![]() | ![]() |
wrap = false (Немного отрезан если не хватает пространства) | ![]() | ![]() |
pack = false (Все Widget имеют одинаковый размер) | ![]() | ![]() |
justify = true (Widget будут распространены на готовом пространстве и поровну) | ![]() | ![]() |
MarginLeft, MarginTop, MarginRight, MarginBottom, Spacing:
Поля (field) контролирующие пиксели (Pixel) между widget (space - расстояние) и количество пикселей между widget и стороной родительского Composite (margin - грань). По умолчанию, RowLayout использует 3 Pixel для выравнивания (margin) и интервалом (space). Смотрите детали в следующем изображении.

Video:
GridLayout это самый полезный и сильный в стандартных Layout, но так же являеся самым сложным. С GridLayout, дочерний Widget одного Composite будет расставлен в сетке. GridLayout имеет некоторые конфигурационные поля, и так же как RowLayout, Widget расположенные в GridLayout могут иметь связанный объект данных Layout, так же называется GridData. Сила GridLayout находится в способности конфигурации GridData для каждого widget управляемый с помощью GridLayout.
Конфигурации GridLayout:
- NumColumns

- MakeColumnsEqualWidth

Video GridLayout:
StackLayout расставляет все Widget в стопку, они будут иметь одинаковый размер и местоположение. Поле topControl определяет какой Widget находится в самом верху и видно. Пользователь должен настроить значение topControl и потом вызвать метод layout() родительского Composite.

Video StackLayout:
Выше мы ознакомились со стандартными Layout, и сочетаниями разных Layout, и разными контейнерами (Container) (Composite, TabFolder, SashForm,.. ) которые создают желаемый интерфейс.
- TODO
Иногда вам нжуно написать расширенный класс из класса widget готовый в SWT. Это совершенно нормально, но есть маленькое примечание, вам нужно переопределить метод checkSubclass() ничего не делая в том методе.
MyButton.java
package org.o7planning.tutorial.swt.swtsubclass; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; public class MyButton extends Button { public MyButton(Composite parent, int style) { super(parent, style); } // You have to override this method. @Override protected void checkSubclass() { // No need to do anything. } }
В случае, когда вам нужно сделать дизайн сложного интерфейса. Разделение дизайна это необходимо и потом соединить их снова, с дизайном на WindowBuilder это становится легче.
Посмотрим следующий интерфейс, мы попытаемся разделить его.
Посмотрим следующий интерфейс, мы попытаемся разделить его.
Предположим, вы хотите сделать дизайн похожим на изображение ниже. (Он сложный и нужно разделить дизайн, но это иллюстрация примера разделения дизайна интерфейса)

Мы можем сделать дизайн 2-х отдельных Composite и соединить их на MainComposite.

TopComposite
- File/New/Other...


Дизайн интерфейса для TopComposite.

TopComposite.java
package org.o7planning.tutorial.swt.module; import org.eclipse.swt.widgets.Composite; public class TopComposite extends Composite { private Text text; /** * Create the composite. * @param parent * @param style */ public TopComposite(Composite parent, int style) { super(parent, style); setLayout(new FillLayout(SWT.HORIZONTAL)); Composite composite = new Composite(this, SWT.NONE); composite.setLayout(new GridLayout(1, false)); Button btnPreferredSite = new Button(composite, SWT.CHECK); btnPreferredSite.setText("Preferred Site"); Label lblColumnWidth = new Label(composite, SWT.NONE); lblColumnWidth.setText("Column width"); text = new Text(composite, SWT.BORDER); text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); } @Override protected void checkSubclass() { } }
BottomComposite
Индентично создайте класс BottomComposite:

Дизайн интерфейса для BottomComposite:

BottomComposite.java
package org.o7planning.tutorial.swt.module; import org.eclipse.swt.SWT; public class BottomComposite extends Composite { private Text text; /** * Create the composite. * @param parent * @param style */ public BottomComposite(Composite parent, int style) { super(parent, style); setLayout(new FillLayout(SWT.HORIZONTAL)); Composite composite = new Composite(this, SWT.NONE); composite.setLayout(new GridLayout(1, false)); Composite composite_1 = new Composite(composite, SWT.NONE); GridLayout gl_composite_1 = new GridLayout(3, false); gl_composite_1.marginHeight = 0; gl_composite_1.marginWidth = 0; composite_1.setLayout(gl_composite_1); composite_1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); Button btnNewButton = new Button(composite_1, SWT.NONE); btnNewButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); btnNewButton.setText("Add"); Button btnNewButton_1 = new Button(composite_1, SWT.NONE); btnNewButton_1.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); btnNewButton_1.setText("Delete"); Button btnNewButton_2 = new Button(composite_1, SWT.NONE); btnNewButton_2.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); btnNewButton_2.setText("Clear"); text = new Text(composite, SWT.BORDER | SWT.MULTI); text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); } @Override protected void checkSubclass() { // Disable the check that prevents subclassing of SWT components } }
MainComposite
Индентично создайте класс MainComposite:

Регистрация TopComposite & BottomComposite на Palette
Нажмите на правую кнопку мыши на Palette и выберите Add category...

Назовите Pallete Category:
- My Composite


Нажмите на правую кнопку мыши на "My Composite" чтобы добавить TopComposite & BottomComposite.




Индентично добавьте BottomComposite в каталог My Composite.

Теперь TopComposite & BottomComposite могут быть легко перетащены в другие Composite.
MainComposite.java
package org.o7planning.tutorial.swt.module; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; public class MainComposite extends Composite { /** * Create the composite. * @param parent * @param style */ public MainComposite(Composite parent, int style) { super(parent, style); setLayout(new FillLayout(SWT.HORIZONTAL)); Composite composite = new Composite(this, SWT.NONE); composite.setLayout(new GridLayout(1, false)); TopComposite topComposite = new TopComposite(composite, SWT.BORDER); topComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); BottomComposite bottomComposite = new BottomComposite(composite, SWT.BORDER); bottomComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); } @Override protected void checkSubclass() { } }
Обработка события SWT является очень простой с поддержкой WindowBuilder.
Иллюстрированные примеры:
- File/New/Other...

- Package: org.o7planning.tutorial.swt.event1
- Name: ButtonEventDemo


Кликнете правой кнопкой мыши на Button, выберите "Add event handler", отобразится серия событий соответствующие с Button.

WindowBuilder автоматически создает для вас code:
btnClickToMe.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // Sử lý sự kiện Button được chọn tại đây. System.out.println("Button selected!"); } });
ButtonEventDemo.java
package org.o7planning.tutorial.swt.event1; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class ButtonEventDemo { protected Shell shlButtonEventDemo; public static void main(String[] args) { try { ButtonEventDemo window = new ButtonEventDemo(); window.open(); } catch (Exception e) { e.printStackTrace(); } } public void open() { Display display = Display.getDefault(); createContents(); shlButtonEventDemo.open(); shlButtonEventDemo.layout(); while (!shlButtonEventDemo.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } protected void createContents() { shlButtonEventDemo = new Shell(); shlButtonEventDemo.setSize(296, 205); shlButtonEventDemo.setText("Button Event Demo"); shlButtonEventDemo.setLayout(new RowLayout(SWT.HORIZONTAL)); Button btnClickToMe = new Button(shlButtonEventDemo, SWT.NONE); btnClickToMe.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // Handle Button selected here! System.out.println("Button selected!"); } }); btnClickToMe.setText("Click to me"); } }

Вы можете посмотреть больше про JFace, дополнительный API для SWT: