Giáo trình java gui swing

Bài 1: Bắt đầu với Swing 1. Đôi điều về JFC và Swing 2. Biên dịch và thực thi một chương trình Swing 3. Thực thi các Swing Applets 4. Trao đổi thêm về một ứng dụng Swing Bài 2: Các khái niệm và chức năng của Swing 1. Các thành phần Swing và sự phân cấp giới hạn. 2. Layout Management 3. Event Handling 4. Painting 5. Threads and Swing 6. Những tính năng và khái niệm khác của Swing 7. Phân tích một chương trình Swing Bài 3: Sử dụng các tính năng khác của Swing 1. Cách sử dụng Actions 2. Thế nào là kỹ thuật hỗ trợ Assisive(Support Assistive Technologies) 3. Cách sử dụng các đường viền(Border) 4. Cách sử dụng Icons 5. Sử dụng tiến trình(Threads) 6. Sử dụng Timers Bài 4: Bố trí các thành phần bên trong các đối tượng chứa 1. Sử dụng Layout Managers 2. Tạo một Custom Layout Manager 3. Làm việc không có Layout Manager(Absolute Positioning) 4. Giải quyết các vấn đề về Layout Bài 5: Viết sự kiện Listeners 1. Một vài ví dụ về Event-Handling 2. Tổng quan về Writing Event Listeners 3. Hỗ trợ Listeners của các thành phần Swing 4. Thực hiện Listeners cho các Handled Events thông thường 5. Tổng kết về Listener API

