Lập trình ứng dụng Java Desktop sử dụng SWT
1. Giới thiệu
Tài liệu này được viết dựa trên:
Eclipse 4.6, 47 (NEON, OXYGEN)
Trong tài liệu hướng dẫn này tôi sẽ giới thiệu với các bạn về lập trình ứng dụng Desktop với SWT.
Câu hỏi là trong Java có các cách lựa chọn công nghệ nào để lập trình ứng dụng Desktop, hoặc công nghệ nào giúp lập trình một ứng dụng web có giao diện giống ứng dụng Desktop.
Xem thêm:
2. RCP (Rich Client Platform)
RCP (Rich Client Platform) - Là một nền tảng (Platform) xây dựng trên SWT, dùng để lập trình các ứng các ứng dụng Desktop và xa hơn nữa nó đã xây dựng sẵn một nền tảng cho phép bạn phát triển các ứng dụng Desktop kiểu Workbench, giống với Eclipse IDE, hoặc lập trình các Plugin có thể tích hợp vào Eclipse IDE.
Tuy nhiên cho dù chỉ muốn dùng SWT để lập trình và không cần sử dụng những thứ được cung cấp bởi RCP bạn cũng nên tạo một ứng dụng RCP.
Tuy nhiên cho dù chỉ muốn dùng SWT để lập trình và không cần sử dụng những thứ được cung cấp bởi RCP bạn cũng nên tạo một ứng dụng RCP.
SWT:
Workbench Application:
Để tạo một ứng dụng Desktop sử dụng SWT. Trên Eclipse chúng ta sẽ tạo một RCP Plugin project. Bạn có 2 lựa chọn.
- Chỉ sử dụng các tính năng của SWT
- Sử dụng nền tảng cung cấp bởi RCP để lập trình ứng dụng RCP Workbench.
Trong tài liệu này tôi sẽ hướng dẫn các bạn làm quen với lập trình SWT cơ bản, sử dụng WindowBuilder để kéo thả các thành phần vào giao diện.
3. Các cài đặt cần thiết trước khi bắt đầu
Một số cài đặt cần thiết trước khi bắt đầu:
Bạn cần có Eclipse phiên bản mới nhất. Hiện tại đang là Eclipse 4.7 (Mã hiệu OXYGEN).
Bạn cần có Eclipse phiên bản mới nhất. Hiện tại đang là Eclipse 4.7 (Mã hiệu OXYGEN).
Theo tôi bạn lên download package: "Eclipse IDE for Java EE Developers". Các package chỉ khác nhau số lượng Plugin, cho các mục đích lập trình khác nhau. Trong quá trình lập trình có thể cài thêm các Plugin cho các mục đích khác.
Cài đặt Plugin WindowBuilder, đây là 1 Plugin cho phép bạn thiết kế giao diện ứng dụng SWT bằng cách kéo thả rất tiện lợi.
Xem hướng dẫn cài đặt tại:
Xem hướng dẫn cài đặt tại:
4. Một số khái niệm về SWT.
Display & Shell
Lớp Display và Shell là các thành phần khóa (key) của ứng dụng SWT.
- org.eclipse.swt.widgets.Shell mô tả một cửa sổ (Window)
- org.eclipse.swt.widgets.Display chịu trách nhiệm quản lý sự kiện lặp (event loops), phông chữ, màu sắc và kiểm soát các thông tin liên lạc giữa các tiến trình giao diện người dùng (UI Thread) và các tiến trình khác (other Thread). Display là cơ sở cho tất cả các khả năng của SWT.
Mỗi ứng dụng SWT đòi hỏi ít nhất một Display và một hoặc nhiều đối tượng Shell.
- org.eclipse.swt.widgets.Shell mô tả một cửa sổ (Window)
- org.eclipse.swt.widgets.Display chịu trách nhiệm quản lý sự kiện lặp (event loops), phông chữ, màu sắc và kiểm soát các thông tin liên lạc giữa các tiến trình giao diện người dùng (UI Thread) và các tiến trình khác (other Thread). Display là cơ sở cho tất cả các khả năng của SWT.
Mỗi ứng dụng SWT đòi hỏi ít nhất một Display và một hoặc nhiều đối tượng Shell.
Ví dụ:
Display display = new Display();
Shell shell = new Shell(display);
shell.open();
// Chạy vòng lặp sự kiện miễn là các cửa sổ đang mở
while (!shell.isDisposed()) {
// Đọc các sự kiện hàng đợi tiếp theo của hệ điều hành và chuyển nó vào một sự kiện SWT
if (!display.readAndDispatch())
{
// Nếu hiện tại không có sự kiện của hệ điều hành nào để xử lý
// Ngủ cho tới khi có sự kiện
display.sleep();
}
}
// Trường hợp người dùng đóng cửa sổ
// Hủy (dispose) cửa sổ, và tất cả các thành phần liên quan
display.dispose();
SWT Widgets
Các SWT widget được đặt tại packages org.eclipse.swt.widgets và org.eclipse.swt.custom. Các widget này được mở rộng từ lớp Widget hoặc Control. Một vài widget được mô tả tại hình minh họa dưới.
Chi tiết bạn có thể xem tại SWT widget homepage.
5. Tạo RCP Plugin Project
Trên Eclipse chọn:
- File/New/Other...
- Vì không có nhu cầu tạo một ứng dụng Workbench cho nên chúng ta không check vào (1) như hình minh họa dưới.
- Chọn Yes tại vùng (2) để Eclipse tạo ra RCP Application (Chạy trên Desktop), ngược lại nó sẽ tạo ra RAP Application (Chạy trên Web).
Project đã được tạo ra:
Thêm thư viện swt: org.eclipse.swt
Nếu bạn lập trình ứng dụng RAP, thư viện tương ứng là org.eclipse.rap.rwt
6. Ví dụ bắt đầu
Đây là ví dụ đơn giản, chưa sử dụng đến công cụ kéo thả 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) {
// Tạo đối tượng Display
Display display = new Display();
// Tạo đối tượng Shell (Window)
Shell shell = new Shell(display);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Nhấn phải chuột vào HelloSWT.java và chọn Run As/Java Application.
Kết quả chạy ví dụ:
7. Sử dụng WindowBuilder
Tiếp theo chúng ta sẽ tạo một ví dụ với việc kéo thả trên WindowBuilder.
- File/New/Other ..
Đây là cửa sổ thiết kế của WindowBuilder. Nó cho phép bạn kéo thả các Widget một cách dễ dàng.
Bạn có thể xem video dưới đây:
8. SWT Widget
Tổng quan
Đây là cây phân cấp các Widget có trong SWT.
Bạn có thể xem bản giới thiệu (demo) về các Control tại link dưới đây, đó là RWT Control, nhưng về bản chất chúng giống với SWT control.
Demo:
Widget có thể chứa các Widget khác (Container)
Các Control
9. SWT Layout
Layout là gì?
Nói một cách đơn giản Layout là cách bố trí sắp xếp các thành phần lên trên giao diện.
Các Layout chuẩn của SWT là:
- FillLayout – Làm các Widget có kích thước bằng nhau trong một hàng hoặc cột
- RowLayout – Giàng buộc các Widget trong một hàng hoặc hàng, lấp đầy (Fill), bọc (Wrap), và các tùy chọn khoảng trống (space).
- GridLayout – Giàng buộc các Widget trong một mạng lưới
Ví dụ trực tuyến
Đây là một ví dụ trực tuyến, cho phép bạn xem cách hành sử của các Layout.
- TODO Link?
FillLayout
FillLayout là lớp layout đơn giản. Nó đặt các vật dụng (Widget) trong một hàng hoặc cột, buộc chúng phải có cùng kích thước. Ban đầu, các Widget tất cả sẽ được cao như các Widget cao nhất, và rộng như widget rộng nhất. FillLayout không wrap (gói) các Widget, và bạn không thể xác định lề (margin) hoặc khoảng cách (space).
FillLayout fillLayout = new FillLayout();
fillLayout.type = SWT.VERTICAL;
shell.setLayout(fillLayout);
Ban đầu | Sau khi thay đổi kích thước | |
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");
// Làm cửa sổ trở về kích thước tự nhiên.
shell.pack();
//
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// tear down the SWT window
display.dispose();
}
}
Kết quả chạy ví dụ:
RowLayout
RowLayout được sử dụng nhiều hơn FillLayout vì nó có khả năng wrap (gói), và bởi vì nó hỗ trợ margin và spacing. RowLayout có một số trường (field) cấu hình. Ngoài ra, chiều cao và chiều rộng của mỗi widget trong một RowLayout có thể được xác định bằng cách thiết lập một đối tượng RowData cho các widget bằng cách sử dụng setLayoutData
Các trường cấu hình:
Wrap, Pack, Justify:
Ban đầu | Sau khi thay đổi kích thước | |
wrap = true pack = true justify = false (Mặc định) | ||
wrap = false (Bị xén bớt nếu không đủ không gian) | ||
pack = false (Tất cả các Widget sẽ có cùng kích thước) | ||
justify = true (Các Widget sẽ được trải ra trên các không gian có sẵn, và căn đều) |
MarginLeft, MarginTop, MarginRight, MarginBottom, Spacing:
Là các trường (field) kiểm soát số lượng điểm ảnh (Pixel) giữa các widget (space - khoảng cách) và số lượng điểm ảnh giữa một widget và một cạnh của Composite cha (margin - Lề). Theo mặc định, RowLayout sử dụng 3 Pixel cho căn lề (margin) và khoảng cách (space). Chi tiết xem hình minh họa dưới đây.
Video:
GridLayout
GridLayout là hữu ích và mạnh mẽ nhất trong các Layout tiêu chuẩn, nhưng nó cũng là phức tạp nhất. Với một GridLayout, các Widget con của một Composite được đặt trong một mạng lưới. GridLayout có một số trường cấu hình, và, giống như RowLayout, các Widget nằm trong GridLayout có thể có một đối tượng dữ liệu Layout liên quan, được gọi là GridData. Sức mạnh của GridLayout nằm trong khả năng cấu hình GridData cho mỗi widget điều khiển bởi GridLayout.
Các cấu hình của GridLayout:
- NumColumns
- MakeColumnsEqualWidth
Video GridLayout:
StackLayout
StackLayout xếp tất cả Widget thành một chồng, chúng sẽ có cùng kích thước và vị trí. Trường topControl quy định Widget nào đứng ở trên cùng và có thể được nhìn thấy. Người sử dụng phải thiết lập giá trị topControl và sau đó gọi phương thức layout() của Composite cha.
Video StackLayout:
Kết hợp các Layout
Trên kia chúng ta đã làm quen với các Layout tiêu chuẩn, và việc kết hợp các Layout khác nhau, và các bộ chứa (Container) khác nhau (Composite, TabFolder, SashForm,.. ) sẽ tạo nên các giao diện mong muốn.
- TODO
10. Viết các class mở rộng từ các widget của SWT
Đôi khi bạn có nhu cầu viết một lớp mở rộng từ một lớp widget có sẵn của SWT. Việc đó hoàn toàn bình thường, tuy nhiên có một ghi chú nhỏ, bạn cần viết đè phương thức checkSubclass() mà không cần phải làm gì trong phương thức đó.
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);
}
// Cần phải ghi đè method này.
// Vì method cha ném ra ngoại lệ
@Override
protected void checkSubclass() {
// Không cần làm gì cả.
}
}
11. Module hóa các thành phần giao diện
Trong các trường hợp bạn phải thiết kế một giao diện phức tạp. Việc chia nhỏ các thiết kế ra là cần thiết và sau đó ghép lại với nhau, với việc thiết kế trên WindowBuilder việc đó càng trở lên dễ dàng hơn.
Hãy xem một giao diện như sau, và chúng ta sẽ tìm cách chia nhỏ nó ra.
Hãy xem một giao diện như sau, và chúng ta sẽ tìm cách chia nhỏ nó ra.
Giả sử rằng bạn muốn thiết kế một giao diện giống hình minh họa dưới đây. (Nó không phức tạp để cần phải phân nhỏ thiết kế, tuy nhiên đây là ví dụ minh họa cho việc chia nhỏ thiết kế giao diện như thế nào).
Chúng ta có thể thiết kế 2 Composite riêng biệt và ghép nó lại trên MainComposite.
TopComposite
- File/New/Other...
Thiết kế giao diện cho 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
Tương tự tạo lớp BottomComposite:
Thiết kế giao diện cho 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
Tương tự tạo lớp MainComposite:
Đăng ký TopComposite & BottomComposite lên Palette
Nhấn phải chuột lên Palette và chọn Add category...
Đặt tên Pallete Category:
- My Composite
Nhấn phải chuột vào Pallette Category "My Composite" để thêm TopComposite & BottomComposite vào.
Tương tự thêm BottomComposite vào catalog My Composite.
Bây giờ TopComposite & BottomComposite dễ dàng được kéo thả vào các Composite khác.
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() {
}
}
12. Xử lý sự kiện
Xử lý sự kiện SWT rất đơn giản với sự hỗ trợ của WindowBuilder.
Các ví dụ minh họa:
- File/New/Other...
- Package: org.o7planning.tutorial.swt.event1
- Name: ButtonEventDemo
Nhấn phải chuột lên Button, chọn "Add event handler", một loạt các sự kiện tương ứng với Button hiển thị ra.
WindowBuilder sẽ tự động tạo code cho bạn:
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");
}
}
Eclipse RCP
- Các nền tảng nào bạn nên chọn để lập trình ứng dụng Java Desktop?
- Lập trình ứng dụng Java Desktop sử dụng SWT
- Hướng dẫn lập trình Eclipse RCP 4 cho người mới bắt đầu - Ứng dụng e4 Workbench
- Đóng gói và triển khai ứng dụng Desktop SWT/RCP
- Hướng dẫn lập trình Eclipse RCP 3 cho người mới bắt đầu - Ứng dụng Workbench
- Cài đặt e4 Tools Developer Resources cho Eclipse
- Ứng dụng Eclipse RCP 3 đơn giản - Tương tác View và Editor
Show More
Công nghệ của Eclipse
- Làm sao để có các thư viện mã nguồn mở Java dưới dạng OSGi
- Cài đặt Tycho cho Eclipse
- Hướng dẫn lập trình Java OSGi cho người mới bắt đầu
- Tạo dự án Java OSGi với Maven và Tycho
- Cài đặt WindowBuilder cho Eclipse
- Các nền tảng nào bạn nên chọn để lập trình ứng dụng Java Desktop?
- Lập trình ứng dụng Java Desktop sử dụng SWT
- Hướng dẫn và ví dụ Eclipse JFace
- Cài đặt e4 Tools Developer Resources cho Eclipse
- Đóng gói và triển khai ứng dụng Desktop SWT/RCP
- Cài đặt Eclipse RAP Target Platform
- Cài đặt EMF cho Eclipse
- Cài đặt RAP e4 Tooling cho Eclipse
- Tạo Eclipse RAP Widget từ ClientScripting widget
- Cài đặt GEF cho Eclipse
- Hướng dẫn lập trình Eclipse RAP cho người mới bắt đầu - Ứng dụng Workbench (trước e4)
- Hướng dẫn lập trình Eclipse RCP 3 cho người mới bắt đầu - Ứng dụng Workbench
- Ứng dụng Eclipse RCP 3 đơn giản - Tương tác View và Editor
- Hướng dẫn lập trình Eclipse RCP 4 cho người mới bắt đầu - Ứng dụng e4 Workbench
- Cài đặt RAP Tools cho Eclipse
- Hướng dẫn lập trình Eclipse RAP cho người mới bắt đầu - Ứng dụng cơ bản
- Hướng dẫn lập trình Eclipse RAP cho người mới bắt đầu - Ứng dụng e4 Workbench
- Đóng gói và triển khai ứng dụng Eclipse RAP
Show More
Các hướng dẫn lập trình Java SWT
- Hướng dẫn và ví dụ Java SWT FillLayout
- Hướng dẫn và ví dụ Java SWT RowLayout
- Hướng dẫn và ví dụ Java SWT SashForm
- Hướng dẫn và ví dụ Java SWT Label
- Hướng dẫn và ví dụ Java SWT Button
- Hướng dẫn và ví dụ Java SWT Toggle Button
- Hướng dẫn và ví dụ Java SWT Radio Button
- Hướng dẫn và ví dụ Java SWT Text
- Hướng dẫn và ví dụ Java SWT Password Field
- Hướng dẫn và ví dụ Java SWT Link
- Lập trình ứng dụng Java Desktop sử dụng SWT
- Hướng dẫn và ví dụ Java SWT Combo
- Hướng dẫn và ví dụ Java SWT Spinner
- Hướng dẫn và ví dụ Java SWT Slider
- Hướng dẫn và ví dụ Java SWT Scale
- Hướng dẫn và ví dụ Java SWT ProgressBar
- Hướng dẫn và ví dụ Java SWT TabFolder và CTabFolder
- Hướng dẫn và ví dụ Java SWT List
Show More