Bài giảng Lập trình hướng đối tượng - Bài 9: Tiếp tục cải tiến chương trình đồ họa liệt kê các số nguyên tố - Lê Hồng Phư

Nội dung

● Tiếp tục cải tiến chương trình liệt kê các số nguyên

tố trong bài giảng trước:

– Lập trình đa luồng trong ứng dụng đồ họa:

● Luồng đồ họa

● Luồng công việc

– Sử dụng ProgressMonitor

– Sử dụng SwingWorker

– Sử dụng PropertyChangeListener

pdf 20 trang phuongnguyen 7280
Bạn đang xem tài liệu "Bài giảng Lập trình hướng đối tượng - Bài 9: Tiếp tục cải tiến chương trình đồ họa liệt kê các số nguyên tố - Lê Hồng Phư", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Bài giảng Lập trình hướng đối tượng - Bài 9: Tiếp tục cải tiến chương trình đồ họa liệt kê các số nguyên tố - Lê Hồng Phư

Bài giảng Lập trình hướng đối tượng - Bài 9: Tiếp tục cải tiến chương trình đồ họa liệt kê các số nguyên tố - Lê Hồng Phư
Bài 9: Tiếp tục cải tiến chương trình 
đồ họa liệt kê các số nguyên tố
Lê Hồng Phương, 
Nguyễn Việt Hùng, Hà Mỹ Linh
phuonglh@gmail.com
Khoa Toán-Cơ-Tin học
Trường Đại học Khoa học Tự nhiên Hà Nội
2012-2013 Object-Oriented Programming: Collections 2
Nội dung
● Tiếp tục cải tiến chương trình liệt kê các số nguyên 
tố trong bài giảng trước:
– Lập trình đa luồng trong ứng dụng đồ họa: 
● Luồng đồ họa
● Luồng công việc
– Sử dụng ProgressMonitor
– Sử dụng SwingWorker
– Sử dụng PropertyChangeListener
2012-2013 Object-Oriented Programming: Collections 3
Nguyên tắc tách luồng
● Khi lập trình các ứng dụng có giao diện đồ họa, ta 
cần chú ý nguyên tắc tách luồng:
– Luồng đồ họa: vẽ, cập nhật các thành phần đồ 
họa, nhận các sự kiện bấm phím, kích chuột...
– Luồng công việc: sử dụng để chạy các tác vụ 
cần nhiều thời gian để thực hiện.
● Chú ý: luồng đồ họa còn được gọi là luồng phân phối 
sự kiện: Event Dispatch Thread – EDT. Mọi ứng 
dụng đồ họa đều chạy trong một luồng đồ họa.
2012-2013 Object-Oriented Programming: Collections 4
Nguyên tắc tách luồng
● Trong chương trình liệt kê số nguyên tố ở bài giảng 
trước, ta không tách luồng.
● Nếu người dùng nhập vào số n lớn cỡ hàng trăm triệu thì 
tác vụ liệt kê số nguyên tố sẽ mất nhiều thời gian.
● Trong thời gian chờ tính toán, giao diện đồ họa của 
chương trình không hoạt động: 
– Người dùng không thể chọn thực đơn hay thực hiện 
bất kì công việc nào khác trên giao diện.
– Lí do: luồng đồ họa đang bận tính toán!
2012-2013 Object-Oriented Programming: Collections 5
Nguyên tắc tách luồng
● Ta cần cải tiến chương trình với cách giải quyết cơ bản:
– Viết một luồng công việc có nhiệm vụ liệt kê các số 
nguyên tố, chạy tách riêng khỏi luồng đồ họa.
– Khi nào luồng công việc thực hiện xong nhiệm vụ, trả 
về kết quả thì sẽ thực hiện cập nhật kết quả trên giao 
diện bằng luồng đồ họa.
● Trong thực tế, không nhất thiết phải chờ luồng công việc 
chạy xong, có kết quả toàn bộ mới thực hiện cập nhật đồ 
họa.
– Cập nhật dần dần giao diện, sử dụng kết quả trung 
gian → Tăng tính tương tác của chương trình.
2012-2013 Object-Oriented Programming: Collections 6
Cách giải quyết cơ bản
● Với cách giải quyết cơ bản, ta chỉ cập nhật giao diện khi 
luồng công việc kết thúc. 
– Tăng cường tính tương tác bằng cách sử dụng một 
thanh tiến trình (JProgressBar) hoặc một hộp thoại 
tiến trình (ProgressMonitor) chỉ định mức độ hoàn 
thành tác vụ của luồng công việc.
– Nếu dùng ProgressMonitor, người dùng có thể ngắt 
luồng công việc giữa chừng bằng cách nhấn nút 
Cancer.
2012-2013 Object-Oriented Programming: Collections 7
ProgressMonitor
● Với những số n nhỏ thì 
chương trình chạy 
nhanh, hộp thoại tiến 
trình không xuất hiện.
● Nhập số n lớn, hộp 
thoại tiến trình sẽ xuất 
hiện.
progressMonitor = new ProgressMonitor(
PrimeNumberFrame.this, 
"Computing prime numbers...", "", 0, 100);
private ProgressMonitor progressMonitor;
Một trường của lớp 
PrimeNumberFrame
2012-2013 Object-Oriented Programming: Collections 8
Nguyên tắc cập nhật đồ họa
● Việc cập nhật trạng thái của các thành phần đồ họa 
cần phải được thực hiện trong luồng đồ họa.
● Nếu luồng công việc thực hiện chức năng cập nhật 
các thành phần đồ họa thì sẽ sinh ngoại lệ – chương 
trình bị lỗi.
● Lớp SwingWorker giúp lập trình viên quản lí cả luồng 
công việc và cập nhật đồ họa, tránh gây lỗi.
2012-2013 Object-Oriented Programming: Collections 9
​Luồng khởi tạo
● Khi bắt đầu chương trình đồ họa, chương trình luôn xuất 
phát từ luồng bắt đầu, hay luồng khởi tạo (initial thread). 
● Nhiệm vụ của luồng này là tạo một đối tượng Runnable 
để sinh giao diện cho chương trình và chuyển đối tượng 
đó vào chạy trong luồng đồ họa.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
PrimeNumberFrame app = new PrimeNumberFrame();
app.pack();
app.setVisible(true);
}
});
Ở đây, ta sử dụng lớp nội 
không tên cài đặt giao diện
Runnable. (Chương trình 
gọn hơn) 
2012-2013 Object-Oriented Programming: Collections 10
Luồng đồ họa
● Sau khi luồng đồ họa khởi động thì chương trình được 
điều khiển bởi luồng này. 
● Chương trình hoạt động theo nguyên tắc: nhận sự kiện 
→ xử lí sự kiện.
● Ví dụ:
– Bấm phím Ok → liệt kê các số nguyên tố
– Chọn mục thực đơn Exit → thoát chương trình
– Chọn mục thực đơn About → mở hộp thoại About
2012-2013 Object-Oriented Programming: Collections 11
Luồng công việc
● Luồng công việc (worker thread hay background thread) 
được sử dụng để thực hiện các tác vụ chậm.
● Mỗi luồng công việc được biểu diễn bởi một đối tượng 
thuộc lớp javax.swing.SwingWorker. 
– Đây là một lớp trừu tượng, ta cần tạo lớp con kế thừa 
lớp này.
● Lớp SwingWorker cung cấp các phương thức hữu ích 
sau.
2012-2013 Object-Oriented Programming: Collections 12
Luồng công việc
● Phương thức doInBackground thực hiện tác vụ, trả 
về kết quả để dùng trong các luồng khác (thường là 
dùng trong luồng đồ họa)
● Phương thức done chứa các lệnh được thực hiện 
trong luồng đồ họa khi thực hiện xong tác vụ.
2012-2013 Object-Oriented Programming: Collections 13
Luồng công việc
● Chú ý:
– Phương thức doInBackground cũng có thể trả các 
kết quả trung gian bằng cách gọi phương thức 
publish; 
– Phương thức process chứa các lệnh được thực 
hiện trong luồng đồ họa để cập nhật dần giao 
diện.
● Trong chương trình ví dụ, ta không sử dụng các kết 
quả trung gian nên không dùng publish và process.
2012-2013 Object-Oriented Programming: Collections 14
Luồng công việc
● Luồng công việc còn định nghĩa một số thuộc tính, trong 
đó nếu giá trị của các thuộc tính này thay đổi thì sẽ làm 
phát siinh sự kiện thuộc kiểu PropertyChangeEvent.
– Ta quan tâm tới thuộc tính progress. 
– Để thay đổi giá trị của thuộc tính này, ta gọi phương 
thức setProgress. 
● Xử lí sự kiện PropertyChangeEvent bằng cách 
– Viết một lớp cài đặt giao diện PropertyChangeListener
– Gọi phương thức addPropertyChangeListener.
2012-2013 Object-Oriented Programming: Collections 15
class PrimeEnumerationTask extends SwingWorker {
private int n;
private DefaultListModel listModel;
public PrimeEnumerationTask(int n) {
super();
this.n = n;
listModel = new DefaultListModel();
}
@Override
protected DefaultListModel doInBackground() throws IOException {
PrimeNumbers pn = new PrimeNumbers();
setProgress(0);
int k = 2;
while (k <= n && !isCancelled()) {
if (pn.isPrime(k)) {
listModel.addElement(k);
}
setProgress(100 * k / n);
k++;
}
return listModel;
}
// more code goes here...
}
Kết quả trung gian 
(từng số nguyên tố)
Không được cập nhật 
giao diện đồ họa ở đây!
2012-2013 Object-Oriented Programming: Collections 16
class PrimeEnumerationTask extends SwingWorker {
// more code goes here...
@Override
protected void done() {
// update the UI in the EDT
okButton.setEnabled(true);
primeList.setModel(listModel);
}
}
Các lệnh trong done sẽ được 
chạy trong luồng đồ họa khi 
luồng công việc kết thúc
class EnumeratePrimeNumbersListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
// some code... 
progressMonitor = new ProgressMonitor(
PrimeNumberFrame.this, "Computing prime numbers...", 
"", 0, 100);
progressMonitor.setProgress(0);
task = new PrimeEnumerationTask(n);
task.addPropertyChangeListener(new
 ProgressPropertyChangeListener());
