Cái tên JFC - Java Foundation Classes
được Oracle
sử dụng để nói về nhóm các class
dựng sẵn hỗ trợ vẽ giao diện đồ họa người dùng trong thư viện tiêu chuẩn của Java SE
. Nhóm này còn được xem là một framework
với tên gọi khác là AWT Swing
do được tạo thành bởi các package
chủ đạo là java.awt
và javax.swing
.
Trong đó thì java.awt
cung cấp các class
nền tảng để hỗ trợ vẽ các thành phần giao diện đồ họa người dùng theo ý muốn, còn javax.swing
là phần mở rộng được xây dựng dựa trên java.awt
và cung cấp đầy đủ các thành phần phổ biến như các nút nhấn Button
, ô đánh dấu Checkbox
hoặc Radiobox
, v.v... với giao diện lập trình thân thiện hơn. Chúng ta sẽ tìm hiểu về bộ công cụ này dựa theo các thành phần thường xuất hiện trong các giao diện cửa sổ ứng dụng và ngược dòng trong tập tài liệu của Oracle
để tìm hiểu về những class
liên quan.
Tạo cửa sổ ứng dụng
class
javax.swing.JFrame
java.lang.Object java.awt.Component java.awt.Container java.awt.Window java.awt.Frame javax.swing.JFrame
implements
java.awt.image.ImageObserver
,
java.awt.MenuContainer
,
java.io.Serializable
,
javax.accessibility.Accessible
,
javax.swing.RootPaneContainer
,
javax.swing.WindowConstants
Do chúng ta đang dự định vẽ giao diện người dùng độc lập chứ không ở trong không gian trình duyệt web nên câu hỏi đầu tiên xuất hiện đó là: Làm thế nào để tạo ra một cửa sổ ứng dụng? Rồi sau đó chúng ta mới có thể nghĩ tới việc đặt vào cửa sổ ứng dụng này các thành phần tương tác với người dùng như hiển thị thông tin hay các tùy chọn, nút nhấn, v.v...
import javax.swing.*; class App { private static JFrame window; public static void main (String[] $args) { App.createWindow (); App.displayWindow (); } public static void createWindow () { App.window = new JFrame (); // -- App.window.setTitle ("Empty Window"); // -- int $width = 800; int $height = 500; App.window.setSize ($width, $height); // -- App.window.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } public static void displayWindow () { App.window.setVisible (true); } } // -- App
screenshot
Ok.. code tạo cửa sổ ứng dụng độc lập khá đơn giản. Ở đây chúng ta có một vài điểm đáng lưu ý là cửa sổ ứng dụng sẽ bắt đầu được vẽ ra màn hình khi câu lệnh $window.setVisible (true);
được thực thi. Vì vậy nên thường thì tất cả các câu lệnh khác sẽ mang tính thiết lập các thành phần, bố cục hiển thị, code đáp ứng sự kiện người dùng, v.v... nên được đặt trước câu lệnh này.
Bổ sung các thành phần
class
javax.swing.JPanel
class
javax.swing.JButton
Tất cả các class
mô phỏng các thành phần tạo nên giao diện đồ họa tương tác với người dùng đều bắt đầu từ class java.awt.Component
trong dòng kế thừa của JFrame
ở phần trên. Các object Component
sẽ có thể được đặt vào bên trong các khung chứa Container
được định nghĩa bởi class java.awt.Container
cũng đã xuất hiện trong dòng kế thừa ở phần trên. Và bởi các Container
cũng được xem là Component
nên chúng ta sẽ có thể đặt một Container
vào trong một Container
khác để cấu trúc nên giao diện người dùng tùy ý.
Điểm khác biệt căn bản so với khi sử dụng bộ ngôn ngữ vẽ giao diện nền web, đó là khi sử dụng HTML
thì trình duyệt web được lập trình sẵn để tách nội dung đánh dấu từ HTML
và tạo thành các object
trong môi trường JS
; Còn ở đây chúng ta sẽ phải tạo ra từng object
và thực hiện xếp lớp các object
để cấu trúc nên giao diện người dùng.
import javax.swing.*; class App { private static JFrame window; public static void main (String[] $args) { App.createWindow (); App.addComponents (); App.displayWindow (); } public static void createWindow () { ... } public static void addComponents () { JPanel $panel = new JPanel (); JButton $button = new JButton ("Clickable"); // -- $panel.add ($button); App.window.add ($panel); } public static void displayWindow () { ... } } // -- App
Trong code ví dụ này thì chúng ta đang tạo ra một khung chứa tạm JPanel
kiểu như <div>
trong HTML
để nhóm các thành phần liên quan và tạo ra một bố cục trang đơn cần hiển thị. Như vậy khi muốn thay đổi bố cục trang đơn thì chúng ta sẽ không cần phải mở thêm một cửa sổ JFrame
khác và đóng cửa sổ hiện tại.
screenshot
Lúc này chúng ta thấy rằng đã xuất hiện cấu trúc xếp lớp các Component
và khi cần chỉnh sửa nội dung hiển thị của một Component
nào đó, ví dụ như phần chữ hiển thị bên trong nút nhấn kia, thì chúng ta sẽ phải truy xuất được Component
đó từ object window
. Và đứng từ vị trí của mỗi Container
thì chúng ta sẽ chỉ có thể truy xuất tới lớp Component
nội tại gần nhất bằng các phương thức:
$container.getComponents ();
- truy xuất mảng tất cả cácComponent
nội tại.$container.getComponent ($index);
- truy xuất mộtComponent
tại trị số$index
được thiết lập bởi thao tác$container.add ($component, $index);
Trong trường hợp muốn sử dụng phương thức đầu tiên sau đó tự sàng lọc để tìm Component
cần chỉnh sửa thì chúng ta có thể đặt tên cho mỗi Component
ở thời điểm khởi tạo bằng phương thức $component.setName ("name")
.
Một cách xử lý khác, đó là chúng ta cũng có thể định nghĩa các class
mở rộng các JComponent
và bổ sung các trường lưu lại địa chỉ tham chiếu của các Component
cần sử dụng. Cách thức này được xem là phù hợp nhất đối với các Component
phức hợp có số lượng thành phần bên trong cố định và trong trường hợp chúng ta cần quản lý nhiều đoạn code xử lý sự kiện. Ở đây mình sẽ tạm thời cấu trúc lại code ví dụ đã có với các tệp như sau:
[learn-java] ├── App.java └── [view] ├── StartPage.java └── Window.java
Ở lớp cửa sổ ứng dụng thì tạm thời chúng ta sẽ chỉ cần lưu lại địa chỉ tham chiếu của một JPanel
duy nhất được xem là giao diện của một trang đơn page
cần hiển thị trong cửa sổ ứng dụng. Chúng ta sẽ có các class
mô tả các giao diện trang đơn khác nhau và ở một thời điểm thì sẽ chỉ có một object
biểu thị trang đơn được sử dụng. Khi tạo ra một object
mô phỏng trang đơn khác để chuyển bố cục thì object
mô phỏng trang đơn hiện tại sẽ được xóa đi để giảm tải cho bộ nhớ đệm RAM
.
package view; import javax.swing.*; public class Window
extends JFrame { JPanel page; public Window () { super (); // -- int $width = 800; int $height = 500; this.setSize ($width, $height); // -- this.page = new StartPage (); this.add (this.page); // -- this.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); } public void display () { this.setVisible (true); } } // -- class
Ở đây bố cục trang đơn mở đầu một ứng dụng ví dụ là StartPage
. Việc thay đổi nội dung chữ của một nút nhấn thực ra không cần thiết vì vậy nên mình quyết định không tạo thêm trường lưu lại tham chiếu của JButton
để truy xuất nhanh.
package view; import javax.swing.*; class StartPage
extends JPanel { StartPage () { JButton $button = new JButton ("Clickable"); this.add ($button); } } // -- class
Và ở tệp khởi động đại diện cho ứng dụng, do chưa có logic xử lý back-end
nên chúng ta cũng chưa cần lưu lại địa chỉ của Window
được tạo ra.
import view.*; class App { public static void main (String[] $args) { Window $window = new Window (); $window.display (); } } // -- App
Trong tất cả các ví dụ ở các bài viết tiếp theo về JFC
, chúng ta sẽ chỉnh sửa cập nhật dần dần từ cấu trúc code này thay vì tạo ra các ví dụ hoàn toàn mới.
Bố cục của các Container
Khi tạo ra một Component
bất kỳ, cứ miễn rằng đó là một Container
, thì chúng ta sẽ có thể thực hiện thiết lập logic dàn chỉnh bố cục cho các thành phần bên trong Container
đó bằng phương thức $container.setLayout ($layout);
. Trong đó thì $layout
là một object
được tạo ra từ một trong các class
sau:
java.awt.FlowLayout
- được sử dụng mặc định, đặt các thành phần theo một dòng hiển thị từ trái qua phải (mặc định), hoặc từ phải qua trái.java.awt.BorderLayout
- sắp xếp các thành phần theo các hướng và trung tâm.java.awt.CardLayout
- xếp lớp các thành phần theo dạng một tập thẻ và chỉ hiển thị một thẻ duy nhất ở mỗi thời điểm.java.awt.GridLayout
- tạo lưới hiển thị các thành phần với các ô có cùng kích thước.java.awt.GridBagLayout
- tạo lưới hiển thị các thành phần với các ô có kích thước có thể khác nhau.javax.swing.GroupLayout
- nhóm các thành phần theo các nhóm hiển thị dọc và ngang để tạo thứ tự trình bày.javax.swing.SpringLayout
- thiết lập vị trí của các thành phần tương quan vớiContainer
.
Ở phần này thì chúng ta chỉ liệt kê danh sách các kiểu bố cục và liên kết trỏ tới các trang tài liệu để có thể sử dụng khi cần tới thôi. Bây giờ thì chúng ta cần code ví dụ về mỗi thành phần cụ thể đã rồi mới có thể nghĩ tới việc tạo ra các bố cục được. Khi bắt đầu mini project
nghiệm thu, chắc chắn chúng ta sẽ cần tới những công cụ này.
(chưa đăng tải) [Object-Oriented + Java] Bài viết #10 - JFC Text Contents