Professional Documents
Culture Documents
TÓM TẮT
Trong phần này sẽ hướng dẫn bạn cách tạo ra những giao diện người dùng đồ hoạ
(GUIs) với JFC/Swing cho những ứng dụng và applets thông qua việc sử dụng
những thành phần Swing. Những thành phần Swing, một bộ phận của JavaTM
Foundation Classes (JFC), có thể được sử dụng hoặc với JDKTM 1.1 hoặc JavaTM 2
platform.
Ghi chú: phần này không hướng dẫn bạn cách sử dụng những thành phần
AWT
1. Nhập môn với Swing
Trong phần này sẽ lướt qua nhanh và nhằm mục đích là cho bạn
hình dung về JFC và Swing. Sau đó sẽ là cách để biên dịch và
chạy chương trình - cho cả ứng dụng và các applets thông qua
việc sử dụng các thành phần Swing bằng một chương trình đơn
giản.
9095883.doc 1
Giáo trình Java
Sử dụng các đường vẽ, các text để chế tạo ra một hình ảnh, kể cả các hình ảnh
động.
8. Chuyển đổi thành Swing
Hướng dẫn cách chuyển đổi một chương trình sử dụng AWT API 1.1 sang chương
trình sử dụng các thành phần Swing.
Với mỗi phiên bản sử dụng, tùy thuộc vào việc chúng ta cần đến JDK 1.1 hay là Java
2 Platform và không cần phải thêm bất kỳ thư viện nào mà vẫn có thể sử dụng được
Swing API. Tuy nhiên, nếu cần sử dụng JDK 1.1 thì thêm vào Swing API (sử dụng
JFC 1.1)
Hãng Sun đã phát hành nhiều phiên bản của JFC 1.1 và để nhận biết nó là phiên bản
nào thì cần dựa vào phiên bản của Swing API chứa trong nó.
Bảng sau đây liệt kê các thông tin về Swing API.
9095883.doc 2
Giáo trình Java
Swing 1.0.3)
Phiên bản đầu tiên có đầy đủ Swing 1.1 API
hổ trợ để sử dụng các sản phầm thương mại.
JFC 1.1 Java Plug-in 1.1.2 và Java Plug-in 1.2 cung
Swing 1.1 v 1.2, v 1.2.1
(with Swing 1.1) cấp applet hổ trợ cho từng JDK 1.1 +
Swing 1.1 và Java 2 Platform v 1.2 tương
ứng.
Thêm vào các tính năng mở rộng, xữ lý
nhiều lỗi kỹ thuật, các chức năng mới (API
JFC 1.1
không cần thay đổi) cho Swing 1.1. Java
Swing 1.1.1 (with v 1.2.2
Plug-in 1.1.3 và Java Plug-in 1.2.2 cung
Swing 1.1.1)
cấp applet hổ trợ choJDK 1.1 + Swing 1.1.1
và Java 2 Platform v 1.2.2, tương ứng.
Thêm vào các tính năng, xữ lý nhiều lỗi kỹ
Không có sự thuật, các chức năng mới. Bổ sung thêm các
khác biệt về Không có v 1.3 Beta tính năng và các hàm API mới. Java Plug-in
"Swing" version 1.3 Beta cung cấp applet hổ trợ cho phiên
bản này.
9095883.doc 3
Giáo trình Java
nguồn (native code), nên chúng có thể được thêm vào như là một add-on của JDK 1.1
hay như một phần của Java 2 Platform.
Ngay cả những thành phần Swing đơn giản nhất cũng đã có những khả năng vượt xa
các thành phần AWT:
• Swing buttons và labels có thể hiển thị hình ảnh và cả văn bản.
• Có thể dễ dàng thay đổi đường viền của hầu hết các thành phần Swing. Ta có thể
dễ dàng thay đổi đường viền của một label hay một đối tượng chứa nào đó.
• Có thể dễ dàng thay đổi hành vi hay giao diện của một thành phần Swing trong
phương thức điều khiển của nó hoặc tạo ra một lớp con (subclass) của chính
thành phần đó.
• Thành phần Swing không có hình chữ nhật. Do đó, các nút lệnh có thể có hình
tròn hoặc bo góc.
• Kỹ thuật hỗ trợ (Assistive technologies) qua việc đọc màn hình có thể dể dàng
lấy thông tin từ các thành phần Swing.
2. Biên dịch và thực thi một chương trình Swing
Ðể viết một chương trình sử dụng các thành phần Swing, trước tiên, ta phải có phiên
bản của JDK và JFC tương ứng. Biên dịch và thực thi một chương trình Swing còn
tùy thuộc vào việc đang sử dụng JDK 1.1 hay Java 2 Platform. Nếu sử dụng Java 2
Platform thì sẽ đơn giản hơn vì Swing đã được tích hợp.
2.1 Biên dịch và thực thi chương trình với Java 2 Platform, v 1.2 or 1.3
Trong phần này, chúng ta sẽ khảo sát các vấn đề qua ví dụ SwingApplication.java
có giao diện như sau:
Sau đây là các bước trình tự cho việc biên dịch và thực thi một chương trình Swing
với Java 2 SDK, v 1.2 hay v 1.3:
1. Nếu chưa có, cài đặt vào máy phiên bản Java 2 Platform.
2. Tạo một chương trình sử dụng các thành phần Swing.
3. Biên dịch chương trình.
4. Cho thực thi chương trình.
9095883.doc 4
Giáo trình Java
Hiện nay, đang có 2 phiên bản của Java 2 Platform, tất cả đều miễn phí do Sun cung
cấp (bạn có thể vào địa chỉ này để được hổ trợ: http://www.sun.com). Phiên bản thứ
nhất là v 1.2 (Java 2 SDK, Standard Edition v 1.2) và phiên bản thứ hai là v 1.3 (Java
2 SDK, Standard Edition v 1.3).
Ðể tạo một chương trình sử dụng các thành phần Swing, có thể sử dụng chương trình
mẫu mà chúng tôi cung cấp sau đây SwingApplication.java. Cần lưu ý là tên file phải
chính xác là: "SwingApplication.java"
import javax.swing.*; //This is the final package name.
//import com.sun.java.swing.*; //Used by JDK 1.2 Beta 4 and all
//Swing releases before Swing 1.1 Beta 3.
import java.awt.*;
import java.awt.event.*;
/*
* An easy way to put space between a top-level container
* and its contents is to put the contents in a JPanel
* that has an "empty" border.
*/
JPanel pane = new JPanel();
pane.setBorder(BorderFactory.createEmptyBorder(
30, //top
30, //left
10, //bottom
30) //right
);
pane.setLayout(new GridLayout(0, 1));
pane.add(button);
9095883.doc 5
Giáo trình Java
pane.add(label);
return pane;
}
9095883.doc 6
Giáo trình Java
Cũng tương tự như với Java 2 Platform, nhưng trình biên dịch sử dụng ở đây là JDK
1.1 và JFC 1.1.
3. Thực thi các Swing Applets
Để viết một Swing Applets, trước tiên là phải thực thi được chúng. Phần này sẽ giới
thiệu 2 applets.
Sau đây là phần mã của applets HelloSwingApplet.java
import javax.swing.*; //This is the final package name.
//import com.sun.java.swing.*; //Used by JDK 1.2 Beta 4 and all
//Swing releases before Swing 1.1 Beta 3.
import java.awt.*;
getContentPane().add(label, BorderLayout.CENTER);
}
}
Để thực thi một Swing Applets, theo trình tự các bước sau:
(1) Đảm bảo là đã có trình duyệt 1.1 hoặc 1.2 hoặc tải về Java Plug-in và chúng
là những phiên bản mới nhất. Trường hợp không có các thứ trên, có thể sử
dụng Applet Viewer (appletviewer).
(2) Nếu bạn đang sử dụng trình duyệt 1.1 không có Java Plug-in thì cần phải
nạp file Swing JAR vào trình duyệt.
9095883.doc 7
Giáo trình Java
(3) Kiểm tra lại xem trình duyệt của bạn đã hoàn chỉnh chưa. Trong phạm vi
bài này thì hình dưới đây kiểm chứng cho trình duyệt của bạn là đã đáp ứng
hoàn hay hay chưa. Nếu trong trình duyệt của bạn xuất hiện applet như
dưới đây thì OK. Trường hợp chỉ thấy một thay vì hai applet hoặc không
thấy các hình ảnh thì trình duyệt của bạn chưa thực sự sẵn sàng.
Phần mã của SwingApplication.java thực hiện những công việc sau:
Importing Swing packages
Dòng lệnh sau sẽ import gói Swing chính:
import javax.swing.*;
Lưu ý: JFC 1.1 và Java 2 SDK v 1.2 phiên bản beta sử dụng tên gọi
khác nhau cho gói Swing.
Hầu hết các chương trình đều cần import hai gói chính của AWT là:
import java.awt.*;
import java.awt.event.*;
Choosing the look and feel
Swing cho phép bạn chỉ định rõ “look and feel” mà chương trình của bạn sử
dụng -- Java look and feel, Windows look and feel, CDE/Motif look and feel,
... Đoạn mã in đậm dưới đây sẽ chỉ ra cho bạn cách mà SwingApplication
chỉ định “look and feel”:
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getCrossPlatformLookAndFeelCl
assName());
9095883.doc 8
Giáo trình Java
} catch (Exception e) { }
9095883.doc 9
Giáo trình Java
lệnh(tức là khi người dùng nhấn Alt-i thì cùng tương tự như kích chuột vào nút
lệnh). Dòng (3) đăng ký việc nắm bắt sự kiện cho việc kích nút lệnh
Đoạn mã sau đây khởi tạo và vận hành hoạt động của label:
..//where instance variables are declared:
private static String labelPrefix = "Number of button
clicks: ";
private int numClicks = 0;
...//in GUI initialization code:
final JLabel label = new JLabel(labelPrefix + "0 ");
...
label.setLabelFor(button);
...//in the event handler for button clicks:
label.setText(labelPrefix + numClicks);
Đoạn mã trên đơn giản, ngoại trừ dòng khởi động phương thức setLabelFor().
Nó xuất hiện ở đây giống như sự gợi ý về kỷ thuật hổ trợ trực tiếp (assistive
technologies) mà thông qua đó, một label được mô tả như là một button.
Thêm thành phần vào các đối tượng chứa.
SwingApplication nhóm label và button vào trong một đối tượng chứa
(JPanel) trước khi thêm vào frame một thành phần khác. Đoạn mã sau đây
khởi tạo một panel:
(1) JPanel pane = new JPanel();
(2) pane.setBorder(BorderFactory.createEmptyBorder(30,
30, 10, 30));
(3) pane.setLayout(new GridLayout(0, 1));
(4) pane.add(button);
(5) pane.add(label);
Dòng (1) dùng để tạo một panel, khai báo một đối tượng có kiểu Jpanel với tên
gọi là pane.
Dòng (2) để tạo đường viền bao bọc cho panel đó.
Dòng (3) dùng đẻ tạo một đối tượng quản lý layout để giám sát tất cả các thành
phần có trong panel sẽ được hiển thị trên một cột.
Dòng (4) và (5) dùng để đưa button và label vào trong panel. Việc thêm button
và label vào trong panel có nghĩa là chúng sẽ được điều khiển bởi layout quản
lý panel đó.
Thêm đường viền (borders) xung quanh một thành phần.
Đoạn mã sau đây sẽ tạo một đường viền cho một panel:
pane.setBorder(BorderFactory.createEmptyBorder(
30, //top
9095883.doc 10
Giáo trình Java
30, //left
10, //bottom
30) //right
);
đường viền này đơn giản chỉ cung cấp một vùng trống của panel. Thêm 30
pixels cho top, left, và right, và 10 pixels cho bottom. Borders là tính năng mà
JPanel thừa kế từ lớp JComponent.
Handling events
SwingApplication chứa 2 event handlers. Một nắm bắt sự kiện kích vào nút
lệnh(action events). Cái kia để nắm bắt sự kiện đóng cửa sổ (window events).
Sau đây là đoạn mã quản lý các sự kiện của SwingApplication:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
numClicks++;
label.setText(labelPrefix + numClicks);
}
});
...
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Dealing with thread issues
Chương trình SwingApplication là một tiến trình an toàn. Bởi vì, một khi
giao diện của nó đang được hiển thị (visible), thì thao tác trên giao diện của nó
chỉ xảy ra cho một event handler. Không thể có hai tiến trình cùng truy xuất
đến một GUI trong cung fmột thời điểm.
Supporting assistive technologies
Hỗ trợ assistive technologies, một thiết bị giống như để đọc màn hình, cung
cấp cách thức để xử lý thông tin trên GUI. Hỗ trợ này đã có trong hầu hết các
thành phần Swing. Trong SwingApplication có một chỗ đề cập đến kỹ thuật
này:
label.setLabelFor(button);
Như đã nói, việc lấy thông tin từ các thành phần Swing là điều đang được quan
tâm, kỹ thuật trên đã giúp cho công việc này được thực hiện một cách dễ dàng:
JButton button = new JButton("I'm a Swing button!");
label = new JLabel(labelPrefix + "0 ");
label.setText(labelPrefix + numClicks);
JFrame frame = new JFrame("SwingApplication");
9095883.doc 11
Giáo trình Java
Ví dụ này sẽ đề cập đến một vài thành phần Swing thường dùng và cách thức
chúng tương tác với nhau trong một GUI và của sự phân cấp giới hạn.
SwingApplication tạo 4 thành phần Swing thường dùng như
sau:
• một frame, hoặc một cửa sổ làm việc chính (JFrame)
• một panel, thông thường gọi là pane (JPanel)
• một button (JButton)
• một label (JLabel)
frame là đối tượng chứa ở mức đỉnh. is a top-level container. Sự hiện
diện của frame nhằm cung cấp một vùng để các thành phần khác thiết lập sự có
mặt của mình trên vùng đó. Ngoài ra còn có các thành phần khác thường được
sử dụng để làm đối tượng chứa mức đỉnh là dialogs (JDialog) và applets
(JApplet).
panel là đối tượng chứa mức trung gian (intermediate container). panel nhằm
mục đích xác định vị trí của button và label. Những đối tượng chứa mức trung
gian khác còn có scroll panes (JScrollPane) và tabbed panes (JTabbedPane),
chúng có ảnh hưởng lẫn nhau, tương tác với nhau rtong giao diện của một
chương trình.
9095883.doc 12
Giáo trình Java
button và label là những thành phần cơ bản (atomic components), những thành
phần mà không thể chứa các thành phần Swing khác AWT thông thường, các
thành phần cơ bản này sẽ là nơi để nhận thông tin đầu vào từ phía người dùng.
Swing API cung cấp nhiều thành phần cơ bản, bao gồm combo boxes
(JComboBox), text fields (JTextField), và tables (JTable).
Hình dưới đây là sơ đồ phân cấp giới hạn của các thành phần trong ví dụ
SwingApplication.
Như hình vẽ trên, ngay cả các chương trình Swing đơn giảnn nhất cũng có
nhiều mức khác nhau. Nhưng bao giờ gốc của sơ đồ vẫn là đối tượng chứa mức
đỉnh, nới để các thành phần Swing khác thể hiện sự tồn tại của mình.
Mách nước: Để xem sự phân cấp của bất kỳ frame hay dialog nào, chỉ
cần kích chuột vào border của nó để chọn, nhấn Control-Shift-F1.
Mỗi một đối tượng chứa mức đỉnh đều gián tiếp chứa một đối tượng chứa
trung gian thường được gọi là content pane. Khi làm việc, bạn không cần quan
tâm thế nào là đối tượng chứa mức đỉnh và cái nào là đối tượng chứa trung
gian. Chương trình sẽ tự động quản lý cho bạn.
pane contains, trực tiếp hoặc gián tiếp chứa tất cả các thành phần sẽ hiển thị
trong GUI. Riêng đối với top-level container thì có menu bar, menu bar sẽ
đứng trong một vùng đặc biệt nằm ngoài content pane.
Để thêm một thành phần vào đối tượng chứa, có thể dùng nhiều cách khác
nhau của phương thức add(). Phương thức add() có ít nhất 1 đối số (argument)
Đoạn mã sau đây sẽ thực hiện việc thêm một button và một label vào trong
panel:
frame = new JFrame(...);
button = new JButton(...);
label = new JLabel(...);
pane = new JPanel();
pane.add(button);
pane.add(label);
frame.getContentPane().add(pane,
BorderLayout.CENTER);
2. Layout Management
9095883.doc 13
Giáo trình Java
Các đối tượng chứa sử dụng layout managers để xác lập kích thước và vị trí
của các thành phần chứa trong nó. Borders sẽ ảnh hưởng đến layout của Swing
GUIs bằng cách làm cho các thành phần lớn lên.
Hình dưới đây hiển thị GUI của 5 chương trình. GUI của chúng khác nhau là
do sử dụng các layout managers khác nhau để xác định kích thước và vị trí của
buttons.
Layout management là quá trình xác định kích thước và vị trí của các thành
phần. Mặc định, mỗi đối tượng chứa sẽ có một layout manager.
Java platform hỗ trợ sử dụng 5 layout managers thông thường nhất:
BorderLayout, BoxLayout, FlowLayout, GridBagLayout, và GridLayout.
Những layout managers được thiết kế để hiển thị đa thành phần trong cùng
một thời điểm. Và lớp thứ 6, CardLayout, là một trường hợp đặc biệt. Nó được
sử dụng để kết hợp các layout managers với nhau.
Xác lập Layout Manager
Bạn có thể dể dàng thay đổi một layout managers trở thành một container để
sử dụng. Đơn giản là chỉ cần gọi phương thức setLayout. Đoạn mã sau đây
sử dụng BorderLayout:
JPanel pane = new JPanel();
pane.setLayout(new BorderLayout());
Một vài gợi ý về Component (Providing Hints about a
Component)
Ta có thể sử dụng các phương thức sau để tùy biến kích thước và vị trí của các
thành phần: setMinimumSize, setPreferredSize, và
setMaximumSize, hoặc có thể xây dựng các lớp con của các thành phần để
khai thác các phương thức như: getMinimumSize, getPreferredSize, và
getMaximumSize.
9095883.doc 14
Giáo trình Java
Bên cạnh việc cung cấp các tùy biến về kích thước, ta cũng còn có thể cung
cấp thêm các tùy biến về việc canh chỉnh, gồm các phương thức sau:
setAlignmentX và setAlignmentY, getAlignmentX và
getAlignmentY methods.
How Layout Management Occurs
Ví dụ sau đây mô tả trình tự quá trình hiển thị của một frame (JFrame).
1. Khi GUI được xây dựng, JFrame sẽ gọi phương thức pack. Việc chỉ
định này sẽ bảo đảm frame xuất hiện đúng với kích thước mà nó đã
được xác lập trước đó.
2. To find the frame's preferred size, the frame's layout manager adds the
size of the frame's edges to the preferred size of the component directly
contained by the frame. This is the sum of the preferred size of the
frame's content pane, plus the size of the frame's menu bar, if any.
3. The content pane's layout manager is responsible for figuring out the
content pane's preferred size. By default, this layout manager is a
BorderLayout object. However, let's assume that we replace it with a
GridLayout object that's set up to create two columns, as in the
bottom right of the preceding snapshot. The interesting thing about grid
layout is that it forces all components to be the same size, and it tries to
make them as wide as the widest component's preferred width and as
high as highest one's preferred height.
First, the grid layout manager queries the content pane
for its insets -- the size of the content pane's border, if
any. Next, the grid layout manager queries each
component in the content pane for its preferred size,
noting the largest preferred width and largest preferred
height. Then it calculates the content pane's preferred
size.
4. When each button is asked for its preferred size, the button first checks
whether the user specified a preferred size. If so, it reports that size. If
not, it queries its look and feel for the preferred size.
3. Event Handling
Event handling thể hiện việc chương trình phản hồi các yêu cầu từ phía bên
ngoài, ví dụ như việc người dùng nhấn phím chuột. Chương trình Swing sẽ
thực hiện tất cả các thao tác và nắm bắt các sự kiện (event handling) bằng cách
thực hiện tiến trình của sự kiện.
Mỗi khi người dùng nhấn phím hay kích chuột, thì một sự kiện xảy ra. Bất kể
đối tượng nào cùng đều được gán bởi một sự kiện. Các thành phần Swing có
9095883.doc 15
Giáo trình Java
thể tạo ra nhiều kiểu sự kiện khác nhau. Bảng sau đây liệt kê một vài kiểu sự
kiện:
Hành động Kiểu Listener
User kích vào nút lệnh, nhấn phím Spacebar khi đang
làm việc trong text field, hoặc kích chọn vào menu ActionListener
item
WindowListene
User đóng một frame (main window)
r
User nhấn một nút chuột trong khi đang rê chuột trên
MouseListener
một thành phần
MouseMotionLi
User di chuyển chuột trên một thành phần
stener
ComponentList
Thành phần hiển thị
ener
Thành phần lấy trạng thái của keyboard FocusListener
ListSelectionLi
Việc chọn lựa trong Table hoặc list có thay đổi
stener
Mỗi sự kiện đều được đại diện bởi một đối tượng và đối tượng đó cung cấp
thông tin về sự kiện cũng như nhận dạng được nơi phat ra sự kiện. Nguồn của
sự kiện thông thường là các thành phần, nhưng những kiểu đối tượng khác
cũng có thể là nguồn của sự kiện. Hình sau đây minh hoạ cho vấn đề này.
3. Đăng ký sự hiện diện của lớp event handler như là một listener trên một
hoặc nhiều thành phần. Ví dụ:
4. someComponent.addActionListener(instanceOfMyCl
ass);
9095883.doc 16
Giáo trình Java
5. Thực thi những phương thức trong listener interface. Ví dụ:
6. public void actionPerformed(ActionEvent e) {
7. ...//code that reacts to the action...
8. }
Hãy xem xét cách thức một nút lệnh (JButton) nắm bắt sự kiện kích chuột. Để
xác định khi nào thì người dùng kích chuột lên nút lệnh (hoặc dùng các phím
nóng) thì một chương trình phải có đối tượng thực thi giao diện ActionListener.
Chương trình phải đăng ký đối tượng đó như là một action listener trên nút
lệnh (nguồn của sự kiện) bằng cách sử dụng phương thức addActionListener.
Khi user kích lên nút lệnh, nút lệnh sẽ phát ra một hành vi của sự kiện. Đây là
yêu cầu của phương thức actionPerformed. Trong phương thức này, tham số sẽ
là một đối tượng ActionEvent và tham số này sẽ cung cấp thông tin về sự kiện
và nguồn của sự kiện.
9095883.doc 17
Giáo trình Java
Cũng giống như event-handling, painting cũng được thực hiện trong một tiến
trình đơn. Trong khi một sự kiện đang xảy ra thì quá trình vẽ lại không được
thực hiện.
Quá trình vẽ lại các thành phần sẽ không bị ngắt quảng bởi các sự kiện khác.
Ví dụ minh hoạ về Painting (An Example of Painting)
Để minh hoạ cho quá trình painting, ta sử dụng lại chương trình
SwingApplication. Hình dưới là giao diện của SwingApplication:
Khi GUI của SwingApplication được vẽ, quá trình đó xảy ra như sau:
1. Đối tượng chứa mức đỉnh, JFrame, sẽ vễ lại nó trước tiên.
2. Các đối tượng chứa trung gian, trước hết là vẽ lại background, chứa nó.
Sau đó sẽ là JPane.
3. JPanel trước hết sẽ vẽ lại background, sau đó là đường viền và sau
cùng là các thành phần con chứa trong nó.
4. Để vẽ lại, JButton vẽ nền của nó, sau đó là dòng văn bản của chính nó.
9095883.doc 18
Giáo trình Java
...
//All manipulation of the GUI -- setText, getText, etc. --
//is performed in event handlers such as
actionPerformed().
...
}
6. Những tính năng và khái niệm khác của Swing
Swing cung cấp nhiều tính năng. Rất nhiều tính năng được cung cấp bởi
JComponent class. Một vài tính nằng thú vị sẽ không được đề cập đến trong
bài học này như icons, actions, công nghệ Pluggable Look & Feel, assistive
technologies, và separate models.
6.1 Những tính năng của Jcomponent (Features that
JComponent Provides)
9095883.doc 19
Giáo trình Java
Ngoại trừ đối tượng chứa mức đỉnh, tất cả các thành phần khác bắt đầu bằng ký
tự J đều được thừa kế từ lớp Jcomponent. Hầu hết các thành phần đều có các
tính năng chung như tooltips và cấu hình về giao diện (look and feel). Ngoài ra,
chúng còn thừa kế nhiều phương thức tiện lợi khác nữa.
6.2 Icons
Nhiều thành phần Swing, đặt biệt là button và label, có thể hiển thị hình ảnh.
Ta có thể chỉ định cho các hình ảnh này như là các đối tượng icon
6.3 Actions
Với đối tượng Action, Swing API cung cấp những hỗ trợ đặc biệt cho việc chia
xẽ dữ liệu và trạng thái giữa hai hoặc nhiều thành phần phát ra các sự kiện
hành động. Ví dụ, khi ta có một button và một menu item cùng một chức năng,
lúc đos cần cân nhắc việc sử dụng đối tượng Action để xác định văn bản, icon
và trạng thái của hai thành phần.
6.4 Support for Assistive Technologies
Assistive technologies such as screen readers can use the Accessibility API to
get information from Swing components. Because support for the Accessibility
API is built into the Swing components, your Swing program will probably
work just fine with assistive technologies, even if you do nothing special. With
very little extra effort, however, you can make your program function even
more smoothly with assistive technologies, which might well expand its
market. See How to Support Assistive Technologies for details.
7. Phân tích một chương trình Swing
Bao gồm một ứng dụng nhỏ về Swing với tên gọi là Converter sẽ mô tả
cách một chương trình Swing làm việc và mối quan hệ gắn kết nhau giữa các
đoạn mã trong chương trình.
Converter là một ứng dụng dùng để chuyển đổi đơn vị đo lường giữa hai hệ
thống met và U.S units. Để chạy được ứng dụng này thì phải biên dịch các tập
tin sau: Converter.java, ConversionPanel.java, ConverterRangeModel.java,
DecimalField.java, FollowerRangeModel.java,FormattedDocument.java và
Unit.java.
Sau đây là hình ảnh minh hoạ về giao diện của Converter:
9095883.doc 20
Giáo trình Java
Trong các bài học sau, chúng ta sẽ tìm hiểu chi tiết về các tính năng, khái niệm về
Swing. Chắc chắn sẽ còn nhiều thú vị đang chờ đợi chúng ta
9095883.doc 21
Giáo trình Java
9095883.doc 22
Giáo trình Java
Đây là những gì nhìn thấy khi menu "Go left" trở nên disabled:
9095883.doc 23
Giáo trình Java
tác động hay không. Thông qua phương thức
setEnabled(boolean setEnabled(false), vô hiệu tất cả các tác động lên
) các thành phần. Tương tự như vậy, sử dụng phương
boolean isEnabled() thức setEnabled(true) để tác động lại hành vi của
các thành phần.
Creating an Action-Controlled Component
Method Purpose
JMenuItem
add(Action)
JMenuItem Tạo một đối tượng JMenuItem và đặt chúng vào
insert(Action, int) trong menu hay popup menu.
(in JMenu and
JPopupMenu)
JButton add(Action) Tạo một đối tượng Jbutton và đặt chúng lên thanh
(in JToolBar) công cụ.
2. Thế nào là kỹ thuật hỗ trợ Assisive(Support Assistive
Technologies)
Các thành phần Swing hỗ trợ kỹ thuật trợ giúp. Chương trình của bạn sẽ được
hỗ trợ tốt hơn. Ví dụ như dòng tooltip sẽ hiện lên chức năng của một nút lệnh
nào đó khi ta di chuyển chuột lên nút lệnh đó.
9095883.doc 24
Giáo trình Java
Trong phần mã của chương trình, câu lệnh (1) dùng để tạo icon sử dụng một
icon, câu lệnh (2) và (3) gán icon ấy vào trong hai label::
(1) ImageIcon icon = new ImageIcon("images/middle.gif",
"a pretty but meaningless splat");
...
(2) label1 = new JLabel("Image and Text", icon,
JLabel.CENTER);
...
(3) label3 = new JLabel(icon);
Tham số thứ nhất trong ImageIcon constructor xác định tập tin ảnh để nạp
lên, phần này phải đẻ ý đến đường dẫn tới thư mục có chứa tập tin class. Tham
số thứ hai dùng để mô tả về icon ấy, giống như phần tooltip của các ứng dụng
mà chúng ta vẫn thường thấy.
Nói chung, các applet nạp hính ảnh từ máy tính, nơi phục vụ cho applet ấy. Có
hai lý do để làm như vậy, thứ nhất là không tin tưởng khi để các applet đọc các
tập tin hệ thông từ máy nó đang chạy. Thứ hai là để kết hợp các lớp của applet
với tập tin dữ liệu với nhau. Để nạp một hình ảnh từ server, một applet phải sử
dụng URL như đoạn mã trong ví dụ dưới đây:
public class SomeClass extends JApplet ... {
protected String leftButtonFilename =
"images/left.gif";
...
public void init() {
...
URL leftButtonURL = getURL(leftButtonFilename);
...
leftButtonIcon = new ImageIcon(leftButtonURL,
"an arrow pointing left");
...
}
...
protected URL getURL(String filename) {
URL codeBase = getCodeBase();
URL url = null;
try {
url = new URL(codeBase, filename);
9095883.doc 25
Giáo trình Java
} catch (java.net.MalformedURLException e) {
System.err.println("Couldn't create image: " +
"badly specified URL");
return null;
}
return url;
}
...
}
• Với mỗi image icon, nó sử dụng một đối tượng image để để chứa dữ
liệu của hình ảnh và đối tượng MediaTracker được chia sẽ cho tất cả các
icon trong cùng một chương trình.
Xác định hình ảnh nguồn (Specifying the Image Source)
Thường thì dữ liệu của một hình ảnh xuất phát từ một tập tin hình ảnh. Có thể
xác định nơi lưu trữ của tập tin thông qua tên tập tin hoặc sử dụng đối tượng
URL. Đối với ứng dụng, tên tập tin hoặc URL đều có liên quan đến thư mục
chứa chứa tập tin .class của ứng dụng hoặc là đường dẫn. Để chỉ định một URL
liên quan đến đường dẫn của ứng dụng, ta có thể sử dụng phương thức
getSystemResource như ở ví dụ dưới đây:
ImageIcon icon = null;
URL iconURL =
ClassLoader.getSystemResource("images/middle.gif");
if (iconURL != null) {
icon = new ImageIcon(iconURL,
"a beautiful yet meaningless icon");
}
Phương thức getSystemResource sẽ dò tìm trong thư mục và tập tin JAR trong
đường dẫn của chương trình, trả về URL ngay khi nó tìm thấy. Ví dụ, khi ta
đưa vào đường dẫn của ứng dụng tập tin jar có tên icons.jar, nếu tập tin JAR có
chứa images/middle.gif, thì dứat khoát, đường dẫn sẽ trả về một URL xác định
cho images/middle.gif. Tuy nhiên, có thể là URL đó không có bất cứ liên quan
nào về tập tin icons.jar.
9095883.doc 26
Giáo trình Java
Bảng sau đây liệt kê những cấu trúc và phương thức sử dụng thông thường của
ImageIcon. constructors and methods. Lưu ý là ImageIcon không có
nguồn gốc từ JComponent hay thậm chí là từ Component.
Setting, Getting, and Painting the Image Icon's Image
Method or
Purpose
Constructor
ImageIcon()
ImageIcon(byte[]
)
ImageIcon(byte[],
String)
ImageIcon(Image Tạo một ImageIcon instance, khởi tạo nó để chứa hình
) ảnh đã được xác lập. Tham số thứ nhất chỉ ra nguồn của
ImageIcon(Image hình ảnh như image, số byte, tên tập tin, hay URL. Từ đó
, String) hình ảnh sẽ được nạp lên. Nguồn của hình ảnh phải có
ImageIcon(String) dạng thức file được hỗ trợ bởi lớp java.awt.Image có
đuôi là GIF hoặc JPEG.
ImageIcon(String,
String)
ImageIcon(URL)
ImageIcon(URL,
String)
void
setImage(Image) Xác lập hoặc lấy image hiển thị bởi image icon.
Image getImage()
Vẽ ảnh của icon trong vùng đồ hoạ đã được chỉ địnhPaint
the image icon's image in the specified graphics context.
You would do this only if you're implementing a custom
void
component that performs its own painting. The
paintIcon(Compo
Component object is used as an image observer. You
nent, Graphics,
can rely on the default behavior provided by
int, int)
Component class and pass in any component. The two
int argments specify the x and y coordinates,
respectively.
Setting or Getting Information about the Image Icon
Method Purpose
void
setDescription(S
Set or get a description of the image. This description is
tring)
intended for use by assistive technologies.
String
getDescription()
int Get the width or height of the image icon in pixels.
getIconWidth()
9095883.doc 27
Giáo trình Java
int
getIconHeight()
Watching the Image Icon's Image Load
Method Purpose
void
setImageObserver(Image
Observer) Set or get an image observer for the image icon.
ImageObserver
getImageObserver()
Get the loading status of the image icon's
int getImageLoadStatus() image. The set of values returned by this
method are defined by MediaTracker.
5. Sử dụng tiến trình(Threads)
Sử dụng tiến trình là một công việc khó khăn. Do đó nếu có thể được thì bạn
nên tránh phần này. Tuy nhiên Thread có thể giúp cải tiến chương trình của bạn
bằng cách quản lý sự thực thi.
Nguyên tắc đầu tiên khi sử dụng threads là: tránh dùng chúng nếu như có thể.
Threads có thể rất khó sử dụng và chúng có thể gây khó khăn khi chúng ta
debug chương trình. Để tránh trường hợp bị đình trệ của chương trình, cần phải
quan tâm ngay từ đầu rằng mỗi tiến trình được tạo ra không kêu gọi thực thi
bất kỳ một thành phần Swing nào.
Mặc dù nguy hiểm, nhưng threads rất cso giá trị khi ta sử dụng chúng một cách
cẩn thận. Ta có thể cải thiện việc thực hiện chương trình. Đôi khi, một vài tiến
trình làm đơn giản mã hoặc cấu trúc của một chương trình. Sau đây là một vài
tình huống khi sử dụng tiến trình:
• To move a time-consuming initialization task out of the main thread, so
that the GUI comes up faster. Examples of time-consuming tasks
include making extensive calculations and blocking for network or disk
I/O (loading images, for example).
• To move a time-consuming task out of the event-dispatching thread, so
that the GUI remains responsive.
• To perform an operation repeatedly, usually with some predetermined
period of time between operations.
• To wait for messages from other programs.
Nếu tạo một thread, cần phải tránh những nguy hiểm khi thực thi một tiến trình
với các lớp tiện ích như SwingWorker hay Timer. Đối tượng SwingWorker tạo
một thread để thực thi một qui trình xữ lý về thời gian. Sau khi qui trình hoàn
thành, SwingWorker cung cấp một vài tùy chọn để thực hiện việc gửi đi một sự
9095883.doc 28
Giáo trình Java
kiện. Đối tượng Timer thực thi một thread và sinh ra một hoặc nhiều hành vi sự
kiện sau khi xác định được lặp lại.
6. Sử dụng Timers
Với lớp Timer, bạn có thể cho thực hiện một tiến trình của việc thực thi một
hành động sau một khoảng thời gian xác định và lặp lại hành vi ấy.
Có hai cách để thực hiện Timer:
• Thực hiện một tác vụ, với thời gian lặp lại được xác định. Ví dụ, tool tip
manager sử dụng timers để quyết định khi nào thì hiển thị và khi nào thì
tắt nó đi.
• Thực hiện việc lặp đi lặp lại một tác vụ.
Trong ví dụ dưới đây sử dụng đối tượng timer để thể hiện tiến trình làm việc
của một tác vụ.
9095883.doc 29
Giáo trình Java
Bảng sau đây liệt kê những cấu trúc và phương thức của Timer. Các hàm API
về sử dụng timers chia thành hai loại như sau:
• Tạo và khởi động Timer
• Chạy một Timer
Creating and Initializing the Timer
Method or
Purpose
Constructor
Tạo một timer. Tham số int chỉ rõ thời gian dừng
(milliseconds) giữa hai hành vi sự kiện. Sử dụng setDelay
để thay đổi độ trể. Tham số thứ hai là một action listener, là
Timer(int,
một constructor dùng để nhận biết với một timer. Ngoài ra,
ActionListener)
còn có thể đăng ký action listeners với
addActionListener và gỡ bỏ chúng bằng
removeActionlistener.
void
setDelay(int) Xác lập hoặc lấy số milliseconds.
int getDelay()
void
setInitialDelay(i
nt) Xác lập hoặc lấy số milliseconds chờ trước khi bắt đầu hành
int vi sự kiện thứ nhất.
getInitialDelay(
)
void
setRepeats(boo Xác lập hoặc chỉ ra timer có lặp lại hay không. Mặc định có
lean) giá trị true. Gọi setRepeats(false) để khởi đầu cho một
boolean timer khởi động và kết thúc một hành.
isRepeats()
void
setCoalesce(bo Xác lập hoặc chỉ ra timer có liên tục hay không. Gửi một
olean) hành vi sự kiện vào một hành vi sự kiện đơn. Mặc định có
boolean gái trị true.
isCoalesce()
Running the Timer
Method Purpose
void start()
Khởi động timer. restart còn có thể thoát bất kỳ một hành vi
void
sự kiện nào được gửi tới.
restart()
void stop() Dừng hoạt động của một timer.
boolean
Kiểm tra xem có timer.
isRunning()
9095883.doc 30
Giáo trình Java
Bài 4: Bố trí các thành phần bên trong các đối tượng chứa
Bài học này sẽ hướng dẫn bạn cách quản lý việc bày trí mà Java Platform cung
cấp, cách sử dụng vị trí tuyệt đối.
1. Sử dụng Layout Managers
Phần này cung cấp các qui tắc tổng quan và chi tiết lệnh trong việc sử dụng
việc quản lý bố trí mà Java platform cung cấp.
a. Sử dụng Layout Managers
Sử dụng BorderLayout
Sau đây là một Applet cho thấy BorderLayout làm việc như thế nào.
setLayout(new BorderLayout());
setFont(new Font("Helvetica", Font.PLAIN, 14));
cards.add(BUTTONPANEL, p1);
9095883.doc 31
Giáo trình Java
cards.add(TEXTPANEL, p2);
Khi bạn thêm một thành phần vào một Container mà có sử dụng CardLayout,
bạn phải sử dụng phương thức add() hai thông số: add(String name,
Component comp). Thông số thứ nhất có thể bất kì chuỗi nào để nhận ra
thành phần được thêm vào.
Sau đây là một đoạn mã ví dụ cho phương thức trên:
//Where the container is initialized:
...
//Put the Choice in a Panel to get a nicer look.
Panel cp = new Panel();
Choice c = new Choice();
c.addItem(BUTTONPANEL);
c.addItem(TEXTPANEL);
cp.add(c);
add("North", cp);
...
9095883.doc 32
Giáo trình Java
add(new Button("Button 3"));
add(new Button("Long-Named Button 4"));
add(new Button("Button 5"));
Lớp FlowLayout có ba cấu trúc:
public FlowLayout()
public FlowLayout(int alignment)
public FlowLayout(int alignment,
int horizontalGap, int verticalGap)
thông số alignment phải là các giá trị FlowLayout.LEFT,
FlowLayout.CENTER, hoặc FlowLayout.RIGHT. Thông số horizontalGap và
verticalGap xác định số Pixel đặc giữa các thành phần. Nếu bạn không xác lập giá
trị này, FlowLayout sẽ mặc định giá tri 5 cho mỗi thông số.
Sử dụng GridLayout
Sau đây là một Aplet cho thấy GridLayout làm việc như thế nào.
//Construct a GridLayout with 2 columns and an
unspecified number of rows.
setLayout(new GridLayout(0,2));
setFont(new Font("Helvetica", Font.PLAIN, 14));
9095883.doc 33
Giáo trình Java
GridBagLayout rút ra một giá trị ràng buộc và không dùng lại
GridBagConstraints. Bạn phải cẩn thận, tuy nhiên, để khởi tạo lại giá trị của
một đối tượng GridBagConstraints làm giá trị mặc định khi cần thiết.
Bạn có thể xác lập các giá trị sau:
gridx, gridy
Xác định hàng và cột tại vị trí trên bên tái của thành phần. Hầu hết cột trên bên
tải có địc chỉ gridx=0, và hàng trên cùng có địa chỉ gridy=0. Sử dụng
GridBagConstraints.RELATIVE (giá trị mặc định) để xác định rằng thành
phần đó chỉ ở bên phải hay ở phía dưới.
gridwidth, gridheight
xác lập số cột hoặc số hàng trong vùng hiển thị của thành phần. những giá trị
này xác định số Cell mà thành phần sử dụng, không phải số Pixel nó sử dụng.
Mặc định là 1. Sử dụng GridBagConstraints.REMAINDER để xác định
thành phần đang ở hàng cuối cùng hay cột cuối cùng. Sử dụng
GridBagConstraints.RELATIVE để xác định bước kế tiếp của thaǹh phần
là hàng cuối hay cột cuối cùng.
fill
Được sử dụng khi vùng hiển thị của thành phần lớn hơn kich thước thành phần
đòi hỏi để quyết định khi nào hoặc thay đổi kích thước như thế nào. các giá trị
thích hợp là GridBagConstraints.NONE (mặc định),
GridBagConstraints.HORIZONTAL,
GridBagConstraints.VERTICAL và GridBagConstraints.BOTH.
ipadx, ipady
xác định phần phụ ở bên trong: bao nhiêu để thêm vào kích thước tối thiểu của
thành phần. giá trị mặc định là 0. Chiều rộng của thành phần tối thiểu nhất là
bằng chiều rộng tối thiểu của nó cộng với ipadx*2. Similarly, chiều cao của
thành phần tối thiểu nhất là bằng chiều cao tối thiểu của nó cộng với ipady*2.
insets
xác định phần phụ bên ngoài của thành phần. mặc định, mỗi thành phần không
có phần phụ bên ngoài.
anchor
được sử dụng khi thành phần nhỏ hơn vùng hiển thị để quyết định khi nào đặt
thành phần. gái trị thích hợp là GridBagConstraints.CENTER (mặc định),
GridBagConstraints.NORTH, GridBagConstraints.NORTHEAST,
GridBagConstraints.EAST, GridBagConstraints.SOUTHEAST,
GridBagConstraints.SOUTH, GridBagConstraints.SOUTHWEST,
GridBagConstraints.WEST, và GridBagConstraints.NORTHWEST.
Ví dụ :
Sau đây là một Applet chỉ cho thấy GridBagLayout hoạt động như thế nào.
Sau đây là một đoạn lệnh tạo một GridBagLayout và các thành
phần nó quản lí
protected void makebutton(String name,
GridBagLayout gridbag,
GridBagConstraints c) {
Button button = new Button(name);
9095883.doc 34
Giáo trình Java
gridbag.setConstraints(button, c);
add(button);
}
public GridBagWindow() {
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
makebutton("Button1", gridbag, c);
makebutton("Button2", gridbag, c);
makebutton("Button3", gridbag, c);
9095883.doc 35
Giáo trình Java
9095883.doc 36
Giáo trình Java
private boolean laidOut = false;
private Button b1, b2, b3;
public NoneWindow() {
super();
setLayout(null);
setFont(new Font("Helvetica", Font.PLAIN, 14));
b1 = new Button("one");
add(b1);
b2 = new Button("two");
add(b2);
b3 = new Button("three");
add(b3);
}
laidOut = true;
}
}
...
}
9095883.doc 37
Giáo trình Java
4. Giải quyết các vấn đề về Layout
Một vài vấn đề thông thường về layout mà thường là các thành phần hiển thị
quá nhỏ hoặc không hiển thị. Trong phần này sẽ giúp chúng ta xử lý những vấn
đề này.
Bài toán: Làm thế nào để xác định được chính xác kích thước của một thành
phần?
• Đầu tiên, chắc chắn bạn thật sự muốn xác lập kích thước chính xác của
thành phần. những thành phần chuẩn có kích thước khác nhau, phụ
thuộc vao Platform mà thành phần đó đang chạy và Font nó sử dụng, vì
vậy thwongf chỉ làm theo cảm giác để xác định kích thước chính xác
của các thành phần.
Đối với những Custom Component có kích thước xác
định, xác định kích thước chính xác chỉ là cảm giác chủ
quan. Bạn cần bỏ qua các phương thức minimumSize() và
preferredSize() của thành phần để trả về một kích thước
đúng cho thành phần đó.
Để thay đổi kích thước của thành phần khi thành phần đó
đang hiển thị, xem bài toán tiếp theo.
Bài toán: Làm thế nào để thay đổi kích thước của một thành phần?
• Một khi thành phần đã hiển thị, bạn có thể thay đổi kích thước của nó
bằng phương thức resize(). Rồi bạn gọi phương thức validate() để
Container vè lại.
Bài toán: Thành phần đang có kích thước quá nhỏ.
• Thành phần đó có thực thi những phương thức preferredSize() và
minimumSize() hay không? Nếu vậy, nó có trả về giá trị đúng hay
không?
• Khi bạ dùng Layout manager, bạn có thể dùng không gian sẵn có hay
không?
Bài 5: Viết sự kiện Listeners
Trong bài học này sẽ trình bày một cách chi tiết để làm thế nào viết một sự
kiện listeners. Để hiểu phần này thì bạn phải có kiến thức về Event Handling.
1. Một vài ví dụ về Event-Handling
Các applets trong phần này sẽ minh hoạ cho các sự kiện và quá trình tiến hành
của sự kiện.
2. Tổng quan về Writing Event Listeners
Cung cấp thông tin cần thiết về tất cả các kiểu của sự kiện. Một trong những
tiêu đề trong phần này là trình bày cách làm sao để giảm bớt công sức và sự
không cần thiết của việc viết code cho chương trình bằng cách sử dụng các lớp
trong để thực thi các sự kiện.
9095883.doc 38
Giáo trình Java
Để có thể nắm bắt phần này một cách dễ dàng, xem như bạn đã có những kiến
thức cơ bản về các sự kiện listener trong phần Event Handling. Chẵng hạn như
ta có thể gắn một đa listeners vào nguồn của một đơn sự kiện. Nhưng quan
trọng hơn hết là các phương thức event-listener sẽ được xử lý một cách nhanh
chóng. Bởi vì tất cả các event-handling và các phương thức vẽ đều được thực
hiện trong cung một tiến trình.
Trong phần này, chúng ta sẽ bàn về EventObject, một lớp con cho tất cả các
sự kiện AWT và Swing
Lấy thông tin sự kiện: Event Objects (Getting Event
Information: Event Objects)
Mỗi một phương thức event-listener đều có một đối số đơn, một đối tượng thừa
kế từ lớp EventObject. method has a single argument -- an object that inherits
from the EventObject class. Mặc dù đối số luôn xuất phát từ
EventObject, với kiểu tổng quan để có thể thực hiện chính xác hơn. Ví dụ
như khi nắm bắt sự kiện của chuột, đối số cho phương thức này sẽ lấy từ
MouseEvent, một lớp con của EventObject.
Lớp EventObject định nghĩa một phương thức rất hữu ích như
sau:
Object getSource()
Phương thức này trả về một đối tượng nắm bắt sự kiện.
Chú ý rằng phương thức getSource cũng trả về một đối tượng.
Lớp Event đôi khi cũng định nghĩa một phương thức giống như
getSource, nhưng kiểu của giá trị trả về hơi bị hạn chế. Ví dụ
như lớp ComponentEvent định nghĩa phương thức
getComponent, giống như getSource, trả về đối tượng nắm
bắt sự kiện. Cái khác nhau ở đây là getComponent luôn luôn
trả về một Component.
Thường thì một lớp sự kiện nào đó định nghĩa một phương thức
và trả về thông tin của sự kiện.
Khái niệm: Low-Level Events and Semantic Events
Các sự kiện có thể được phân chia thành 2 loại: low-level events và semantic
events. Low-level events mô tả window-system xảy ra hoặc dữ liệu vào ở mức
thấp (low-level input). Tất cả các sự kiện còn lại thuộc loại semantic event.
Sự kiện mouse và key, cả hai đều là kết quả trực tiếp từ phía người dùng, là
những sự kiện low-level. Những sự kiện low-level khác bao gồm component,
container, focus, và window events. Sự kiện component cho phép thay đổi vị
trí, kích thước và sự hiển thị của thành phần. Sự kiện container quản lý để nắm
bắt được thành phần nào khi được thêm vào hay gở bỏ khỏi các đối tượng
chứa. Focus events sẽ báo cho biết khi nào một thành phần là có hoặc không
keyboard focus, khả năng nhận biết ký tự được gõ tại bàn phím. Window
9095883.doc 39
Giáo trình Java
events giúp để nắm bắt những trạng thái căn bản nhất của bất kỳ Window nào,
chẳng hạn như Dialog hay một Frame.
Semantic events bao gồm action events, item events, và list selection events.
Hành động của mỗi semantic event có thể khác nhau do thành phần. Ví dụ như
một button có thể nắm bắt sự kiện khi người dùng kích chuột lên nó. Nhưng
một text field nắm bắt sự kiện khi người dùng nhấn Return.
Sử dụng Adapters and Inner Classes để nắm bắt các sự kiện
Phần này hướng dẫn bạn sử dụng các lớp adapters và inner để làm giảm bớt sự lộn
xộn trong đoạn mã của chương trình bạn.
Hầu hết các giao diện AWT listener, không như ActionListener, chứa nhiều hoặc
một phương thức. Ví dụ, giao diện MouseListener chứa năm phương thức:
mousePressed, mouseReleased, mouseEntered, mouseExited, và
mouseClicked. Dù là bạn chỉ quan tâm về nhấn chuột, nếu lớp bạn đang sử dụng
thực thi MouseListener thì bạn phải thực thi tất cả 5 phương thức.
Ví dụ :
//An example with cluttered but valid code.
public class MyClass implements MouseListener {
...
someObject.addMouseListener(this);
...
/* Empty method definition. */
public void mousePressed(MouseEvent e) {
}
9095883.doc 40
Giáo trình Java
AWT cung cấp lớp adapter class cho mỗi listener interface với nhiều hơn một phương
thức.
Để sử dụng adapter, bạn tạo một lớp con cho nó, thay vì phải thực thi một listener
interface.
/*
* An example of extending an adapter class instead of
* directly implementing a listener interface.
*/
public class MyClass extends MouseAdapter {
...
someObject.addMouseListener(this);
...
public void mouseClicked(MouseEvent e) {
...//Event handler implementation goes here...
}
}
Giả dụ bạn muốn viết một applet, và bạn muốn Applet của bạn chứa vài đoạn mã để
nắm bắt các sự kiện của chuột. Từ khi ngôn ngữ Java khhong cho phép đa thừa kế thì
bạn không thể mở rộng cả 2 lớp Applet and MouseAdapter. Giải pháp là định
nghĩa một lớp inner -- một lớp nằm trong Aplet -- that extends the MouseAdapter
class,
//An example of using an inner class.
public class MyClass extends Applet {
...
someObject.addMouseListener(new MyAdapter());
...
class MyAdapter extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
...//Event handler implementation goes here...
}
}
}
3. Hỗ trợ Listeners của các thành phần Swing
Có thể nói rằng loại của sự kiện một thành phần có thể được phân loại bằng
cách dựa vào loại của sự kiện listeners mà ta đăng ký trên thành phần đó. Ví dụ
như lớp Component định nghĩa nhýÞng phương thức listener nhý sau:
• addComponentListener
• addFocusListener
• addKeyListener
• addMouseListener
• addMouseMotionListener
9095883.doc 41
Giáo trình Java
Do vậy, mỗi thành phần hỗ trợ component, focus, key, mouse, và mouse-
motion listeners. Tuy nhiên, một thành phần khởi động những sự kiện mà
listeners có đắngky trên nó. Ví dụ, một mouse listener được đăng ký trên một
thành phần riêng biệt, nhưng thành phần ấy không có listeners khác, thì thành
phần đó sẽ khởi động chỉ mỗi sự kiện mouse events, không có các sự kiện
component, focus, key, or mouse-motion.
Listeners that All Swing Components Support
Vì tất cả các thành phần Swing đều xuất phát từ lớp AWT Component, cho
nên ta phải khai báo những listeners sau trên bất kỳ thành phần Swing nào:
component listener
Nắm bắt sự thay đổi về kích thước, vị trí và sự hiển thị của thành phần. focus
listener
Nắm bắt các thành phần có nhận hay không tác động từ bàn phím.
key listener
Nắm bắt động tác ấn phím; sự kiện key chỉ khởi tạo bởi các thành phần đang
có trạng thái mặc định của bàn phím.
mouse events
Nắm bắt sự kiện kích chuột và di chuyển chuột trên thành phần.
mouse-motion events
Nắm bắt sự thay đổi về vị trí của con trỏ trên thành phần.
Các Listeners khác mà các thành phần Swing hỗ trợ
Bảng sau đây liệt kê các thành phần Swing và listeners được hỗ trơ. Trong
nhiều trường hợp, các sự kiện được khởi động trực tiếp từ thành phần. Những
trường hợp khác, các sự kiện được khởi động từ dữ liệu của thành phần hoặc từ
các kiểu mẫu được chọn.
Listener
Component document,
chang list wind othe
action caret undoable item
e selection ow r
edit
button X X X
check box X X X
color chooser X
combo box X X
dialog X
h
ype
editor pane X X
rlin
k
file chooser X
frame X
internal frame inte
9095883.doc 42
Giáo trình Java
rnal
fra
me
list
list X
data
m
menu enu
m
enu
key
men
menu item X X X u
dra
g
mo
use
option pane
password field X X X
p
opu
popup menu p
men
u
progress bar X
radio button X X X
slider X
tabbed pane X
tabl
e
mo
del
tabl
e
table X colu
mn
mo
del
cell
edit
or
9095883.doc 43
Giáo trình Java
text area X X
text field X X X
hyp
text pane X X
erli
nk
toggle button X X X
tree
exp
ansi
on
tree
will
exp
tree
and
tree
mo
del
tree
sele
ctio
n
viewport
(used by X
scrollpane)
4. Thực hiện Listeners cho các Handled Events thông thường
Phần này sã bao gồm các chi tiết về ví dụ và thông tin của việc viết những sự
kiện listener thông thường.
Viết một Action Listener
Khi người sử dụng kích chuột vào Button, đúp chuột vào ListItem, chọn MenuItem,
hoặc nhấn phím trong TextField, một sự kiện sẽ xảy ra. Kết quả đó là một thông báo
actionPerformed được gởi đi đến tất cả các action listener và nó đăng kí với các
thành phần có liên quan.
Các phương thức, sự kiện của hành động
Giao diện ActionListener chứa một phương thức đơn, và do đó nó không có lớp
adapter tương ứng. Đây là phương thức ActionListener cô độc:
void actionPerformed(ActionEvent)
Một ví dụ về nắm bắt các sự kiện của hành động
Một ví dụ đơn giản
public class Beeper ... implements ActionListener {
...
//where initialization occurs:
9095883.doc 44
Giáo trình Java
button.addActionListener(this);
...
public void actionPerformed(ActionEvent e) {
...//Make a beep sound...
}
}
9095883.doc 45
Giáo trình Java
Trả về thành phần mà sinh ra sự kiện đó. Bạn có thể dùng nó thay vì dùng phương
thức getSource.
int getAdjustmentType()
Trả về kiểu của adjustment được tìm thấy. giá trị trả về là một trong những giá trị sau
được định nghĩa trong lớp AdjustmentEvent: UNIT_INCREMENT,
UNIT_DECREMENT, BLOCK_INCREMENT, BLOCK_DECREMENT, TRACK.
int getValue()
Trả về giá trị của thành phần ngay sau khi adjustment được tìm thấy.
Viết một Component Listener
là một trong những sự kịen của thành phần được phát ra bởi đối tượng Component
ngay sau khi thành phần đó mất đi, làm ẩn đi, chuyển vị trí hoặc thay đổi kích thước
Các phương thức, sự kiện của thành phần
Giao diện ComponentListener và lớp mô phỏng tương ứng,
ComponentAdapter, chứa 4 phương thức:
void componentHidden(ComponentEvent)
được gọi bởi AWT sau khi thành phần biến mất bởi phương thức setVisible.
void componentMoved(ComponentEvent)
được gọi bởi AWT sau khi thành phần di chuyển, nó quan hệ với đối tượng chứa nó.
void componentResized(ComponentEvent)
được gọi bởi AWT sau khi thành phần thay đổi kích thước.
void componentShown(ComponentEvent)
được gọi bởi AWT sau khi thành phần xuất hiện bởi phương thức setVisible.
Ví dụ về Handling Component Events
public class ComponentEventDemo ... implements ComponentListener {
...
//where initialization occurs:
aFrame = new Frame("A Frame");
ComponentPanel p = new ComponentPanel(this);
aFrame.addComponentListener(this);
p.addComponentListener(this);
...
9095883.doc 46
Giáo trình Java
}
9095883.doc 47
Giáo trình Java
9095883.doc 48
Giáo trình Java
+ "\n");
}
...
}
9095883.doc 49
Giáo trình Java
label.setVisible(false);
}
}
Lớp ItemEvent
Mỗi phương thức của Item event có một thông số đơn: đối tượng ItemEvent. Lớp
ItemEvent định nghĩa các phương thức sau:
Object getItem()
Trả về Item đợc tập trung trong sự kiện này.
ItemSelectable getItemSelectable()
Tar về thành phần phát ra sự kiện.
int getStateChange()
trả về trạng thái mới của Item. Lớp ItemEvent định nghĩa hai trạng thái:
SELECTED và DESELECTED.
Viết một Key Listener
Đựoc phát ra khi người sử dụng đánh phím. Đặc biệt Key events phát ra bởi đối tượng
mà dang được tập trung khi người dùng nhấn hoặc nhả phím.
Các phương thức sự kiện của Key
Giao diện KeyListener và lớp mô phỏng tương ứng, KeyAdapter, chứa ba
phương thức:
void keyTyped(KeyEvent)
đựoc gọi sau khi phím đựoc đánh.
void keyPressed(KeyEvent)
được goị sau khi một phím được ấn.
void keyReleased(KeyEvent)
được gọi sau khi một phím được nhả.
Ví dụ về Handling Key Events
public class KeyEventDemo ... implements KeyListener ... {
...//where initialization occurs:
typingArea = new TextField(20);
typingArea.addKeyListener(this);
...
/** Handle the key typed event from the text field. */
public void keyTyped(KeyEvent e) {
displayInfo(e, "KEY TYPED: ");
}
/** Handle the key pressed event from the text field. */
public void keyPressed(KeyEvent e) {
displayInfo(e, "KEY PRESSED: ");
}
/** Handle the key released event from the text field. */
public void keyReleased(KeyEvent e) {
displayInfo(e, "KEY RELEASED: ");
}
9095883.doc 50
Giáo trình Java
...
protected void displayInfo(KeyEvent e, String s){
...
char c = e.getKeyChar();
int keyCode = e.getKeyCode();
int modifiers = e.getModifiers();
...
tmpString = KeyEvent.getKeyModifiersText(modifiers);
9095883.doc 51
Giáo trình Java
addMouseListener(this);
...
9095883.doc 52
Giáo trình Java
Các phương thức, sự kiện của Mouse Motion
Giao diện MouseMotionListener và lớp mô phỏng tương ứng,
MouseMotionAdapter, chứa hai phương thức:
void mouseDragged(MouseEvent)
được gọi sau khi người sử dụng di chuyển chuột trong khi chuột đang được nhấn.
void mouseMoved(MouseEvent)
được gọi sau khi người sử dụng di chuyển chuột khi con chuột chưa bị nhấn.
Ví dụ về Handling Mouse Motion Events
...//where initialization occurs:
MyListener myListener = new MyListener();
addMouseListener(myListener);
addMouseMotionListener(myListener);
...
class MyListener extends MouseAdapter
implements MouseMotionListener {
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
repaint();
}
void updateSize(MouseEvent e) {
int x = e.getX();
int y = e.getY();
currentRect.setSize(x - currentRect.x,
y - currentRect.y);
repaint();
}
}
9095883.doc 53
Giáo trình Java
Các phương thức, sự kiện được sử dụng bởi Mouse-Motion Listeners
Mỗi phương thức Mouse Motion Event có một thông số đơn, và nó không đợc gọi là
MouseMotionEvent! Thay vào đó, phương thức Mouse Motion Event sử dụng đối
tượng MouseEvent.
Viết một Text Listener
Các sự kiện Text trả về sau khi chuỗi trong thành phần Text có sự thay đổi.
Các phương thức, sự kiện của Text
Giao diện TextListener chỉ có một phương thức nên không có lớp mô phỏng tương
ứng:
void textValueChanged(TextEvent)
được gọi sau khi chuỗi trong thành phần Text thay đổi.
Examples of Handling Text Events
public class TextEventDemo ... {
TextField textField;
TextArea textArea;
TextArea displayArea;
...
//where initialization occurs:
textField = new TextField(20);
...
textField.addTextListener(new MyTextListener("Text Field"));
displayArea.append(preface + s + "\"\n");
...
}
}
9095883.doc 54
Giáo trình Java
...
}
Lớp TextEvent
Mỗi phương thức Text Event có một thông số đơn : đối tượng TextEvent. Lớp
TextEvent định nghĩa một phương thức. Phương thức getSource mà TextEvent
thừa kế từ EventObject, bạn có thể nhận được thành phần Text liên quan đến sự
kiện này và gởi thông điệp cho nó.
Viết một Window Listener
Các sự kiện của Window được phát ra sau khi Window mở, đóng, thu nhỏ, phóng to,
hoạt động và không hoạt động.
Các phương thức, sự kiện của Window
Giao diện WindowListener và lớp mô phỏng tương ứng, WindowAdapter, chứa
các phương thức sau:
void windowOpened(WindowEvent)
được gọi au khi Window được mở lần đầu.
void windowClosing(WindowEvent)
được gọi sau khi người sử dụng đóng Window.
void windowClosed(WindowEvent)
được gọi sau khi Window đóng lại.
void windowIconified(WindowEvent)
void windowDeiconified(WindowEvent)
được gọi sau khi Window phóng to hay thu nhỏ.
void windowActivated(WindowEvent)
void windowDeactivated(WindowEvent)
được gọi sau khi Window hoạt động hay không hoạt động.
Ví dụ về Handling Window Events
public class WindowEventDemo ... implements WindowListener {
...//where initialization occurs:
//Create but don't show window.
window = new Frame("Window Event Window");
window.addWindowListener(this);
window.add("Center",
new Label("The applet listens to this window"
" for window events."));
window.pack();
}
9095883.doc 55
Giáo trình Java
9095883.doc 56
Giáo trình Java
9095883.doc 57
Giáo trình Java
JLabel label;
9095883.doc 58
Giáo trình Java
rocketship.gif:
starfield.gif:
Và đây là giao diện của applet. Cần lưu ý là để khởi động hay dừng applet thì
click chuột lên applet.
This is a picture of the applet's GUI. To run the applet, click the picture. The
applet will appear in a new browser window.
9095883.doc 59
Giáo trình Java
(compWidth - imageWidth)/2,
(compHeight - imageHeight)/2, this);
}
Mã của ví dụ này có trong tập tin ImageSequenceTimer.java, ví dụ này đơn
giản hơn ví dụ vừa mô tả ở trên, chỉ đơn giản là tạo một vòng lặp để hiển thị
9095883.doc 60
Giáo trình Java
thứ tự hết hình này đến hình kia thay vì di chuyển một hình ảnh. Dưới đây là
sự khác biệt đó:
. . .//In initialization code:
Image[] images = new Image[10];
for (int i = 1; i <= 10; i++) {
images[i-1] = getImage(getCodeBase(),
"images/duke/T"+i+".gif");
}
9095883.doc 61
Giáo trình Java
Chương trình MTImageSequenceTimer.java là một ví dụ về việc sử dụng
phương thức MediaTracker waitForAll và checkAll. Applet vẫn hiển thị dòng
chữ "Please wait..." cho đến khi tất cả các hình ảnh đều được nạp đầy đủ.
Những thay đổi về mã dưới đây sử dụng MediaTracker để hiển thị hình ảnh.
Những sự khác nhau được in đậm.
...//Where instance variables are declared:
MediaTracker tracker;
9095883.doc 62
Giáo trình Java
Tăng tốc việc nạp hình ảnh (Speeding Up Image Loading)
Cho dù có hay không sử dụng MediaTracker, việc nạp hình ảnh sử dụng
URLs (cách các applets thờng làm) luôn luôn tốn nhiều thời gian. Hầu hết thời
gian ấy là để khởi tạo sự kết nối HTTP. Mỗi một tập tin hình ảnh đòi hỏi một
kết nối HTTP khác nhau, và mỗi một kết nối ấy có thể tiêu tốn vài giây để khởi
tạo. Cho nên, thời gian kéo dài là chuyện đương nhiên.
Cách thức để tránh xãy ra phiền phức trên là nên đặt tất cả các hình ảnh vào
trong một tập tin ảnh. Có thể sử dụng tập tin JAR để thực hiện điều này.
5. Giải quyết các vấn đề về đồ hoạ
Mô tả một vài vấn đề liên quan đến đồ hoạ, giải pháp để giải quyết các vấn đề
này.
9095883.doc 63
Giáo trình Java
Bài 7: Chuyển đổi qua Swing
Trong bài này sẽ trình bày cách thức để chuyển đổi một chương trình từ AWT
sang sử dụng các thành phần Swing. Nếu một chương trình được viết để sử
dụng với JDK 1.0, nghĩa là thay vì sử dụng hệ thống các sự kiện listening được
giới thiệu trong JDK 1.1 thì lại sử dụng các phương thức như là
handleEvent và action, lúc đó, điều trước tiên là chuyển đổi chương trình
để sử dụng hệ thống các sự kiện mới hơn.
1. Tại sao phải chuyển đối
Các thành phần Swing cung cấp cho các nhà lập trình và người dùng đầu cuối
nhiều thuận tiện. Trừ khi bạn có một lý do nào đó thật chính đáng, còn lại thì
tất cả nên chuyển đổi sang sử dụng các thành phần Swing.
The strongest reason to convert to Swing is because it offers many benefits to
programmers and end users. Among them:
The rich set of ready-made components means that you can easily add some
snazzy features to your programs -- image buttons, tool bars, tabbed panes,
HTML display, images in menu items, color choosers, ... The list goes on and
on.
You might be able to replace or reimplement some custom components with
more reliable, extensible Swing components.
Having separate data and state models makes the Swing components highly
customizable, and enables sharing data between components.
Swing's Pluggable Look & Feel architecture gives you a wide choice of look-
and-feel options. Besides the usual platform-specific looks and feels, you can
also use the Java Look & Feel, add an accessory look and feel (such as an
audio "look and feel"), or use a third-party look and feel.
Swing components have built-in support for accessibility, which makes your
programs automatically usable with assistive technologies.
The Swing components will continue to be enhanced in the future.
It's reasonable to put off converting if you don't think your users will be able
run Swing programs conveniently. For example, if your program is an applet
and you want anyone on the Internet to be able to use it, then you have to
consider how many Web surfers have browsers that can run Swing programs.
As of this writing, the major browsers don't have Swing support built in; the
user must add it by downloading and installing Java Plug-in .
You have the choice of upgrading to Java 2 (JDK 1.2) when you convert to
Swing. However, you don't need to decide right now whether to upgrade.
Programs written with JDK 1.1 and Swing generally work just fine in Java 2.
9095883.doc 64
Giáo trình Java
For information about new and improved features of Java 2, see Tables of JDK
Features .
2. Chuyển đổi như thế nào?
Trong phần này sẽ phác thảo về trình tự các bước của việc chuyển đổi chương
trình của bạn sang dùng các thành phần Swing. Việc chuyển đổi này được áp
dụng giống nhau cho cả ứng dụng và applets, trừ phi có những lưu ý khác.
Hoàn toàn tốt đẹp khi thực hiện việc chuyển đổi một chương trình AWT sử
dụng JDK 1.1.
Sau đây là trình tự các bước:
Bước 1: Lưu dự phòng một bản copy của chương trình sẽ chuẩn bị chuyển đổi.
Copy tất cả các tập tin của chương trình, kể cả tập tin .java và .class. Những
bản copy này sẽ hữu dụng cho chung sta trong một số trường hợp sau:
- Cần tham chiếu đến phần mã nguồn trong quá trình chuyển đổi diễn ra.
- Sau khi chuyển đổi, có thể chạy cả hai bản để có thể so sánh giữa chúng với
nhau.
- Một vài chương trình người dùng có thể chưa sẵn sàng nâng cấp VM lên
phiên bản có hỗ trợ lớp Swing. Do đó, có thể là tạm thời sử dụng chương trình
với AWT.
Bước 2: Xoá bỏ tất cả những tham chiếu đến gói java.awt.
Trong bước này, trình biên dịch sẽ làm việc cho bạn. Để thực hiện việc này,
cần vô hiệu tất cả các dòng import hoặc các đoạn lệnh liên quan đến gói
java.awt, trình bêin dịch sẽ nhắc nhở mỗi khi ta dùng một vài lớp nàp đó của
gói AWT. Tuy nhiên, vẫn có một vài lớp thuộc gói AWT vẫn dùng được, ví dụ
như layout managers, nhưng tốt nhất thì chương trình của bạn không nên dùng
các thành phần của AWT. Sau đây là một đoạn lệnh cần được xoá bỏ:
//import java.awt.*; //temporarily remove this import
or
//import java.awt.Button; //temporarily remove this import
import java.awt.Color; //it's OK to leave this in, since
//Color isn't a component
...
/*java.awt.*/Frame = new /*java.awt.*/Frame(...);
9095883.doc 65
Giáo trình Java
Trường hợp không có tham chiếu đến gói AWT, tình biên dịch sẽ phát một lỗi
"not found" khi phát hiện trong chương trình có sử dụng các thành phần AWT.
Điều này giúp cho việc chuyển đổi dẽ dàng hơn là phải ngồi dò từng dòng lệnh
trong cái rừng mà bạn vừa mới tạo ra. Lúc đó, chỉ việc thay đổi các thành phần
AWT sang các thành phần Swing một cách dễ dàng. Trong bước thứ 9, ta sẽ
tìm hiểu cách thêm vào lại các lớp thuộc gói AWT nếu cần.
Step 3: Nếu chương trình là một applet, gở bỏ dòng lệnh import java.applet.*
(nếu có) và bất kỳ tham chiếu nào liên quan đến java.applet.Applet.
Ta không cần tham chiếu đến lớp Applet vì Swing applet đã trở thành một lớp
con của lớp JApplet của Swing. Nếu chương trình đang sử dụng
AppletContext, AppletStub, hoặc AudioClip thì cần phải giữ lại những lớp này
trong gói java.applet. Sau đây là một ví dụ:
//import java.applet.*; //temporarily remove this import
import java.applet.AppletContext; //add this if necessary
Bước 4: Import the gói Swing.
Thêm dong fllẹnh sau đay vào chương trình.
import javax.swing.*;
Dòng lệnh sẽ imports các thành phần Swing cùng với một số lớp Swing khác.
Bước 5: Kiểm nhận một tiến trình an toàn!
Trước khi tiếp tục, cần lưu ý rằng: Although AWT is thread-safe, Swing is not.
Hầu hết các chương trình đều định nghĩa các thành phần trong các phương thức
event-handling và painting, là nhưng phương thức được gọi từ tiến trình event-
dispatching. Định nghĩa một thành phần trong nhưng phương thức là an toàn.
Tuy nhiên, nếu chương trình cần định nghĩa một thành phần ở bất cứ nơi nào
khác nữa, ví dụ như trong một tiến trình chính sau khi GUI đã hiển thị, hoặc
trong mã lệnh, thì nhất thiết phải làm cho nó là thread-safe.
Bước 6: Thay đổi mỗi thành phần AWT thành những thành phần Swing tương
ứng.
Trong nhiều trường hợp, các thành phần AWT và các thành phần Swing tương
ứng đều tương thích về mã lệnh, chỉ cần thay đổi rất đơn giản về tên gọi của
các thành phần mà thôi. Ví dụ như để thay đổi môt AWT button sang một
Swing button, chỉ cần thực hiện như trong bảng dưới đây:
AWT Code:
Button button = new Button("A
Button");
9095883.doc 66
Giáo trình Java
button.addActionListener(this);
Swing Code:
JButton button = new JButton("A
Button");
button.addActionListener(this);
Một vài thành phần Swing có mã nguồn không tương thích với thành phần
AWT tương ứng. Do đó, có một vài thành phần AWT phải viết lại mã lệnh khi
chuyển sang sử dụng các thành phần Swing.
Bước 7: Chuyển đổi cách gọi phương thức add và setLayout.
Chương trình sử dụng các thành phần AWT, ta có thể thêm trực tiếp các thành
phần AWT vào trong frames, dialogs, và applets. Tương tự, ta cũng có thể xác
lập các layout manager trực tiếp vào các đối tượng chứa trên. Trong trường hợp
ngược lại, khi sử dụng các phiên bản Swing có chứa các đối tượng trên, khi
thêm các thành phần thì gọi content pane. Các ví dụ đơn giản sau:
AWT Code:
frame.add(panel, BorderLayout.CENTER);
Swing Code:
frame.getContentPane().add(panel,
BorderLayout.CENTER);
Và đây là phần chi tiết:
AWT Code:
frame.setLayout(new FlowLayout());
frame.add(button);
frame.add(label);
frame.add(textField);
Swing Code:
Container contentPane =
frame.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(button);
contentPane.add(label);
contentPane.add(textField);
Đoạn mã sau minh hoạ cách chuyển đổi mã của một applet. Chú ý rằng layout
manager mặc định của một content pane là BorderLayout chứ không phải
FlowLayout được sử dụng trong Applet.
9095883.doc 67
Giáo trình Java
AWT Code:
setLayout(new BorderLayout());
add(button, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
Swing Code:
Container contentPane = getContentPane();
contentPane.add(button,
BorderLayout.NORTH);
contentPane.add(panel,
BorderLayout.CENTER);
Bước 8: Di chuyển mã lệnh của việc vẽ ra khỏi các phương thức paint và
update.
Với các thành phần Swing, việc thực hiện painting trong mã lênh được thể hiện
trong phương thức paintComponent. Cách khác để thực hiện painting là sử
dụng các icon chuẩn hoặc tự tạo và đường viền.
Nếu trong chương trình có các lớp con Frame, Dialog, hoặc Applet thực thi
việc làm tươi hay vẽ thì cần phải di chuyển các mã lệnh vào trong một thành
phần khác. Còn việc xác định chính xác thành phần nào thì lại phụ thuộc kiểu
của painting. Nếu một đối tượng chứa có thể thực hiện một icon thì có thể thay
thế thành phần đó bằng một label. Ngoài ra, các thành phần khác có thể thay
thế bởi các lớp con của lớp Jpanel. Có thể thêm các thành phần vào các content
pane của frame, dialog, hoặc applet như đã mô tả ở bước 7.
Bước 9: Sử dụng trình biên dịch để tìm kiếm các thay đổi cần thiết khác.
Sau khi đã phần mã nguồn như đã mô tả ở các bước trên, nên sử dụng trình
biên dịch để vừa biên dịch vừa kiểm tra lại chương trình. Không nên sử dụng
trình biên dịch trong lần đầu đối với chương trình của mình mà chưa có sự
chỉnh sửa nào cả.
Trình biên dịch giúp chúng ta các công việc như sau:
Tìm kiếm các thành phần AWT mà chúng ta đã bỏ sót trong quá trình chuyển
đổi sang Swing. Nếu như ta đã xoá tất cả các dòng lệnh tham chiếu đến
java.awt như ở bước 2 thì trình biên dịch sẽ xuất hiện câu thông báo lỗi như
sau:
TextEventDemo.java:23: Class Button not found
Trong phần khai báo.
Button button = new Button("Clear");
^
9095883.doc 68
Giáo trình Java
Đến thời điểm này, viêc nhận dạng các lớp AWT trong chương trình vẫn còn
cần thiết. Nếu như ta đã xoá tất cả các dòng lệnh tham chiếu đến java.awt, trình
biên dịch hiển thị thông báo như sau:
TextEventDemo.java:17: Class BorderLayout not found
Trong phần khai báo.
BorderLayout layout = new BorderLayout();
^
Các lớp AWT có thể vẫn còn được sử dụng bởi Swing trong chương trình.
Bước 10: Chạy chương trình Swing.
Thực hiện giống như đã mô tả trong phần biên dịch và chạy chương trình
Swing. Chương trình sẽ phát ra lỗi trường hợp chúng ta không nhớ thêm vào
hay setLayout, các lỗi như sau:
java.lang.Error: Do not use javax.swing.JFrame.add() use
javax.swing.JFrame.getContentPane().add() instead
at javax.swing.JFrame.createRootPaneException(JFrame.java:333)
at javax.swing.JFrame.addImpl(JFrame.java:355)
at java.awt.Container.add(Container.java:212)
at AppletDemo.main(AppletDemo.java:121)
Quay trở lại phần mã nguồn và điều chỉnh các phần cho phù hợp.
Bước11: So sánh hai chương trình Swing và AWT, cải tiến chương trình theo
khả năng của Swing.
Mặc dù các phiên bản của Swing và AWT là giống nhau, nhưng việc cải tiến
triệt để theo Swing là cần thiết. Cần lưu ý là có một khác biệt, trừ khi bạn thực
hiện việc copy bản JDK với tập tin swing.properties đã được xác lập, còn lại
thì hầu hết chương trình đều sử dụng một look and feel mới: the Java Look &
Feel. Ta có thể xác lập một look and feel khác nếu muốn.
Step 12: Clean up!
Bây giờ là lúc tinh gọn phần mã lệnh.
9095883.doc 69