Tiếp nội dung phần 1, Bài giảng Lập trình Java: Phần 2 cung cấp cho người học những kiến thức như: Lập trình đồ họa AWT; Java Applet và Swing; Lập trình đa luồng. Mời các bạn cùng tham khảo để nắm chi tiết nội dung giáo trình!
CHƢƠNG 4: LẬP TRÌNH ĐỒ HOẠ AWT 4.1 Giới thiệu AWT Các ứng dụng phần mềm thân thiện trình bày nhiều hình giao diện đồ họa đẹp Các ngơn ngữ lập trình cung cấp đối tượng đồ họa, chúng điều khiển người lập trình, hay người sử dụng Một số kết quan trọng ngơn ngữ dựa Giao diện người dùng đồ họa (Graphical User Interface - GUI) Trong chương này, ta thảo luận Java hỗ trợ tính GUI thi hành chúng GUI cung cấp chức nhập liệu theo cách thân thiện với người dùng GUI đa dạng từ ứng dụng đến ứng dụng chứa nhiều điều khiển hộp văn bản, nhãn, hộp danh sách hay điều khiển khác Các ngôn ngữ lập trình khác cung cấp nhiều cách khác để tạo GUI Các ngôn ngữ VB hay VC++ cung cấp chức kéo thả phần mềm giống C++ yêu cầu người lập trình phải viết tồn mã để xây dựng GUI Một phần tử (element) GUI thiết lập cách sử dụng thủ tục sau: Tạo đối tượng Xác định xuất ban đầu đối tượng Chỉ nằm đâu Thêm phần tử vào giao diện hình Một thành phần (component) GUI đối tượng trực quan Người dùng tương tác với đối tượng thông qua trỏ chuột hay bàn phím Các thành phần button, label … nhìn thấy hình Bất kỳ chung cho tất thành phần GUI tìm thấy lớp Component Để tạo đối tượng GUI cần nhập gói java.awt AWT viết tắt Abstract Windowing Toolkit AWT lớp Java cho phép tạo GUI chấp nhận nhập liệu người dùng thơng qua bàn phím chuột AWT cung cấp thành phần khác để tạo GUI hiệu lôi người sử dụng Các thành phần là: Vật chứa (Container) Thành phần (Component) Trình quản lý cách trình bày (Layout manager) Đồ họa (Graphic) tính vẽ (draw) Phông chữ (Font) Sự kiện (Event) Gói AWT chứa lớp, giao diện gói khác Hình sau mơ tả phần nhỏ hệ thống phân cấp lớp AWT 136 Object CheckboxGroup MenuComponent Component BorderLayout FlowLayout GridLayout Hình 4.1 Hệ thống phân cấp lớp AWT 4.2 Container (vật chứa) 4.2.1 Giới thiệu Container vùng mà bạn đặt thành phần giao diện bạn vào Bất vật mà kế thừa từ lớp Container vật chứa Applet vật chứa, Applet dẫn xuất từ Panel, lớp Panel lại dẫn xuất từ lớp Container Một vật chứa chứa nhiều phần tử, phần tử vẽ hay tơ màu tuỳ thích Bạn xem vật chứa cửa sổ Như khung (frame), panel, latch, hook, thành phần có kích thước nhỏ khác Gói java.awt chứa lớp gọi Container Lớp trực tiếp hay gián tiếp phải sinh hai vật chứa sử dụng phổ biến Frame Panel Frame Panel vật chứa thường sử dụng Frame cửa sổ độc lập ngược lại Panel vùng nằm cửa sổ khác Panel đường biên, chúng trình bày cửa sổ trình duyệt hay appletviewer cung cấp Appletviewer công cụ JDK hỗ trợ để xem Applet Frame lớp Window Chúng trình bày cửa sổ độc lập, cửa sổ có chứa đường biên xung quanh 4.2.2 Frame Frame khơng phụ thuộc vào Applet trình duyệt Frame hoạt động vật chứa hay thành phần (component) Bạn sử dụng constructor sau để tạo frame: Frame(): Tạo frame không hiển thị (invisible) Frame(String title): Tạo frame khơng hiển thị, có tiêu đề Ví dụ 4.1: Minh hoạ cách tạo Frame import java.awt.*; class FrameDemo extends Frame { public FrameDemo(String title) 137 { super(title); } public static void main(String args[]) { FrameDemo f=new FrameDemo(“I have been Frameed!!!”); f.setSize(300,200); f.setVisible(true); } } Lớp định nghĩa FrameDemo lớp lớp Frame Lớp FrameDemo có phương thức khởi tạo, phương thức khởi tạo ta cho gọi phương thức super() Nó gọi phương thức khởi tạo lớp cha (trong trường hợp Frame) Mục đích super() gọi phương thức khởi tạo lớp cha Nó tạo đối tượng lớp con, lớp tạo Frame Tuy nhiên, Frame khơng nhìn thấy khơng có kích thước Để làm điều này, ta sử dụng hai phương thức nằm phương thức main: setSize() setVisible() Kết chạy chương trình giống hình 4.2 Hình 4.2 Kết chạy ví dụ 4.1 4.2.3 Panel Panel sử dụng để nhóm số thành phần lại với Cách đơn giản để tạo panel sử dụng phương thức khởi tạo nó, hàm Panel() Ví dụ 4.2:Chỉ cách tạo panel: import java.awt.*; 138 class PanelTest extends Panel { public static void main(String args[]) { Paneltest p=new Paneltest(); Frame f=new Frame(“Testing a Panel”); f.add(p); f.setSize(300,200); f.setVisible(true); } public Paneltest() { } } Panel khơng thể nhìn thấy trực tiếp Do đó, cần thêm panel đến frame Vì ta cần tạo frame thêm Panel tạo vào Tuy nhiên, frame khơng nhìn thấy được, khơng có kích thước Chúng ta sử dụng hai phương thức phương thức main – setSize() setVisible() để thiết lập kích thước hiển thị frame Kết xuất chương trình: Hình 4.3 Kết chạy ví dụ 4.2 4.2.4 Dialog Lớp „Dialog‟ tương tự lớp Frame, nghĩa Dialog lớp lớp Window Đối tượng Dialog tạo sau: 139 Frame myframe=new Frame(“My frame”); // calling frame String title = “Title”; boolean modal = true; // whether modal or not Dialog dlg=new Dialog(myframe, title, modal); Tham số „modal‟ dialog ngăn chặn tương tác xảy đến với cửa sổ mở khác, dialog hiển thị hình Kiểu hộp thoại ngăn chặn người dùng tương tác với cửa sổ khác (của ứng dụng) hình, dialog đóng lại 4.3 Thành phần (Component) 4.3.1 Giới thiệu Một component đặt giao diện người dùng, thay đổi kích thước hay làm cho nhìn thấy, ẩn Ví dụ dùng phổ biến Textfield, Label, Checkbox, Textarea v.v… Và thành phần cao cấp khác Scrollbar, Scrollpane Dialog Tuy nhiên chúng không sử dụng thường xuyên TextField TextComponent TextArea Button C o m p o n e n t Label Checkbox List Choice Container Panel Applet Window Frame Canvas Dialog Scrollbar Hình 4.4 Các lớp thành phần Bây xét số thành phần thường sử dụng 4.3.2 Nhãn Lớp sử dụng để trình bày String Nó khơng thể sửa đổi Đây chuỗi đọc Sử dụng constructor sau để tạo label: Label() Tạo Label trống 140 Label(String labeltext) Tạo Label với nội dung cho Label(String labeltext, int alignment) Tạo Label với chế độ canh lề (alignment) , canh lề Label.LEFT, Label.RIGHT hay Label.CENTER Các phương thức sử dụng phổ biến label trình bày bảng bên dưới: Phương thức Chức setFont(Font f) Thay đổi phông chữ Label setText(String s) Thiết lập nhãn cho Label getText() Lấy nội dung nhãn Bảng 4.1 Các phương thức Label Ví dụ 4.3:Về cách sử dụng Label: import java.awt.*; class LabelTest extends Frame { Label label1=new Label(“This is just a label”); public LabelTest(String title) { super(title); add(label1); } } public static void main(String args[]) { LabelTest f=new LabelTest(“Label”); f.setSize(300,200); f.show(); } } label1=new Label(“This is just a label”); 141 Label hiển thị thêm vào Container Ở đây, Frame Container mà thành phần Label thêm vào Việc thực cách sử dụng phương thức add() Khi chạy chương trình kết hình 4.5 Hình 4.5 Kết chạy ví dụ 4.3 4.3.3 Ô văn Một Textfield vùng chứa dịng văn bản, văn hiển thị hay nhập vào người dùng Trong Java, constructor sau sử dụng để tạo Textfield: TextField(): Tạo textfield TextField(int columns): Tạo textfield với số cột cho trước TextField(String s): Tạo textfield với chuỗi văn cho trước TextField(String s, int columns): Tạo textfield với nội dung số cột cho trước Các phương thức thường sử dụng đối tượng TextField tóm tắt bảng sau: Phƣơng thức Chức setEchoChar(char) Đặt kí tự thay ký tự nhập vào setText(String s) Gán nội dung cho TextField getText() Lấy nội dung TextField setEditable(boolean) Xác định TextField có soạn thảo hay khơng Nó soạn thảo giá trị tham số truyền vào True isEditable() Xác định xem trường có mode soạn thảo hay không Giá trị trả kiểu Boolean 142 Bảng 4.2 Các phương thức TextField Ví dụ 4.4: Cách sử dụng TextField: import java.awt.*; class TextFieldTest extends Frame { TextField tf1=new TextField(30); public TextFieldTest(String title) { super(title); setLayout(new FlowLayout()); add(tf1); } public static void main(String args[]) { TextFieldTest f=new TextFieldTest(“TextField”); f.setSize(300,200); f.show(); } } Trong ví dụ nàycó sử dụng phương thức setLayout() để thay đổi cách trình bày thành phần vật chứa Layout manager có chức xếp thành phần vật chứa Kết chương trình hình bên dưới: Hình 4.6 Kết chạy ví dụ 4.4 143 4.3.4 Vùng văn Một Textarea sử dụng văn nhập vào có hai hay nhiều dịng Textarea có scrollbar TextArea trường văn soạn thảo với nhiều dòng Để tạo Textarea, làm theo bước sau: 1) Tạo đối tượng 2) Chỉ số dòng, số cột đối tượng cần có 3) Bố trí phần tử hình Trong Java, bạn sử dụng constructor sau để tạo TextArea: TextArea(): Tạo TextArea TextArea(int rows, int cols): Tạo TextArea với số lượng cột dòng cho trước TextArea(String text): Tạo TextArea với nội dung cho trước TextArea(String text, int rows, int cols): Tạo TextArea với dung, số dòng số cột cho trước Các phương thức thường sử dụng nhiều TextArea: Phƣơng thức Chức setText(String) Gán nội dung cho TextArea getText() Trả nội dung TextArea setEdiable(boolean) Xác định xem TextAreacó thể soạn thảo hay khơng TextArea soạn thảo giá trị True isEditable() Xác định xem TextArea có chế độ soạn thảo không Trả giá trị kiểu Boolean insertText(String, int) Chèn chuỗi vào vị trí cho trước replaceText(String, int, int) Thay văn nằm vị trí int, int cho trước Bảng 4.3 Các phương thức TextArea Ví dụ 4.5: Cách sử dụng TextArea: import java.awt.*; class TextAreaTest extends Frame { Label lbl=new Label(“Details”); 144 TextArea ta1=new TextArea(); public TextAreaTest(String title) { super(title); setLayout(new FlowLayout()); add(lbl); add(ta1); } public static void main(String args[]) { TextAreaTest t=new TextAreaTest(“TextArea”); t.setSize(300,200); t.show(); } } Kết chương trình hình bên dưới: Hình 4.7 Kết chạy ví dụ 4.5 4.3.5 Nút Nút ấn hay gọi nút lệnh phần thiếu GUI Sử dụng button cách dễ để nhận tác động người dùng Để tạo button, bạn làm theo bước sau: 1) Tạo phần tử Button với nhãn mục đích Button 2) Bố trí phần tử hình 3) Hiển thị phần tử hình Sử dụng hai constructor sau để tạo button Java: Button() Button(String text) 145 Ở đây, từ khóa synchronized khơng hiệu chỉnh phương thức “display()” Từ khóa sử dụng phương thức run() lớp “Target” Kết xuất hình tương tự với kết hình số 6.6 6.10.3 Ƣu điểm phƣơng thức đồng Người lập trình thường viết chương trình đơn luồng Tất nhiên số trường hợp định đa luồng khơng hiệu Ví dụ khơng làm tăng hiệu trình biên dịch Trình biên dịch Java Sun khơng chứa nhiều phương thức đồng Các phương thức đồng không thực thi tốt phương thức không đồng Các phương thức chậm từ ba đến bốn lần so với phương thức tương ứng không đồng Trong trường hợp cần hiệu cao nên hạn chế sử dụng phương thức đồng 6.11 Cơ chế đợi thông báo Luồng chia tác vụ thành đơn vị cụ thể logic Điều thay hình thức lập trình lặp kiện Các luồng loại trừ “polling” (kiểm tra liên tục) Một vòng lặp dùng để kiểm tra điều kiện gọi “polling” Khi điều kiện nhận giá trị True (đúng), câu lệnh tương ứng thực Đây tiến trình thường lãng phí thời gian CPU Ví dụ luồng sinh số liệu luồng khác chi phối luồng sinh phải đợi luồng sử dụng hồn thành trước phát sinh liệu Để tránh trường hợp polling, Java bao gồm chế giao tiếp tiến trình phương thức “wait()”, “notify()” “notifyAll()” Các phương thức thực phương thức final lớp Object, tất lớp thâm nhập chúng Tất phương thức gọi từ phạm vi phương thức đồng (synchronized) Các chức phương thức “wait()”, “notify()”, “notifyAll()” là: Phương thức wait() làm cho luồng gọi từ bỏ yêu cầu monitor, chuyển sang trạng thái “sleep” (chờ) luồng khác thơi monitor tài ngun cần (đối tượng monitor gọi phương thức “notify()”) Phương thức notify() đánh thức, thông báo cho luồng mà gọi phương thức wait() đối tượng Phương thức notifyAll() đánh thức, thông báo tất luồng mà gọi phương thức wait() đối tượng Luồng có quyền ưu tiên cao luồng chạy Cú pháp phương thức sau: 240 final void wait() throws IOException final void notify() final void notifyAll() Các phương thức wait() notify() cho phép chia sẻ đối tượng, làm tạm ngừng luồng, đối tượng trở thành khơng cịn giá trị cho luồng Chúng cho phép luồng tiếp tục thích hợp Các luồng thân khơng kiểm tra trạng thái đối tượng chia sẻ Một đối tượng mà điều khiển luồng yêu cầu theo kiểu gọi monitor Trong phạm vi Java, monitor đối tượng mà có mã đồng Các monitor sử dụng cho phương thức wait() notify() Cả hai phương thức phải gọi mã đồng Một số điểm cần nhớ sử dụng phương thức wait(): Luồng gọi trả CPU Luồng gọi mở khóa Luồng gọi vào vùng đợi monitor Các điểm cần nhớ phương thức notify() Một luồng vùng đợi monitor chuyển sang trạng thái sẵn sàng Luồng mà thông báo phải yêu cầu khóa monitor trước bắt đầu Phương thức notify() khơng xác, khơng thể luồng thơng báo Trong trạng thái trộn lẫn, luồng thay đổi trạng thái monitor mà điều làm ảnh hưởng đến luồng đưa thông báo Trong trường hợp này, phương thức monitor đưa đề phòng: o Trạng thái monitor kiểm tra vòng lặp “while” thay câu lệnh if o Sau thay đổi trạng thái monitor, phương thức notifyAll() nên sử dụng thay notify() Ví dụ 6.7: Biểu thị cho việc sử dụng phương thức notify(0 wait(): import java.applet.*; import java.awt.*; import java.awt.event.*; /* */ public class mouseApplet extends Applet implements MouseListener{ boolean click; 241 int count; public void init() { super.init(); add(new clickArea(this)); //doi tuong ve duoc tao va them vao add(new clickArea(this));//doi tuong ve duoc tao va them vao addMouseListener(this); } public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { synchronized (this) { click = true; notify(); } count++; //dem viec click Thread.currentThread().yield(); click = false; } public void mouseReleased(MouseEvent e) { } } //kết thúc Applet class clickArea extends java.awt.Canvas implements Runnable{ mouseApplet myapp; clickArea(mouseApplet mapp){ this.myapp = mapp; setSize(40,40); 242 new Thread(this).start(); } public void paint(Graphics g){ g.drawString(new Integer(myapp.count).toString(),15,20); } public void run(){ while(true){ synchronized (myapp) { while(!myapp.click){ try{ myapp.wait(); }catch(InterruptedException ie){ } } } repaint(250); } }//end run } Không cần phương thức wait() notify(), canvas biết cập nhập hiển thị Kết xuất ngồi chương trình đưa sau: Hình 6.7 Kết sau lần kích chuột 243 6.12 Khoá chết (Deadlock) Một “deadlock” xảy hai luồng có phụ thuộc vịng cặp đối tượng đồng bộ; ví dụ, luồng thâm nhập vào monitor đối tượng “ObjA”, luồng khác thâm nhập vào monitor đối tượng “ObjB” Nếu luồng “ObjA” cố gắng gọi phương thức đồng “ObjB” khố chết xảy Khó để tìm khóa chết nguyên nhân sau: Nó hiểm xảy ra, hai luồng chia nhỏ thời gian thực thi lúc Nó liên quan đến nhiều hai luồng hai đối tượng đồng Nếu chương trình đa luồng bị treo thường xuyên, kiểm tra lại điều kiện gây khố chết Ví dụ 6.8:sau tạo điều kiện khố chết Lớp bắt đầu luồng Mỗi luồng gọi phương thức đồng run() Khi luồng “t1” thức dậy, gọi phương thức “synchIt()” đối tượng deadlock “dlk2” Khi luồng “t1” monitor “dlk2”, luồng “t1” bắt đầu đợi monitor Khi luồng “t2” thức, cố gắng gọi phương thức “synchIt()” đối tượng Deadlock “dlk1” Bây giờ, “t2” phải đợi, trường hợp tương tự với luồng “t1” Từ đó, hai luồng đợi lẫn nhau, hai không thức Đây điều kiện khoá chết public class Deadlock implements Runnable{ public static void main(String args[]){ Deadlock dlk1= new Deadlock(); Deadlock dlk2 = new Deadlock(); Thread t1 = new Thread(dlk1); Thread t2 = new Thread(dlk2); dlk1.grabIt = dlk2; dlk2.grabIt = dlk1; t1.start(); t2.start(); System.out.println("Started"); try{ t1.join(); t2.join(); }catch(InterruptedException e){ System.out.println("error occured"); 244 } System.exit(0); } Deadlock grabIt; public synchronized void run() { try{ Thread.sleep(1500); }catch(InterruptedException e){ System.out.println("error occured"); } grabIt.syncIt(); } public synchronized void syncIt() { try{ Thread.sleep(1500); System.out.println("Sync"); }catch(InterruptedException e){ System.out.println("error occured"); } System.out.println("In the syncIt() method"); } } Kết chương trình hiển thị sau: 245 Hình 6.8 Kết thực ví dụ 6.8 6.13 Thu dọn rác Thu dọn “rác” (Garbage collection) cải tạo làm trống nhớ cấp cho đối tượng mà đối tượng không sử dụng thời gian dài Trong ngôn ngữ lập trình hướng đối tượng khác C++, lập trình viên phải tự giải phóng Thất bại việc giải phóng nhớ gây số hậu Java tự động tiến hành thu dọn rác để cung cấp giải pháp cho vấn đề Một đối tượng trở nên thích hợp cho dọn rác khơng có tham chiếu đến nó, gán null Trình thực thi dọn rác lng chạy ngầm (deamon) co mức ưu tiên thấp Ta gọi phương thức gc() thể nghiệm để dọn rác Tuy nhiên, bạn khơng thể dự đốn bảo đảm dọn rác thực thi sau Sử dụng câu lệnh sau để tắt dọn rác ứng dụng: Java –noasyncgc … Nếu tắt dọn rác, chương trình chắn bị treo thiếu nhớ Phƣơng thức finalize() Java cung cấp phương pháp để làm rác trước luồng, chương trình kết thúc Điều tương tự phương thức Destructor C++ Phương thức finalize(), có, thực thi đối tượng, trước dọn rác thực Câu lệnh phương thức finalize() sau: protected void finalize() throws Throwable Tham chiếu rác; đối tượng gọi rác Ví du: Object a = new Object(); 246 Object b = a; a = null; Ở đây, sai nói “b” đối tượng Nó tham chiếu Hơn nữa, đoạn mã trích “a‟ đặt rỗng, khơng thể dọn, cịn có tham chiếu b đến Vì “a” cịn với truy cập được, thật vậy, cịn có phạm vi sử dụng phạm vi chương trình Ở đây, khơng dọn Tuy nhiên, ví dụ cho đây, giả định khơng có tham chiếu đến “a” tồn tại, đối tượng “a” trở nên thích hợp cho việc dọn rác Object a = new Object(); … … … a = null; Một ví dụ khác: Object m = new Object(); Object m = null; Đối tượng tạo ban đầu trở thành đối tượng cần dọn cho dọn rác Object m = new Object(); m = new Object(); Bây giờ, ban đầu dọn, đối tượng tham chiếu “m” tồn Bạn chạy phương thức gc() (garbage collection), khơng bảo đảm chạy Ví dụ 6.9: điển hình cho gc() class GCDemo { public static void main(String args[]) { int i; long a; , 247 Runtime r=Runtime.getRuntime(); long valuesD =new long[200]; System.out.println("Amount of free memory is" + r.freeMemory()); r.gc(); System.out.println("Amount of free memory after garbage collection is " + r.freeMemory()); for (a=10000,i=0;i