task.execute();
okButton.setEnabled(false);
}
}
Tạo và thực hiện tác vụ 
trong luồng công việc
2012-2013 Object-Oriented Programming: Collections 17
class ProgressPropertyChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getPropertyName().equals("progress")) {
int progress = (Integer) event.getNewValue();
progressMonitor.setProgress(progress);
progressMonitor.setNote("" + progress + "%");
 if (progressMonitor.isCanceled() || task.isDone()) {
 Toolkit.getDefaultToolkit().beep();
 if (progressMonitor.isCanceled()) {
 task.cancel(true);
 System.out.println("Task canceled.");
 } else {
 System.out.println("Task completed.");
 }
 okButton.setEnabled(true);
 }
}
}
}
Cập nhật tiến trình
thực hiện tác vụ
Bật lại nút Ok nếu tác vụ bị hủy 
giữa chừng hoặc đã thực hiện xong
2012-2013 Object-Oriented Programming: Collections 18
Chương trình
● Xem các tệp mã nguồn trong gói lecture8.primes4
– ​LookAndFeelLister.java
– PrimeNumberApp.java
– PrimeNumberFrame.java
– PrimeNumbers.java
– PrimeNumberIO.java
2012-2013 Object-Oriented Programming: Collections 19
Tiếp theo...
● Ta có thể tiếp tục cải tiến chương trình theo hướng 
làm chương trình trực quan sinh động hơn: 
– Tìm được số nguyên tố nào thì cập nhật dần kết 
quả vào danh sách luôn, không đợi tìm hết mọi số 
mới cập nhật toàn bộ danh sách.
– (Bài tập về nhà)
● Gợi ý: Sử dụng các phương thức publish và process.
2012-2013 Object-Oriented Programming: Collections 20
Tham khảo thêm
● Concurrency in Swing:
– 
index.html
● How to use progress bars
– 
progress.html
● How to write a property change listener:
– 
tychangelistener.html
● Creating a GUI with JFC/Swing:
–  

File đính kèm:

  • pdfbai_giang_lap_trinh_huong_doi_tuong_bai_9_tiep_tuc_cai_tien.pdf