doc63 trang | Chia sẻ: tlsuongmuoi | Lượt xem: 4394 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Giáo trình java gui swing, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
́p trong để thực thi các sự kiện. Để 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 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) { } /* Empty method definition. */ public void mouseReleased(MouseEvent e) { } /* Empty method definition. */ public void mouseEntered(MouseEvent e) { } /* Empty method definition. */ public void mouseExited(MouseEvent e) { } public void mouseClicked(MouseEvent e) { ...//Event handler implementation goes here... } } Đáng tiếc là kết quả của sự lựa chọn các phương thức rỗng có thể khó đọc và duy trì. Để giúp bạn tránh được các lộn xộn với những phương thức rỗng trong chương trình, 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 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. Component Listener action caret change document, undoable edit item list selection window other button X X X check box X X X color chooser X combo box X X dialog X editor pane X X hyperlink file chooser X frame X internal frame internal frame list X list data menu menu menu item X X X menu key menu drag mouse option pane password field X X X popup menu popup menu progress bar X radio button X X X slider X tabbed pane X table X   table model table column model cell editor text area X X text field X X X text pane X X   hyperlink toggle button X X X tree   tree expansion tree will expand tree model tree selection viewport (used by scrollpane) X 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: button.addActionListener(this); ... public void actionPerformed(ActionEvent e) { ...//Make a beep sound... } } Viết một Adjustment Listener Các sự kiện Adjustment thông báo cho bạn biết sự thay đổi giá trị trong các thành phần. Đối tượng Adjustable có một giá trị nguyên, và nó trả về các các sự kiện adjustment bất cứ khi nào giá trị đó thay đổi. Chỉ có một lớp của AWT thực thi Adjustable là lớp Scrollbar. Có 5 loại sự kiện adjustment: track người sử dụng hoàn toàn thay đổi giá trị của thành phần. unit increment, unit decrement người sử dụng chỉ biểu thị sự thay đổi nhỏ về giá trị của thành phần. block increment, block decrement người sử dụng biểu thị sự thay đổi giá trị của thành phần với số lượng lớn. Các phương thức sự kiện của Adjustment Giao diện Adjustment Listener chứa một phương thức đơn, và vì thế nó không có lớp mô phỏng tương ứng. Sau đây là phương thức đó: void adjustmentValueChanged(AdjustmentEvent) Được gọi bởi AWT vừa sau khi thay đổi giá trị của thành phần. Ví dụ về Handling Adjustment Events class ConversionPanel ... implements AdjustmentListener ... { ... Scrollbar slider; ... ConversionPanel(...) { ... slider.addAdjustmentListener(this); } ... /** Respond to the slider. */ public void adjustmentValueChanged(AdjustmentEvent e) { textField.setText(String.valueOf(e.getValue())); controller.convert(this); } ... } Lớp AdjustmentEvent Phương thức adjustmentValueChanged có một thông số: một đối tượng AdjustmentEvent. Lớp AdjustmentEvent định nghĩa các phương thức sau: Adjustable getAdjustable() 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); ... public void componentHidden(ComponentEvent e) { displayMessage("componentHidden event from " + e.getComponent().getClass().getName()); } public void componentMoved(ComponentEvent e) { displayMessage("componentMoved event from " + e.getComponent().getClass().getName()); } public void componentResized(ComponentEvent e) { displayMessage("componentResized event from " + e.getComponent().getClass().getName()); } public void componentShown(ComponentEvent e) { displayMessage("componentShown event from " + e.getComponent().getClass().getName()); } } class ComponentPanel extends Panel ... { ... ComponentPanel(ComponentEventDemo listener) { ...//after creating the label and checkbox: label.addComponentListener(listener); checkbox.addComponentListener(listener); } ... } Lớp ComponentEvent Mỗi một phương thức của sự kiện các thành phần có một thông số đơn: đối tượng ComponentEvent lớp ComponentEvent định nghĩa một phương thức hay dùng, getComponent, trả về thành phần mà phát ra sự kiện. Viết một Container Listener Những sự kiện của Container được phát ra ngay sau khi một thành phần được thêm vào Container hoặc chuyển đi khỏi Container. Các phương thức, sự kiện của Container Giao diện ContainerListener và lớp mô phỏng tương ứng, ContainerAdapter chứa hai phương thức: void componentAdded(ContainerEvent) được gọi sau khi một thành phần được thêm vào Container. void componentRemoved(ContainerEvent) được gọi sau khi một thành phần được chuyển đi khỏi Container. Ví dụ về Handling Container Events public class ContainerEventDemo ... implements ContainerListener ... { ...//where initialization occurs: buttonPanel = new Panel(); buttonPanel.addContainerListener(this); ... public void componentAdded(ContainerEvent e) { displayMessage(" added to ", e); } public void componentRemoved(ContainerEvent e) { displayMessage(" removed from ", e); } void displayMessage(String action, ContainerEvent e) { display.append(((Button)e.getChild()).getLabel() + " was" + action + e.getContainer().getClass().getName() + "\n"); } ... } Lớp ContainerEvent Mỗi phương thức của Container Event có một thông số đơn: đối tượng ContainerEvent. Lớp ContainerEvent định nghĩa hai phương thức thường dùng sau: Component getChild() Trả về thành phần được thêm hay chuyển khỏi Container trong sự kiện này. Container getContainer() Tar về Container sinh ra sự kiện này. Viết một Focus Listener Các sự kiện Focus được phát ra khi một thành phần có hoặc mất đi sự tập trung vào nó. Các phương thức, sự kiện của Focus Gaio diện FocusListener và lớp mô phỏng tương ứng, FocusAdapter, chứa hai phương thức: void focusGained(FocusEvent) được gọi sau khi thành phần có sự tập trung. void focusLost(FocusEvent) được gọi sau khi thành phần mất sự tập trung. Ví dụ về Handling Focus Events public class FocusEventDemo ... implements FocusListener ... { ...//where initialization occurs window = new FocusWindow(this); ... public void focusGained(FocusEvent e) { displayMessage("Focus gained", e); } public void focusLost(FocusEvent e) { displayMessage("Focus lost", e); } void displayMessage(String prefix, FocusEvent e) { display.append(prefix + ": " + e.getSource() //XXX + "\n"); } ... } class FocusWindow extends Frame { ... public FocusWindow(FocusListener listener) { super("Focus Demo Window"); this.addFocusListener(listener); ... Label label = new Label("A Label"); label.addFocusListener(listener); ... Choice choice = new Choice(); ... choice.addFocusListener(listener); ... Button button = new Button("A Button"); button.addFocusListener(listener); ... List list = new List(); ... list.addFocusListener(listener); } } Lớp FocusEvent Mỗi phương thức Focus Event có một thông số đơn : đối tượng FocusEvent. Lớp FocusEvent định nghĩa một phương thức, isTemporary, trả về giá trị True khi sự kiện mất sự tập trung đó là tạm thời. Mọi thông báo thông thường mà bạn gởi tới đối tượng FocusEvent là getComponent (được định nghĩa trong ComponentEvent), nó trả về thành phần gây ra sự kiện này. Viết một Item Listener Các sự kiện của Item được phát ra khi thực thi giao diện ItemSelectable. Các phương thức, sự kiện của Item Giao diện ItemListener vhỉ có một phương thức, vì vậy nó không có lớp mô phỏng tương ứng: void itemStateChanged(ItemEvent) được gọi sau khi thay đổi trạng thái của thành phần. Ví dụ về Handling Item Events public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { label.setVisible(true); } else { 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: "); } ... protected void displayInfo(KeyEvent e, String s){ ... char c = e.getKeyChar(); int keyCode = e.getKeyCode(); int modifiers = e.getModifiers(); ... tmpString = KeyEvent.getKeyModifiersText(modifiers); ...//display information about the KeyEvent... } } Lớp KeyEvent Mỗi phương thức Key Event có một thông số đơn: đối tượng KeyEvent. Lớp KeyEvent định nghĩanhững phương thức thường dùng sau: int getKeyChar() void setKeyChar(char) Nhận hoặc xác lập kí tự liên quan với sự kiện này. int getKeyCode() void setKeyCode(int) nhận hoặc xác lập mã của phím liên quan với sự kiện này. void setModifiers(int) xác lập tạng thái của phím liên quan tới sự kiện này int getModifiers() Tả về trạng thái của phím trong sự kiện này. Viết một Mouse Listener Các sự kiện được phát ra khi người sử dụng dùng chuột tác đông đến một thành phần. Các phương thức, sự kiện của Mouse Giao diện MouseListener và lớp mô phỏng tương ứng, MouseAdapter, chứa ba phương thức: void mouseClicked(MouseEvent) được gọi sau nkhi người sử dụng kích hoạt chuột vào một thành phần. void mouseEntered(MouseEvent) được gọi sau khi con trỏ chuột nằm trong địa phận của thành phần. void mouseExited(MouseEvent) được gọi sau khi con trỏ chuột ra khỏi địa phận của thành phần. void mousePressed(MouseEvent) được gọi sau khi con chuột được ấn trên địa phận của thành phần. void mouseReleased(MouseEvent) được gọi sau khi con chuột được nhả trên địa phận của thành phần. Ví dụ về Handling Mouse Events public class MouseEventDemo ... implements MouseListener { ...//where initialization occurs: //Register for mouse events on blankArea and applet (panel). blankArea.addMouseListener(this); addMouseListener(this); ... public void mousePressed(MouseEvent e) { saySomething("Mouse button press", e); } public void mouseReleased(MouseEvent e) { saySomething("Mouse button release", e); } public void mouseEntered(MouseEvent e) { saySomething("Cursor enter", e); } public void mouseExited(MouseEvent e) { saySomething("Cursor exit", e); } public void mouseClicked(MouseEvent e) { saySomething("Mouse button click", e); } void saySomething(String eventDescription, MouseEvent e) { textArea.append(eventDescription + " detected on " + e.getComponent().getClass().getName() + ".\n"); textArea.setCaretPosition(maxInt); //scroll to bottom } } Lớp MouseEvent Mỗi phương thức Mouse Event có một thông số đơn: đối tượng MouseEvent. Lớp MouseEvent định nghĩa các phương thức thường dùng sau: int getClickCount() trả về số lần nhấn liên tiếp của người sử dụng. int getX() int getY() Point getPoint() Trả về vị trí của con trỏ trỏ chuột, vị trí này phụ thuộc vào thành phần. boolean isPopupTrigger() trả về giá trị True khi sự kiện này làm xuất hiện Popup Menu. Viết một Mouse Motion Listener Các sự kiện Mouse motion phát ra ki người sử dụng dùng chuột di chuyển trên màn hình. 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(); } public void mouseDragged(MouseEvent e) { updateSize(e); } public void mouseMoved(MouseEvent e) { //Do nothing. } public void mouseReleased(MouseEvent e) { updateSize(e); } void updateSize(MouseEvent e) { int x = e.getX(); int y = e.getY(); currentRect.setSize(x - currentRect.x, y - currentRect.y); repaint(); } } 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")); textArea = new TextArea(5, 20); textArea.addTextListener(new MyTextListener("Text Area")); ... } class MyTextListener implements TextListener { String preface; public MyTextListener(String source) { preface = source + " text value changed.\n" + " First 10 characters: \""; } public void textValueChanged(TextEvent e) { TextComponent tc = (TextComponent)e.getSource(); String s = tc.getText(); ...//truncate s to 10 characters... displayArea.append(preface + s + "\"\n"); ... } } ... } 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(); } public void windowClosing(WindowEvent e) { window.setVisible(false); displayMessage("Window closing", e); } public void windowClosed(WindowEvent e) { displayMessage("Window closed", e); } public void windowOpened(WindowEvent e) { displayMessage("Window opened", e); } public void windowIconified(WindowEvent e) { displayMessage("Window iconified", e); } public void windowDeiconified(WindowEvent e) { displayMessage("Window deiconified", e); } public void windowActivated(WindowEvent e) { displayMessage("Window activated", e); } public void windowDeactivated(WindowEvent e) { displayMessage("Window deactivated", e); } void displayMessage(String prefix, WindowEvent e) { display.append(prefix + ": " + e.getWindow() + newline); } ... } Lớp WindowEvent Mỗi phương thức Window Event có một thông số đơn: đối tượng WindowEvent. Lớp WindowEvent định nghĩa một phương thức, getWindow, trả về Window phát ra sự kiện này. 5. Tổng kết về Listener API Phần này This section features a quick-reference table that shows each listener, its adapter class (if any), and its methods. 6. Giải quyết các vấn đề về Event-Handling If you're having some hard-to-debug problems related to handling events, you might find the solution here. Bài 6: Làm việc với đồ hoạ Trong bài học này, sẽ hướng dẫn bạn cách hiển thị văn bản, các hình, ảnh đơn giản, sử dụng API làm việc trong JDK 1.1 và 1.2. Ngoài ra còn có ví dụ về việc tự tạo một thành phần, sử dụng các API để tạo một đường viền hay một icon. Các kiến thức về hoạt hình sẽ kết thúc bài học này. 1. Tổng quan về đồ hoạ Giới thiệu tổng quát về những thông tin cần thiết cho việc bắt đầu thực thi việc vẽ trong các thành phần. 2. Sử dụng đồ hoạ nguyên bản Trong phần này sẽ hướng dẫn bạn cách vẽ các hình đơn giản và hiển thị text một cách có hiệu quả. Bao gồm các ví dụ của việc sử dụng các lớp Graphics, Font, và FontMetrics classes. 3. Sử dụng hình ảnh Java platform hổ trợ hình ảnh như thế nào sẽ được bàn bạc trong phần này và cách để nạp và hiển thị hình ảnh. 4. Thực hiện hoạt cảnh (Performing Animation) Nhiều chương trình thực hiện hoạt cảnh, hoặc là hoạt hình của chú vịt Duke đang tung tăng bơi lội hay chỉ đơn giản là một hình ảnh chuyển động trên màn hình. Trong phần này sẽ nói về cách thực hiện hình ảnh động, cách sử dụng đối tượng Timer để thực hiện hoạt cảnh. Tạo vòng lặp cho hoạt cảnh với đối tượng Timer(Creating an Animation Loop with Timer) Bước quan trọng nhất để tạo một chương trình hoạt hình chính là khởi tạo các framework một cách chính xác. Ngoại trừ các hoạt hình thực hiện trực tiếp các đáp ứng cho các sự kiện mở rộng (ví dụ như việc người dùng kéo một đối tượng trên màn hình), một chương trình thực hiện hoạt cảnh cần có một vòng lặp của hoạt hình. Minh hoạ cho mục này có trong các ví dụ AnimatorAppletTimer.java và AnimatorApplicationTimer.java. Sau đây là phần tóm lược chung nhất của cả hai ví dụ. Đây cũng là xườn của một chương trình hoạt cảnh: public class AnimatorClass ... implements ActionListener { int frameNumber = -1; Timer timer; boolean frozen = false; JLabel label; //In initialization code: //From user-specified frames-per-second value, determine //how long to delay between frames. ... //Set up a timer that calls this object's action handler. timer = new Timer(delay, this); ... //Set up the components in the GUI. public synchronized void startAnimation() { ... timer.start(); ... } public synchronized void stopAnimation() { ... timer.stop(); ... } public void actionPerformed(ActionEvent e) { //Advance the animation frame. frameNumber++; //Request that the frame be painted. label.setText("Frame " + frameNumber); } ... //When the application's GUI appears: startAnimation(); ... } Tạo chuyển động cho một hình ảnh trên màn hình (Moving an Image Across the Screen) Cách đơn giản nhất để tạo hoạt cảnh là di chuyển một hình ảnh trên màn hình. Trong thế giới của hoạt cảnh truyền thống, điều này được gọi là cutout animation. Có hai hình mà applet sử dụng. 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. Lưu ý:  hình rocketship có ảnh nền là transparent. Đoạn mã để thực hiện hoạt cảnh này không mấy phức tạp. Nói chung, nó cũng giống như xườn đưa ra ở bên trên. Thay vì sử dụng một label để thực hiện hoạt cảnh thì nó sử dụng một thành phần tùy biến. Thành phần tùy biến ở đây là lớp con của JPanel nhằm thực thi việc vẽ cả hai hình ảnh ở trên: ...//Where the images are initialized: Image background = getImage(getCodeBase(), "images/rocketship.gif"); Image foreground = getImage(getCodeBase(), "images/starfield.gif"); ... public void paintComponent(Graphics g) { super.paintComponent(g); //paint any space not covered //by the background image int compWidth = getWidth(); int compHeight = getHeight(); //If we have a valid width and height for the //background image, paint it. imageWidth = background.getWidth(this); imageHeight = background.getHeight(this); if ((imageWidth > 0) && (imageHeight > 0)) { g.drawImage(background, (compWidth - imageWidth)/2, (compHeight - imageHeight)/2, this); } //If we have a valid width and height for the //foreground image, paint it. imageWidth = foreground.getWidth(this); imageHeight = foreground.getHeight(this); if ((imageWidth > 0) && (imageHeight > 0)) { g.drawImage(foreground, ((frameNumber*5) % (imageWidth + compWidth)) - imageWidth, (compHeight - imageHeight)/2, this); } } Có thể bạn sẽ cho rằng việc xoá ảnh nền là không cần thiết khi sử dụng một ảnh nền nào đó. Tuy nhiên, việc xoá hình nền ở đây vẫn được quan tâm, bởi lẽ applet luôn luôn khởi động việc vẽ trước khi hình được nạp đầy đủ. Nếu hình rocketship được nạp trước hình nền thì ta sẽ thấy những phần khác nhau này của chương trình. Hiển thi tuần tự các hình ảnh (Displaying a Sequence of Images) Trong ví dụ của phần này sẽ cung cấp những bước cơ bản của việc hiển thị tuần tự các hình ảnh để nó thật giống như hoạt cảnh mà ta thường thấy. Dưới đây là 10 hình ảnh mà applet sẽ sử dụng: T1.gif: T2.gif: T3.gif: T4.gif: T5.gif: T6.gif: T7.gif: T8.gif: T9.gif: T10.gif: 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ị 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"); } . . .//In the paintComponent method: g.drawImage(images[ImageSequenceTimer.frameNumber % 10], 0, 0, this); Cách khác để thực hiện ví dụ này là dùng một label để hiển thị các hình ảnh. Thay vì sử dụng đoạn lệnh để vẽ lại hình thì ta dùng phương thức setIcon để thay đổi hình được hiển thị. Cải tiến giao diện và thực hiện hoạt cảnh (Improving the Appearance and Performance of Image Animation) Lưu ý hai việc trong vấn đề hoạt cảnh ở trên: Trong khi một bức ảnh đang được nạp, chương trình sẽ hiển thị một phần của toàn bộ bức ảnh, các phần khác có thể chưa được hiển thị. Nạp một bức ảnh sẽ cần một thời gian tương đối dài. Sử dụng lớp MediaTracker có thể giải quyết được vấn đề về hiển thị hình ảnh. MediaTracker còn có thể giảm thiểu lượng thời gian để nạp hình ảnh. Cách khác để cải tiến thời gian nạp hình là thay đổi dạng thức của tập tin ảnh. Trong phần này sẽ đề cập tới vấn đề này. Sử dụng MediaTracker để nạp và nạp hình ảnh (Using MediaTracker to Download Images and Delay Image Display) Lớp MediaTracker cho phép nạp dữ liệu của một nhóm các tập tin ảnh và kết thúc khi hình ảnh đã được nạp đầy đủ. Nói chung, dữ liệu của một hình ảnh chưa được tải về khi nó được vẽ trong lần đầu tiên. Để yêu cầu dữ liệu của các hình ảnh được chuẩn bị trước để tải về, ta có thể sử dụng các phương thức của MediaTracker như sau: checkID(anInt, true) hoặc checkAll(true). Để nạp dữ liệu về một cách đồng bộ, sử dụng phương thức waitForID hoặc waitForAll. Phương thức MediaTracker sử dụng tiến trình của hệ thống để tải dữ liệu về, do đó có thể tăng tốc độ của đường truyền. Để kiểm tra trạng thái của việc nạp dữ liệu về, ta dùng phương thức MediaTracker statusID hoặc statusAll. Cách đơn giản nhất để kiểm tra xem dữ liệu của hình ảnh có đang được tải về hay không thì dùng phương thức checkID hoặc checkAll. 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; tracker = new MediaTracker(this); ...//In the init method: for (int i = 1; i <= 10; i++) { images[i-1] = getImage(getCodeBase(), "images/duke/T"+i+".gif"); } ...//In the buildUI method, //which is called by init and main, //allowing us to run the sample //as an applet or an application: for (int i = 1; i <= 10; i++) { tracker.addImage(images[i-1], 0); } ...//At the beginning of the actionPerformed method: try { //Start downloading the images. Wait until they're loaded. tracker.waitForAll(); } catch (InterruptedException e) {} ...//In the paintComponent method: //If not all the images are loaded, just clear the background //and display a status string. if (!tracker.checkAll()) { g.clearRect(0, 0, d.width, d.height); g.drawString("Please wait...", 0, d.height/2); } //If all images are loaded, paint. else { ...//same code as before... } 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. 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. 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(...); 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"); 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. 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"); ^ Đế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.

Các file đính kèm theo tài liệu này:

  • docGiáo trình Java GUI SWING.doc
Tài liệu liên quan