Tổng quan về Java Ui

Tài liệu Tổng quan về Java Ui: TỔNG QUAN VỀ JAVA UI UI(User Interface) là giới hạn rộng đề cập các loại giao tiếp giữa chương trình và người sử dụng. UI không chỉ là những thứ mà người dùng thấy, mà bao gồm cả những thứ người sử dụng nghe và cảm nhận. Ngay cả tốc độ la một phần quan trọng của UI trong một chương trình Giới thiệu GUI Đây là một UI được ưa chuộng hơn đối với hầu hết các chương trình JAVA Sử dụng âm thanh Ứng dụng sẽ chơi được âm thanh mà các ứng dụng khác không thể làm được Nhận thông tin về cấu hình Người sử dụng có thể chỉ định thông tin cấu hình tới ứng dụng bằng cách sử dụng command-line arguments và parameters Lưu trữ độ ưu tiên của người sử dụng bằng việc sử dụng các thuộc tính. Đối với những thông tin mà ứng dụng cần ngay cả khi ứng dụng không chạy, bạn có thể sử dụng các thuộc tính. Những ứng dụng̣̣ kí sinh(Applets) thường không thể viết các thuộc tí...

doc49 trang | Chia sẻ: hunglv | Lượt xem: 1515 | Lượt tải: 0download
Bạn đang xem trước 20 trang mẫu tài liệu Tổng quan về Java Ui, để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
TỔNG QUAN VỀ JAVA UI UI(User Interface) là giới hạn rộng đề cập các loại giao tiếp giữa chương trình và người sử dụng. UI không chỉ là những thứ mà người dùng thấy, mà bao gồm cả những thứ người sử dụng nghe và cảm nhận. Ngay cả tốc độ la một phần quan trọng của UI trong một chương trình Giới thiệu GUI Đây là một UI được ưa chuộng hơn đối với hầu hết các chương trình JAVA Sử dụng âm thanh Ứng dụng sẽ chơi được âm thanh mà các ứng dụng khác không thể làm được Nhận thông tin về cấu hình Người sử dụng có thể chỉ định thông tin cấu hình tới ứng dụng bằng cách sử dụng command-line arguments và parameters Lưu trữ độ ưu tiên của người sử dụng bằng việc sử dụng các thuộc tính. Đối với những thông tin mà ứng dụng cần ngay cả khi ứng dụng không chạy, bạn có thể sử dụng các thuộc tính. Những ứng dụng̣̣ kí sinh(Applets) thường không thể viết các thuộc tính cho hệ thống các file cục bộ vì những hạn chế về bảo mật thông tin Nhận và hiển thị thông tin đầu vào, đầu ra và các dòng lỗi Các thông tin dầu vào, đầu ra và các lỗi chuẩn là một cách cũ vẫn còn hiện hữu đối với một giao diện người dùng. Nó vẫn còn hữu ích cho việc kiểm tra và gỡ lỗi các chương trình. CÁC THÀNH PHẦN CỦA AWT Các điều khiển cơ bản: Buttons, Checkboxes, Choices, Lists, Menus, and Text Fields Các lớp Button, Checkbox, Choice, List, MenuItem, and TextField cung cấp những công cụ điều khiển cơ bản. Đây là những các phổ biến nhất để người sử dụng xây dựng một chương trình JAVA. Khi người sử dụng kích hoạt một trong những điều khiển trên, ví dụ như khi nhắp chuột vào một nút hay khi nhấn phím trong một hộp Text thì nó sẽ thông báo một sự kiện (ACTION_EVENT). Một đối tượng chứa điều khiển đó có thể đáp trả sự kiện bằng việc sử dụng phương thức action() Các công cụ khác để lấy thông tin đầu vào của người sử dụng: Sliders, Scrollbars, and Text Areas Khi những điều khiển cơ bản không còn thích hợp nữa, bạn có thể sử dụng các lớp Scrollbar and TextArea để lấp dữ liều người sử dụng nhập vào. Lớp Scrollbar được sử dụng cho cả hai chức năng :thanh cuộn và con trược. Scrollbars không được tự động nằm trong Lists, Text Areas và trong những đối tượng ScrollPane. Lớp TextArea chỉ đơn giản cung cấp vùng để hiển thị hay cho phép sửa một vài dòng văn bản Tạo một thành phần theo ý muốn: Canvases Lớp Canvas cho phép bạn viết một thanh phần theo ý mình. Với các lớp con của Canvas, bạn có thể vẽ các hình ảnh như ý mình ra màn hình Thành phần Labels Label chỉ đơn giản để hiển thị một di₫òng văn bản không thể chọn lựa Các đối tượng chứa: Windows, Panels, and Scroll Panes AWT cung cấp 3 kiểu đối tượng chứa, tất cả được thực hiện như các lớp con của lớp Cotainer. Lớp con Window (Dialog, FileDialog, và Frame) cung cấp những cửa sổ dùng để chứa các thành phần. Panel d dùng để nhóm các thành phần trong một vùng của cửa sổ. ScrollPane cũng giống như Panel, nhưng nó đặc biệt hơn: nó hiển thị một thành phần lớn không có giới hạn về không gian, thông thường dùng thanh cuộn để điều khiển hiển thị một phần nào đó của thành phần Frames tạo một cửa sổ khá mạnh, khác với các cửa sổ do Dialogs tạo ra, các cửa sổ do Dialogs tạo ra sẽ phụ thuộc trên cửa sổ do Frames tạo ra Các lớp AWT khác AWT chứa nhiều thành phần khác. Nó chứa các lớp có liên quan đến việc vẽ và nắm bắt sự kiện. Phần này chúng ta thảo luận về các lớp của AWT có trong gói java.awt. AWT chứa hai gói khác là java.awt.image và java.awt.peer mà hầu hết các chương trình không sử dụng nó. Lớp và giao diện trong những gói này sẽ được đề cập đến khi cần thiết Gói java.awt một vài lớp layout manager. Gói java.awt cung cấp vài lớp về kích thước và hình dạng. Lớp Shape bao gồm Point, Rectangle, and Polygon. Lớp Color class rất thích hợp cho việc miêu tả và thao các màu sắc. Nó định nghĩa các hằng số cho các màu được dùng phổ biến như Color.black. Trong khi màu sử dụng phổ biến theo địng dạng RGB (red-green-blue), thì nó cũng có thể hiểu được màu đinh dang theo HSB (hue-saturation-brightness). Lớp Image cung cấp cách trình diễn dữ liệu ảnh. Một ứng dụng có thể lấy những đối tượng Image cho các ảnh GIF và JPEG bằng cách dùng phương thức getImage(). SỬ DỤNG CÁC THÀNH PHẦN, CÁC KHỐI XÂY DỰNG MỘT GUI Sử dụng các thành phần của AWT Hình vẽ sau cho thấy hệ thống phân cấp có tính thừa kế cho các lớp thành phần của AWT. Object | MenuComponent | +------------+ | | MenuItem MenuBar | +----+ | | Menu CheckboxMenuItem Các quy tắc chung khi sử dụng các thành phần Làm thế nào để thêm một thành phần vào một đối tượng chứa Khi bạn đọc bài này, nên chú ý. Bởi không có thành phần nào ngoại trừ cửa sổ tự hiển thị trên màn hình được. Trước hết bạn phải thêm nó vào một đối tượng chứa. Bản thân đối tượng chứa này là một thành phần, cũng có thể được thêm vào đối tượng chứa khác. Windows cũng như Frames and Dialogs nó là những đối tượng chứa mức cao nhất; đó là những thành phần không thêm vào được đối tượng chứa khác. Lớp Container địng nghĩa 3 phương thức cho việc thêm thành phần vào trong no: một phương thức add() một thông số và 2 phương thức add() có hai thông số. Nó phụ thuộc vào cách bố trí của một đối tượng chứa đang dùng. Phương thức add() một thông số thông thường chỉ yêu cầu chỉ định thành phần thêm vào. Phương thức add() 2 thông số. Phương thức 2 thông số đầu tiên cho phép bạn thêm một thông số chỉ định vị trí mà thành thành phần được thêm vào. Thông số thứ 2 của phương thức add() 2 thông số thứ 2 chỉ định thành phần được thêm vào Container. Thông số đầu là chuỗi phụ thuộc. Chú ý: Thêm một thành phần vào Container là chuyển thành phần đó từ Container đang chứa nó sang Container khác. Vì thế không thể có một thành phần trong 2 Container, ngay cả khi 2 Container đó không xuất hiện cùng một lúc trên màn hình. Các lớp thành phần cung cấp cái gì Tất cả các thành phần ngoại trừ Menus được thực thi như những lớp con của lớp Component. Nó thừa kế phần lớn các chức năng của lớp này Các hổ trợ cơ bản cho việc vẽ Lớp Component cung cấp các phương thức paint(), update(), và repaint()để hổ trợ cho việc vẽ Các sự kiện Lớp Component định nghĩa một phương thức handleEvent() cho mục đích chung và một nhóm các phương thức như action() nắm bắt các sự kiện xác định. Lớp Component cũng nhận sự điều khiển từ bàn phím. Điều khiển hình thức: font Lớp Component cung cấp các phương thức để lấy và xác lập font, và lấy thông tin về Font hiện tại Điều khiển hình thức: màu Lớp Component cung cấp các phương thức sau để lấy và xác lập màu nền và màu chữ: setForeground(Color), getForeground(), setBackground(Color), and getBackground(). Màu chữ là màu dùng cho tất cả văn bản có trong thành phần. màu nền là màu đằng sau văn bản hoặc ảnh Nắm bắt ảnh Lớp Component cung cấp nền tảng cho việc hiển thị ảnh. Lưu ý rằng phần lớn các thành phần không hiển thị được ảnh. Canvases và hầu hết các Container có thể hiển thị được ảnh. Điều khiển kích thước và vị trí trên màn hình Phương thức preferredSize() và minimumSize() cho phép một thành phần thiết kế các thành phần với kích thước thích hợp và nhỏ nhất. Làm thế nào để thay đổi hình thức và cách thức tác động của một thành phần Hình thức của hầu hết các thành phần đều phụ thuộc vào Platform. Buttons ở hệ thống Motif khác so với Buttons ở hệ thống Macintosh. Bạn không thể dễ dàng thay đổi hoàn toàn hình thức của các thành phần. bạn chỉ có thể thay đổi một phần nhỏ hình thức của các thành phần đó mà thôi như là thay đổi Font và màu nền. Mặc dù bạn không thể thay đổi hoàn toàn hình thức của các thành phần, nhưng bạn có thể thay đổi cách cư xử của nó. Ví dụ, nếu chỉ có giá trị số mới phù hợp với Textfied, thì bạn có thể thực thi lớp con TextField kiểm tra mọi giá trị nhập vào của bàn phím, không nhận những giá trị không phải là sô.́ Sử dụng Buttons Button là một công cụ điều khiển đơn giản để phát ra một sự kiện hành động khi người sử dụng nhấn vào đó. Hình thức của Buttons trên màn hình phụ thuộc vào nền mà nó đang chạy và nó có nhận được sự tác động hay không. Nếu bạn muốn các Button của chương trình giống nhau ở mọi nền hoặc cho thật đặc biệt, bạn nên tạo một lớp con Canvas để làm được ngoại hình của các nút theo ý muốn; bạn không thể dùng lớp con Button để thay đổi ngoại hình của các nút. những nét của hình thức của một Button có thể thay đổi được là Font và chuỗi hiển thị , màu nền và màu chữ của nó, và và nó có thể được tác động hay không. Sau đây là một Applet hiển thị 3 Button. Khi bạn kích chuột vào nút bên trái, nó sẽ làm cho nút giữa không nhận được sự tác động (và nó làm cho nó không thể nhận sự tác động) và làm cho nút phải nhận được sự tác động. Khi kích chuột vào nút bên phải, nó kích hoạt sự hoạt động của nút giữa và nút trái và làm cho nó sẽ không nhận được sự tác động. //In initialization code: b1 = new Button(); b1.setLabel("Disable middle button"); b2 = new Button("Middle button"); b3 = new Button("Enable middle button"); b3.disable(); . . . public boolean action(Event e, Object arg) { Object target = e.target; if (target == b1) { //They clicked "Disable middle button" b2.disable(); b1.disable(); b3.enable(); return true; } if (target == b3) { //They clicked "Enable middle button" b2.enable(); b1.enable(); b3.disable(); return true; } return false; } Sử dụng Canvases Lớp Canvas tòn tại như là một lớp con. Nó không làm gì cho bản thân nó; nó chỉ cung cấp cho bạn cách thực thi các thành phần tự tạo. Ví dụ, Canvases rất thuận lợi cho việc hiển thị các vùng của hình ảnh, trong bất cứ trường hợp nào bạn cùng có thể nắm bắt được các sự kiện xảy ra trong suốt thời gian hiển thị ảnh. Canvases cũng thuận tiên khi điều khiển -- Button, for example – nó không giống như sự thực thị mặc định của một điều khiển. Vì lẽ rằng bạn không thể thay đổi hình thức của các điều khiển chuẩn bằng các lớp con mà các thành phần tương ứng với no (ví dụ chư Button), do đó bạn phải thực thi lớp con Canvas để bạn có thể có hình thức như ý muốn và cách cư xử tương tự như sự thực thi mặc định của điều khiển. Khi thực thi một lớp con Canvas , cẩn thận khi thực thi những phương thức minimumSize() và preferredSize() để mang lại kích thước đúng đắn cho các Canva. Mặc khác, phù thuộc vào cách bố tri của các đối tượng chứa các Canva, các Canva có thể có kích thước quá nhỏ, có khi không thấy cùng nên. Sau đây là một Applet sử dụng 2 trường hợp của lớp con Canvas subclass: ImageCanvas. Sau đây là một đoạn mã lệnh của ImageCanvas. Bởi vì dữ liệi ảnh được tải về không đồng bộ nên ImageCanvas không cho biết đựơc độ lớn của nó cho đến vài giây sau khi nó tạo được. Vì lý do này, ImageCanvas dùng độ rộng và độ cao ban đầu để tạo ảnh cho đến khi kích thước của ảnh hoàn toàn xác định được thì nó mới thay đổi kích thước của nó. class ImageCanvas extends Canvas { Container pappy; Image image; boolean trueSizeKnown = false; Dimension minSize; int w, h; public ImageCanvas(Image image, Container parent, int initialWidth, int initialHeight) { if (image == null) { System.err.println("Canvas got invalid image object!"); return; } this.image = image; pappy = parent; w = initialWidth; h = initialHeight; minSize = new Dimension(w,h); } public Dimension preferredSize() { return minimumSize(); } public synchronized Dimension minimumSize() { return minSize; } public void paint (Graphics g) { if (image != null) { if (!trueSizeKnown) { int imageWidth = image.getWidth(this); int imageHeight = image.getHeight(this); if ((imageWidth > 0) && (imageHeight > 0)) { trueSizeKnown = true; //Ooh... component-initiated resizing. w = imageWidth; h = imageHeight; minSize = new Dimension(w,h); resize(w, h); pappy.layout(); pappy.repaint(); } } g.drawRect(0, 0, w - 1, h - 1); g.drawImage(image, 0, 0, this); } } } Sử dụng Checkboxes Lớp Checkbox cung cấp những checkbox – 2 trạng thái của Checkbox có thể là “on” hoặc “off”. Khi người sử dụng nhấn chuột vào Checkbox, trạng thái của Checkbox sẽ thay đổi và trả về một sự kiện. Mặc khác, nó cũng nhóm các thành phần để người dùng có thể chọn như là Choices, Lists, và Menus. Nếu bạn muốn tạo một nhóm Checkbox mà chỉ có một Checkbox trong một thời điểm ở trạng thái “on” thì bạn có thể thêm vào một đối tượng CheckboxGroup để giám sát các Checkbox đó. Ví dụ : Panel p1, p2; Checkbox cb1, cb2, cb3; //These are independent checkboxes. Checkbox cb4, cb5, cb6; //These checkboxes are part of a group. CheckboxGroup cbg; cb1 = new Checkbox(); //Default state is "off" (false). cb1.setLabel("Checkbox 1"); cb2 = new Checkbox("Checkbox 2"); cb3 = new Checkbox("Checkbox 3"); cb3.setState(true); //Set state to "on" (true). . . . cbg = new CheckboxGroup(); cb4 = new Checkbox("Checkbox 4", cbg, false); //initial state: off (false) cb5 = new Checkbox("Checkbox 5", cbg, false); //initial state: off cb6 = new Checkbox("Checkbox 6", cbg, false); //initial state: off Sử dụng Choices Lớp Choice cung cấp một thực đơn để lựa chọn, truy nhập bằng một nút đặc biệt. người sử dụng nhấn nút đó và nó sẽ liệt ra một menu và bạn có thể chọn một thứ trong menu đó. Khi người dùng chọn, nó sẽ phản hồi một sự kiện. Ví dụ : //...Where instance variables are defined: Choice choice; //pop-up list of choices //...Where initialization occurs: choice = new Choice(); choice.addItem("ichi"); choice.addItem("ni"); choice.addItem("san"); choice.addItem("yon"); label = new Label(); setLabelText(choice.getSelectedIndex(), choice.getSelectedItem()); . . . public boolean action(Event e, Object arg) { if (e.target instanceof Choice) { setLabelText(choice.getSelectedIndex(), (String)arg); return true; } return false; } } Sử dụng Dialogs AWT cung cấp những hổ trợ cho dialogs – là những cửa sổ phụ thuộc vào những cửa sổ khác—với lớp Dialog. Nó cung cấp những lớp con hữu ích như : FileDialog, cung cấp một cửa sổ mà bạn có thể mở hoặc lưu file. Một yếu tố để phân biệt Dialog và các cửa sổ thông thường khác là Dialog phụ thuộc vào các cửa sổ khác (Frame). Khi cửa sổ đóng thì các Dialog phụ thộc nó cũng biến mất. Khi những cửa sổ đó được thu nhỏ các Dialog phụ thuộc nó sẽ không xuất hiện trên màn hình. Khi cửa sổ được trở về kích thước thông thường thì các Dialog đó sẽ hiển thị ra màn hình. AWT tự động cung cấp các hình thức này cho bạn. Dialogs có thể là modal. Modal dialogs đòi hỏi sự chăm sóc kỹ lưỡng của người sử dụng, chống lại việc người sử dụng làm bất cứ cái gì khác trên ứng dụng cho đến khi Dialog đã được gạt bỏ Ví dụ : class SimpleDialog extends Dialog { TextField field; DialogWindow parent; Button setButton; SimpleDialog(Frame dw, String title) { super(dw, title, false); parent = (DialogWindow)dw; ...//Create and add components, such as the set button. //Initialize this dialog to its preferred size. pack(); } public boolean action(Event event, Object arg) { if ( (event.target == setButton) | (event.target instanceof TextField)) { parent.setText(field.getText()); } field.selectAll(); hide(); return true; } } Sử dụng Frames Lớp Frame cung cấp những cửa sổ cho applets và applications. Mỗi ứng dụng phải có ít nhất 1 Frame. Nếu một ứng dụng có 1 cửa sổ phụ thuộc vào cửa sổ khác thì bạn nên dùng Dialog thay vì dùng Frame cho cửa sổ phụ thuộc đó. Đáng tiếc là applets không thể dùng tốt dialogs, vì vậy người sử dụng thường dùng Frame. Ví dụ: public class MenuWindow extends Frame { boolean inAnApplet = true; TextArea output; public MenuWindow() { ...//This constructor implicitly calls the Frame no-argument //constructor and then adds components to the window. } public boolean handleEvent(Event event) { if (event.id == Event.WINDOW_DESTROY) { if (inAnApplet) { dispose(); } else { System.exit(0); } } return super.handleEvent(event); } . . . public static void main(String args[]) { MenuWindow window = new MenuWindow(); window.inAnApplet = false; window.setTitle("MenuWindow Application"); window.pack(); window.show(); } } Sử dụng Labels Là thành phần đơn giản nhất của UI Components, là một chuỗi kí tự có thể được dùng làm nhãn cho các UI Components khác. Labels không sửa được, nó chỉ làm nhãn cho các UI Components khác trên màn hình Lợi điểm của Lables so vớI các chuỗI kí tự thông thường khác là: Bạn không phảI tự vẽ lạI Labels. Labels là những thành phần của AWT và AWT theo dõi và làm việc đó Labels tuân theo sự sắp xếp của Panel chứa nó và có thể căn chỉnh với các UI Components khác Labels chứa chuỗi không thể sửa đổi được mà chỉ dùng để mô tả các thành phần khác của AWT Để tạo một Label, sử dụng một trong các cấu trúc sau: Label() tạo một nhãn rỗng, với chuỗi được canh chỉnh bên trái. Label(String) tạo một chuỗi có nội dung là String cũung được canh chỉnh bên trái. Label(String,int) tạo một nhãn có nội dung là String Tham số Int bao gồm: Label.RIGHT: chuỗi được canh chỉnh bên phải Label.LEFT : chuỗi được canh chỉnh bên trái Label.CENTER: chuỗi được canh chỉnh giữa Bạn có thể thay đổi font của Label bằng phương thức setFont() Sau đây là một ví dụ minh hoạ sử dụng Label import java.awt.*; public class LabelTest extends java.applet.Applet { public void init() { setFont(new Font ("Helvetica", Font.BOLD, 14)); setLayout(new GridLayout(3,1)); add(new Label("aligned left", Label.LEFT)); add(new Label("aligned center", Label.CENTER)); add(new Label("aligned right", Label.RIGHT)); } } Sử dụng Lists Lớp List cung cấp một vùng có thể cuộn được mà trong đó nó chứa các chuỗi văn bản có thể chọn được (một dòng một chuỗi). Người sử dụng có thể chọn bạn cách kích chuột. Lists có thể cho phép chọn nhiều hay chỉ có một sự lựa chộn trong một thời điểm. Ví dụ : ...//Where instance variables are declared: TextArea output; List spanish, italian; ...//Where initialization occurs: //Build first list, which allows multiple selections. spanish = new List(4, true); //prefer 4 items visible spanish.addItem("uno"); spanish.addItem("dos"); spanish.addItem("tres"); spanish.addItem("cuatro"); spanish.addItem("cinco"); spanish.addItem("seis"); spanish.addItem("siete"); //Build second list, which allows one selection at a time. italian = new List(); //Defaults to none visible, only one selectable italian.addItem("uno"); italian.addItem("due"); italian.addItem("tre"); italian.addItem("quattro"); italian.addItem("cinque"); italian.addItem("sei"); italian.addItem("sette"); . . . public boolean action(Event e, Object arg) { if (e.target instanceof List) { String language = (e.target == spanish) ? "Spanish" : "Italian"; output.appendText("Action event occurred on \"" + (String)arg + "\" in " + language + ".\n"); } return true; } public boolean handleEvent(Event e) { if (e.target instanceof List) { List list = (List)(e.target); String language = (list == spanish) ? "Spanish" : "Italian"; switch (e.id) { case Event.LIST_SELECT: int sIndex = ((Integer)e.arg).intValue(); output.appendText("Select event occurred on item #" + sIndex + " (\"" + list.getItem(sIndex) + "\") in " + language + ".\n"); break; case Event.LIST_DESELECT: int dIndex = ((Integer)e.arg).intValue(); output.appendText("Deselect event occurred on item #" + dIndex + " (\"" + list.getItem(dIndex) + "\") in " + language + ".\n"); } } return super.handleEvent(e); } Sử dụng Menus Applet sau cho thấy nhiều nét đặc trưng của menu giống như menu bạn đã sử dụng. Cửa sổ đưa ra một thanh menu (Menu Bar) chứa năm menu. Mỗi menu chứa một hoặc nhiều menu con Menu chỉ tồn tại trên Menu Bar và Menu Bar chỉ tồn tại khi nó gắn với những cửa sổ (Đặc biệt là Frame) AWT cung cấp những lớp con MenuComponent sau để hổ trợ menu: MenuItem CheckboxMenuItem Menu MenuBar Đây là đoạn mã chỉ ra các phương thức, cư xử của menu: public class MenuWindow extends Frame { . . . public MenuWindow() { MenuBar mb; Menu m1, m2, m3, m4, m4_1, m5; MenuItem mi1_1, mi1_2, mi3_1, mi3_2, mi3_3, mi3_4, mi4_1_1, mi5_1, mi5_2; CheckboxMenuItem mi2_1; ...//Add the output displayer to this window... //Build the menu bar. mb = new MenuBar(); setMenuBar(mb); //Build first menu in the menu bar. //Specifying the second argument as true //makes this a tear-off menu. m1 = new Menu("Menu 1", true); mb.add(m1); mi1_1 = new MenuItem("Menu Item 1_1"); m1.add(mi1_1); mi1_2 = new MenuItem("Menu Item 1_2"); m1.add(mi1_2); //Build help menu. m5 = new Menu("Menu 5"); mb.add(m5); //just setting the help menu doesn't work; must add it mb.setHelpMenu(m5); mi5_1 = new MenuItem("Menu Item 5_1"); m5.add(mi5_1); mi5_2 = new MenuItem("Menu Item 5_2"); m5.add(mi5_2); //Build second menu in the menu bar. m2 = new Menu("Menu 2"); mb.add(m2); mi2_1 = new CheckboxMenuItem("Menu Item 2_1"); m2.add(mi2_1); //Build third menu in the menu bar. m3 = new Menu("Menu 3"); mb.add(m3); mi3_1 = new MenuItem("Menu Item 3_1"); m3.add(mi3_1); mi3_2 = new MenuItem("Menu Item 3_2"); m3.add(mi3_2); m3.addSeparator(); mi3_3 = new MenuItem("Menu Item 3_3"); m3.add(mi3_3); mi3_4 = new MenuItem("Menu Item 3_4"); mi3_4.disable(); m3.add(mi3_4); //Build fourth menu in the menu bar. m4 = new Menu("Menu 4"); mb.add(m4); m4_1 = new Menu("Submenu 4_1"); m4.add(m4_1); mi4_1_1 = new MenuItem("Menu Item 4_1_1"); m4_1.add(mi4_1_1); } . . . public boolean action(Event event, Object arg) { String str = "Action detected"; if (event.target instanceof MenuItem) { MenuItem mi=(MenuItem)(event.target); str += " on " + arg; if (mi instanceof CheckboxMenuItem) { str += " (state is " + ((CheckboxMenuItem)mi).getState() + ")"; } MenuContainer parent = mi.getParent(); if (parent instanceof Menu) { str += " in " + ((Menu)parent).getLabel(); } else { str += " in a container that isn't a Menu"; } } str += ".\n"; ...//Display the string in the output area... return false; } Sử dụng Panels Lớp Panel là một lớp con Container. Bạn có thể sử dụng nó đẻ nắm bắt các Component, hoặc bạn có thể định nghĩa một lớp con để điều khiển các chức năng đặc biệt. Lớp Applet là một lớp con Panel với sự móc nối đặc biệt cho các Browser hoặc khung nhìn cho Applet. Sau đây là một ví dụ dùng Panel để chứa một vài Component : Panel p1 = new Panel(); p1.add(new Button("Button 1")); p1.add(new Button("Button 2")); p1.add(new Button("Button 3")); Sau đây là một ví dụ của lớp con Panel dùng để vẽ một khung. class FramedArea extends Panel { public FramedArea(CoordinatesDemo controller) { ...//Set the layout manager. //Add any Components this Panel contains... } //Ensure that no Component is placed on top of the frame. //The inset values were determined by trail and error. public Insets insets() { return new Insets(4,4,5,5); } //Draw the frame at this Panel's edges. public void paint(Graphics g) { Dimension d = size(); Color bg = getBackground(); g.setColor(bg); g.draw3DRect(0, 0, d.width - 1, d.height - 1, true); g.draw3DRect(3, 3, d.width - 7, d.height - 7, false); } } Sử dụng Scrollbars Scrollbars có hai cách sử dụng: Scrollbar có thể hoạt động như một con trượt cho người dùng lôi kéo để xác lập giá trị. Như điều khiển cuộn một ô vuông(Scroll pane). Scrollbars trong Scroll panes cho người dùng chọn chính xác vùng cần hiển thị. Để tạo một scrollbar, bạn cần tạo một thành phần của lớp Scrollbar. Bạn phải xác lập các giá trị ban đầu của Scrollbar bằng việc gọi phương thức setValues() trước khi Scrollbar hiển thị lên màn hình. int orientation Chỉ cho biết hoặc có thể thanh nằm ngang hoặc có thể là nằm đứng. Giá trị chỉ định là Scrollbar.HORIZONTAL hoặc Scrollbar.VERTICAL. int value Giá trị khởi đầu của scrollbar, cho vùng có thể điều khiển của Scrollbars, có nghĩa là giá trị x (cho thanh cuộn ngang) và giá trị y (cho thanh cuộn đứng) của vùng cuộn mà có thể thấy đầu tiên khi nó hiển thị. int visible Kích thước của phần hiển thị của vùng có thể cuộn. int minimum Giá trị nhỏ nhất của scrollbar can have, thường là 0. int maximum Giá trị lớn nhất của scrollbar. Sau đây là hình vẽ minh hoạ ý nghĩa của các giá trị trên: Sau đây là đoạn mã cho Aplet trên. import java.awt.*; import java.applet.*; import java.net.URL; class ScrollableCanvas extends Canvas { Image image; int tx = 0; int ty = 0; Dimension preferredSize; ScrollableCanvas(Image img, Dimension prefSize) { image = img; preferredSize = prefSize; } public Dimension minimumSize() { return new Dimension(10, 10); } public Dimension preferredSize() { return preferredSize; } public void paint(Graphics g) { g.translate(-tx, -ty); g.drawImage(image, 0, 0, getBackground(), this); } } public class ImageScroller extends Applet { Scrollbar vert; Scrollbar horz; ScrollableCanvas canvas; boolean inAnApplet = true; String imageFile = "../images/people.gif"; Dimension imageSize = new Dimension(600, 320); Dimension preferredImageSize = new Dimension(300, 100); //This method assumes this Applet is visible. public void init() { Image img; if (inAnApplet) { img = getImage(getCodeBase(), imageFile); } else { img = Toolkit.getDefaultToolkit().getImage(imageFile); } canvas = new ScrollableCanvas(img, preferredImageSize); //Create horizontal scrollbar. horz = new Scrollbar(Scrollbar.HORIZONTAL); //Create vertical scrollbar. vert = new Scrollbar(Scrollbar.VERTICAL); //Add Components to the Applet. setLayout(new BorderLayout()); add("Center", canvas); add("East", vert); add("South", horz); validate(); //Now that we've validated, then assuming this Applet is //visible, the canvas size is valid and we can adjust the //scrollbars to match the image area. [CHECK] resizeHorz(); resizeVert(); } public boolean handleEvent(Event evt) { switch (evt.id) { case Event.SCROLL_LINE_UP: case Event.SCROLL_LINE_DOWN: case Event.SCROLL_PAGE_UP: case Event.SCROLL_PAGE_DOWN: case Event.SCROLL_ABSOLUTE: if (evt.target == vert) { canvas.ty = ((Integer)evt.arg).intValue(); canvas.repaint(); } if (evt.target == horz) { canvas.tx = ((Integer)evt.arg).intValue(); canvas.repaint(); } } return super.handleEvent(evt); } //Don't call this until the canvas size is valid. void resizeHorz() { int canvasWidth = canvas.size().width; if (canvasWidth <= 0) { System.out.println("Canvas has no width; can't resize scrollbar"); return; } //Shift everything to the right if we're displaying empty space //on the right side. if ((canvas.tx + canvasWidth) > imageSize.width) { int newtx = imageSize.width - canvasWidth; if (newtx < 0) { newtx = 0; } canvas.tx = newtx; } horz.setValues(//draw the part of the image that starts at this x: canvas.tx, //amount to scroll for a "page": (int)(canvasWidth * 0.9), //minimum image x to specify: 0, //maximum image x to specify: imageSize.width - canvasWidth); //"visible" arg to setValues() has no effect after scrollbar is visible. horz.setPageIncrement((int)(canvasWidth * 0.9)); return; } //Don't call this until the canvas size is valid. void resizeVert() { int canvasHeight = canvas.size().height; if (canvasHeight <= 0) { System.out.println("Canvas has no height; can't resize scrollbar"); return; } //Shift everything downward if we're displaying empty space //on the bottom. if ((canvas.ty + canvasHeight) > imageSize.height) { int newty = imageSize.height - canvasHeight; if (newty < 0) { newty = 0; } canvas.ty = newty; } vert.setValues(//initially draw part of image starting at this y: canvas.ty, //visible arg--amount to scroll for a "page": (int)(canvasHeight * 0.9), //minimum image y to specify: 0, //maximum image y to specify: imageSize.height - canvasHeight); //"visible" arg to setValues() has no effect after scrollbar is visible. vert.setPageIncrement((int)(canvasHeight * 0.9)); return; } public void paint(Graphics g) { //This method probably was called due to applet being resized. resizeHorz(); resizeVert(); return; } } Sử dụng Scroll Panes ScrollPane quản lí thành phần con đơn lẻ, chỉ hiển thị phần mà không gian cho phép. Mặc định, thanh cuộn của Scroll pane chỉ hiển thị khi cần thiết. Ví dụ, nếu Scoll pane đủ rộng để hiển thị thành phần con của nó theo bề ngang thì thyanh cuộn ngang của Scoll pane sẽ không cần thiết và mặc định thanh cuộn ngang của Scoll pane sẽ không xuất hiện. Hình sau cho thấy một Aplet có một Scoll pane, nó có cả hai thanh cuộn. Sau đây là đoạn mã tạo một Scoll pane và đặt thành phần con vào trong đó: ScrollPane sp1 = new ScrollPane(); sp1.add(aComponent); Khi bạn tạo một một Scoll pane, bạn có thể xác lập thông số để xác định khi nào hiển thị thanh cuộn, sử dụng một trong 3 giá trị sau: SCROLLBARS_AS_NEEDED Giá trị mặc định, hiển thị thanh cuộn khi cần thiết. SCROLLBARS_ALWAYS Luôn luôn hiển thị thanh cuộn. SCROLLBARS_NEVER Không bao giờ hiển thị thanh cuộn. Bạn nên chọn giá trị này khi bạn không muốn người sử dụng trực tiếp điều khiển phần mà thành phần con hiển thị. Đây là một ví dụ xác lập quyền hiển thị thanh cuộn: ScrollPane sp2 = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); Sử dụng TextAreas and TextFields Lớp TextArea và TextField hiển thị văn bản có thể lựa chọn và thay thể được. Bạn có thể dùng lớp con TextArea và TextField để thi hành các thao tác như kiểnt ra lỗi nhập liệu. Như với mọi Component, bạn có thể xác lập màu nền và màu chữ của TextAreas and TextFields. Tuy nhiên bạn không thể thay đổi hình thức cơ bản của nó. TextArea và TextField là các lớp con của TextComponent. Từ TextComponent nó có thể thừa kế các phương thức cho phép chúng xác lập và lấy giá trị được chọn. Ví dụ : //Where instance variables are defined: TextField textField; TextArea textArea; public void init() { textField = new TextField(20); textArea = new TextArea(5, 20); textArea.setEditable(false); ...//Add the two components to the panel. } public boolean action(Event evt, Object arg) { String text = textField.getText(); textArea.appendText(text + "\n"); textField.selectAll(); return true; } Lớp cha TextComponent cung cấp các phương thức getText(), setText(), setEditable(), và selectAll() dùng trong đoạn mã trên. Nó cũng cung cấp các phương thức sau :: getSelectedText(), isEditable(), getSelectionStart(), và getSelectionEnd(). Nó cũng cung cấp phương thức select() để cho bạn có thể chọn đoạn văn bản từ vị trí đầu và vị trí cuối. Lớp TextField có 4 cấu trúc: TextField(), TextField(int), TextField(String), and TextField(String, int). giá trị int xác lập số cột trong TextField. Giá trị String xác lập chuỗi mà xuất hiện ban đàu trong TextField. Lớp TextField cũng cung cấp các phương thức sau: int getColumns() Trả về số cột trong Text Field. setEchoChar() Xác lập laọi kí tự hiển thị, nó rất có ích cho việc nhập mật khẩu. char getEchoChar() boolean echoCharIsSet() các phương thức trên cho biết thông tin về kí tự hiển thị. Giống như lớp TextField, lớp TextArea cũng có 4 cấu trúc: TextArea(), TextArea(int, int), TextArea(String), and TextArea(String, int, int). Giá trị Int xác lập số hàng và số cột trong TextArea. Giá trị String xác lập chuỗi ban đàu cho TextArea. Lớp TextArea cung cấp phương thức appendText() dùng trong đoạn mã trên. Nó cũng cung cấp các phương thức sau: int getRows(), int getColumns() Trả về số hàng và số cột trong TextArrea. void insertText(String, int) Chèn một chuỗi vào vịt trí Int. void replaceText(String, int, int) Thay thế đoạn văn bảng từ vị trí int đến vị trí int bằng chuỗi String. Các kiểu sự kiện mới của AWT Giới thiệu các kiểu sự kiện mới của AWT Các sự kiện (events) được phát ra bởi nguồn sự kiện. Một hoặc nhiều listeners có thể đăng kí các thông báo về các Event. Đôi khi các kiểu này còn được gọi là delegatio Một ví dụ đơn giản Sau đây là đoạn mã thực thi sự nắm bẳ sự kiện cho một Button: public class Beeper ... implements ActionListener { ... //where initialization occurs: button.addActionListener(this); ... public void actionPerformed(ActionEvent e) { ...//Make a beep sound... } } Một ví dụ về các kiểu sự kiện khác Aplet sau hiển thị một một vùng hình chữ nhật và một vùng văn bản ... //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); //hack to scroll to bottom } } 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ụ : 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. */ 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. MyClass extends Applet { ... someObject.addMouseListener(new MyAdapter()); ... class MyAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { ...//Event handler implementation goes here... } } } Năm bắt các sự kiện của AWT chuẩn Listener Interface Adapter Class Methods ActionListener none actionPerformed AdjustmentListener none adjustmentValueChanged ComponentListener ComponentAdapter componentHidden componentMoved componentResized componentShown ContainerListener ContainerAdapter componentAdded componentRemoved FocusListener FocusAdapter focusGained focusLost ItemListener none itemStateChanged KeyListener KeyAdapter keyPressed keyReleased keyTyped MouseListener MouseAdapter mouseClicked mouseEntered mouseExited mousePressed mouseReleased MouseMotionListener MouseMotionAdapter mouseDragged mouseMoved TextListener none textValueChanged WindowListener WindowAdapter windowActivated windowClosed windowClosing windowDeactivated windowDeiconified windowIconified windowOpened Các sự kiện được tạo ra bởi các thành phần của AWT AWT Component Types of Events It Can Generate action adjustment component container focus item key mouse mouse motion text window Button X X X X X X Canvas X X X X X Checkbox X X X X X X CheckboxMenuItem Note: This is not a Component subclass! * X Choice X X X X X X Component X X X X X Container X X X X X X Dialog X X X X X X X Frame X X X X X X X Label X X X X X List X X X X X X X MenuItem Note: This is not a Component subclass! X Panel X X X X X X Scrollbar X X X X X X ScrollPane X X X X X X TextArea X X X X X X TextComponent X X X X X X TextField X X X X X X X Window X X X X X X X Viết một Action Listener Khi người sử dụng kich 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 dổ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. Ví dụ về 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. Thiết kế các thành phần trong một Container 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)); add("North", new Button("North")); add("South", new Button("South")); add("East", new Button("East")); add("West", new Button("West")); add("Center", new Button("Center")); Quan trọng: khi thêm một thành phần vào một Container sử dụng BorderLayout, bạn nên dùng phương thức add() hai thông số, và thông số thứ nhất phải là "North", "South", "East", "West", hoặc "Center". Nếu bạn sử dụng phương thức add()một thông số hay bạn không xác lập thông số thứ nhất thì thành phần đó sẽ không hiển thị. Theo mặc định, BorderLayout không đặt khoảng trống giữa các thành. Muốn vậy, bạn phải xác lập nó bằng cách dùng cấu trúc sau: public BorderLayout(int horizontalGap, int verticalGap) Sử dụng CardLayout Sau đây là một Applet cho thấy CardLayout làm việc như thế nào. //Where instance variables are declared: Panel cards; final static String BUTTONPANEL = "Panel with Buttons"; final static String TEXTPANEL = "Panel with TextField"; //Where the container is initialized: cards = new Panel(); cards.setLayout(new CardLayout()); ...//Create a Panel named p1. Put buttons in it. ...//Create a Panel named p2. Put a text field in it. cards.add(BUTTONPANEL, p1); 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); . . . public boolean action(Event evt, Object arg) { if (evt.target instanceof Choice) { ((CardLayout)cards.getLayout()).show(cards,(String)arg); return true; } return false; } Như đoạn mã trên, bạn có thể sử dụng phương thức show() của CardLayout để xác lập thành phần hiển thị hiện tại. Thông số thứ nhất của phương thức show() là Container mà CardLayout điều khiển. thông số thứ hai là chuỗi để xác định thành phần hiển thị. Chuỗi này giống như chuỗi của thành phần thêm vào Container. Theo sau là tất cả các phương thức của CardLayout mà có thể cho phép chọn một thành phần. cho mỗi phương thức, thông số thứ nhất Container cho CardLayout là một Layout Manager. public void first(Container parent) public void next(Container parent) public void previous(Container parent) public void last(Container parent) public void show(Container parent, String name) Sử dụng FlowLayout Sau đây là một Applet cho thấy FlowLayout hoạt động như thế nào. setLayout(new FlowLayout()); setFont(new Font("Helvetica", Font.PLAIN, 14)); add(new Button("Button 1")); add(new Button("2")); 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)); add(new Button("Button 1")); add(new Button("2")); add(new Button("Button 3")); add(new Button("Long-Named Button 4")); add(new Button("Button 5")); Cấu trúc trên cho thấy lớp GridLayout tạo một đối tượng có hai cột và nhiều hàng. Đây là một trong hai cấu trúc cho GridLayout. Sau đây là cách khai báo cho cả hai cấu trúc này: public GridLayout(int rows, int columns) public GridLayout(int rows, int columns, int horizontalGap, int verticalGap) Sử dụng GridBagLayout Theo sau là một vài đoạn lệnh tiêu biểu trong một Container có sử dụng GridBagLayout. GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setLayout(gridbag); //For each component to be added to this container: //...Create the component... //...Set instance variables in the GridBagConstraints instance... gridbag.setConstraints(theComponent, c); add(theComponent); Bạn có thể sử dụng lại một đối tượng của GridBagConstraints cho nhiều thành phần khác nhau, ngay cả khi các thành phần đó có sự ràng buộc khác nhau. 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); gridbag.setConstraints(button, c); add(button); } public GridBagWindow() { GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setFont(new Font("Helvetica", Font.PLAIN, 14)); setLayout(gridbag); c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; makebutton("Button1", gridbag, c); makebutton("Button2", gridbag, c); makebutton("Button3", gridbag, c); c.gridwidth = GridBagConstraints.REMAINDER; //end of row makebutton("Button4", gridbag, c); c.weightx = 0.0; //reset to the default makebutton("Button5", gridbag, c); //another row c.gridwidth = GridBagConstraints.RELATIVE; //next to last in row makebutton("Button6", gridbag, c); c.gridwidth = GridBagConstraints.REMAINDER; //end of row makebutton("Button7", gridbag, c); c.gridwidth = 1; //reset to the default c.gridheight = 2; c.weighty = 1.0; makebutton("Button8", gridbag, c); c.weighty = 0.0; //reset to the default c.gridwidth = GridBagConstraints.REMAINDER; //end of row c.gridheight = 1; //reset to the default makebutton("Button9", gridbag, c); makebutton("Button10", gridbag, c); } Tạo một Layout Manager Chú ý: Trước khi bắt đàu thiết kế một Layout Manager, chắc chắn rằng không tồn tại một Layout Manager sè hoạt động. Cá biệt, GridBagLayout đủ mềm dẻo để làm việc trong nhiều trường hợp khác nhau. Để tạo một Layout Manager, bạn phải tạo một lớp để thực thi giao diện LayoutManager. LayoutManager yêu cầu quan hệ chặt chẽ với nó để thực thi năm phương thức: public void addLayoutComponent(String name, Component comp) Chỉ được gọi bằng phương thức add(name, component) của Container. public void removeLayoutComponent(Component comp) Gọi bởi những phương thức remove() và removeAll() của Container. public Dimension preferredLayoutSize(Container parent) Gọi bởi phương thức preferredSize() của Container, có thể tự gọi dưới mọi tình huống. public Dimension minimumLayoutSize(Container parent) Gọi bởi phương thức minimumSize() của Container, có thể tự gọi dưới mọi tình huống. public void layoutContainer(Container parent) Gọi khi Container hiển thị lần đầuis first displayed, và mọi lúc nó tahy đổi kích thước. Làm việc thiếu Layout Manager Mặc dù có thể làm việc mà không cần Layout Manager, bạn nên dùng Layout Manager nếu có thể. Layout managers dể thay đổi kích thước của Container và điều chỉnh hình dạng của các thành phần phụ thuộc vào Platform. Nó cùng có thể được sử dụng lạ bới các Container va các chương trình khác. nếu Custom Container sè không tái sử dụng, không thể thay đổi kích thước, và hoàn toàn có thể điều khiển được các thông số phụ thuộc vào hệ thống như Font và hình dạng các thành phần. Ví dụ: public class NoneWindow extends Frame { . . . 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); } public void paint(Graphics g) { if (!laidOut) { Insets insets = insets(); /* * We're guaranteed that insets() will return a valid Insets * if called from paint() -- it isn't valid when called from * the constructor. * * We could perhaps cache this in an ivar, but insets can * change, and when they do, the AWT creates a whole new * Insets object; the old one is invalid. */ b1.reshape(50 + insets.left, 5 + insets.top, 50, 20); b2.reshape(70 + insets.left, 35 + insets.top, 50, 20); b3.reshape(130 + insets.left, 15 + insets.top, 50, 30); laidOut = true; } } . . . } Các bài toán về Layout 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 ghi đè lên 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 thaǹh 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ể tahy đổ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 khhong? 4. Làm việc với đồ hoạ Tổng quan về hổ trợ đồ hoạ của AWT Khi phương thức repaint()được gọi, AWT gọi tới phương thức update() của để yêu cầu thành phần đó tự vẽ lại. phương thức update() gọi phương thức paint() của thành phần đó. Đối tượng đồ hoạ Thông số duy nhất cho các phương thức paint() và update()là một đối tượng đồ hoạ(Graphics). Đối tượng Graphics là chìa khoá cho tất cả các công việc vẽ này. Nó cung cấp hai kiểu vẽ cơ bản: kiểu vẽ đơn sơ (như lines, rectangles, and text) và hình ảnh Bên cạnh các kiểu vẽ trên, đối tượng Graphics cung cấp một ngữ cảnh vẽ ở trạng thái duy trì như vùng vẽ hiện tại và màu vẽ hiện tại. Bạn có thể giảm bớt vùng vẽ bằng cách cắt xén nó, nhưng bạn không bao bao giờ tăng được vùng vẽ. Do đó, đối tượng Graphics chắn chắn một thành phần chỉ có thể vẽ được trong vùng quản lí của nó. Hệ thống toạ độ Mỗi thành phần đều có hệ thống toạ độ riêng, từ (0, 0) đến (width - 1, height - 1), với mỗi đơn vị tính là Pixel. Bốn hình thức của phương thức repaint() public void repaint() Gọi phương thức update() ngay lập tức. public void repaint(long time) Gọi phương thức update() sau time mili giây nữa. public void repaint(int x, int y, int width, int height) Gọi phương thức update() ngay lập tức và chỉ vẽ lại vùng giới hạn. public void repaint(long time, int x, int y, int width, int height) Gọi phương thức update() sau time mili giây nữa và chỉ vẽ lại vùng giới hạn Sử dụng các màu gốc của đồ hoạ Vẽ các hình dạng Lớp Graphics định nghĩa các phương thức vẽ cho các loại hình ảnh sau: Đường thẳng (drawLine(), vẽ đưòng thẳng với màu hiện tại của đối tượng Graphics, màu này được xác lập như màu chữ của đối tượng) Hình chữ nhật (drawRect(), fillRect(), và clearRect()) Hình chữ nhật nỗi hoặc chìm (draw3DRect() và fill3DRect()) Round-edged rectangles (drawRoundRect() và fillRoundRect()) Hình Oval (drawOval() and fillOval()) Ve cung (drawArc() and fillArc()) Vẽ các đa giác (drawPolygon() and fillPolygon()) Ví dụ 1: ví dụ đơn giản về vẽ hình chữ nhật Sau đây chỉ là những đoạn lệnh phục vụ việc vé hình chữ nhật: //In FramedArea (a Panel subclass): public void paint(Graphics g) { Dimension d = size(); Color bg = getBackground(); //Draw a fancy frame around the applet. g.setColor(bg); g.draw3DRect(0, 0, d.width - 1, d.height - 1, true); g.draw3DRect(3, 3, d.width - 7, d.height - 7, false); } //In CoordinateArea (a Canvas subclass): public void paint(Graphics g) { //If user has clicked, paint a tiny rectangle where click occurred if (point != null) { g.fillRect(point.x - 1, point.y - 1, 2, 2); } } Applet tạo (và chứa) một đối tượng FramedArea, lần lượt tạo (và chứa) một đối tượng CoordinateArea. Lệnh đầu gọi tới phương thức draw3DRect() để tạo một hình chữ nhật chiếm hết vùng cho phép vẽ của FramedArea. Thông số true xác định rằng hình chữ nhật phải nổi. Lệnh thứ hai gọi draw3DRect() tạo hình chữ nhật thứ hai nhỏ hơn, thông số false xác định hình chữ nhật sẽ xuất hiện chìm xuống. Bên cạnh đó, hai lệnh trên có tác dụng với FramedArea là chứa đối tượng CoordinateArea. CoordinateArea sử dụng fillRect() để tô hai pixel một tại vị trí người sử dụng nhấp chuột. Ví dụ 2: sử dụng hình chữ nhật để chỉ ra vùng được chọn Đây là một Applet mà bạn có thể sử dụng các phương thức cơ bản để thực thi vùng được chọn trong chương trình vẽ. Khi người sử dụng kéo chuột, Applet sẽ hiển thị liên tục một hình chữ nhật. Hình chữ nhật bắt đầu từ điểm mà người sử dụng ấn chuột lần đầu và kết thúc tại vị trí con trỏ chuột hiện tại. Sau đây là các lệnh mới quan trọng nhất cho Applet trên: class SelectionArea extends Canvas { . . . public boolean mouseDown(Event event, int x, int y) { currentRect = new Rectangle(x, y, 0, 0); repaint(); return false; } public boolean mouseDrag(Event event, int x, int y) { currentRect.resize(x - currentRect.x, y - currentRect.y); repaint(); return false; } public boolean mouseUp(Event event, int x, int y) { currentRect.resize(x - currentRect.x, y - currentRect.y); repaint(); return false; } public void paint(Graphics g) { Dimension d = size(); //If currentRect exists, paint a rectangle on top. if (currentRect != null) { Rectangle box = getDrawableRect(currentRect, d); controller.rectChanged(box); //Draw the box outline. g.drawRect(box.x, box.y, box.width - 1, box.height - 1); } } Rectangle getDrawableRect(Rectangle originalRect, Dimension drawingArea) { . . . //Make sure rectangle width and height are positive. . . . //The rectangle shouldn't extend past the drawing area. . . . } } Như bạn thấy, vùng được chọn sẽ giữ được hình chữ nhật hiện tại đang chọn, sử dụng đối tượng Rectangle được gọi bởi currentRect. Khi được thực thi, currentRect giữ nguyên toạ độ gốc (currentRect.x, currentRect.y) trong khi người sử dụng kéo chuột. Điều này có nghĩa là chiều cao và chiều rộng của hình chữ nhật sẽ không quan trọng. Tuy nhiên, những phương thức drawXxx() và fillXxx() không vẽ bất cứ thứ gì nếu chiều rộng hoặc chiều cao không có. Vì lí do này, nên khi SelectionArea vẽ một hình chữ nhật, nó phải xác định điểm góc tái bên trên hình chữ nhật để chiều rộng và chiều cao đwocj rõ ràng hơn. Lớp SelectionArea định nghĩa phương thức getDrawableRect() để thực hiện các pháep tính toán cần thiết cho việc tìm ra điểm đó. Phương thức getDrawableRect() cũng chắn chắn điểm đó không vượt ra khỏi vùng được phép vẽ Ví dụ 3: ví dụ về vẽ các hình ảnh Applet demonstrates minh hạo đầy đủ các hình ảnh được vẽ và được tô như thế nào. Trừ khi Font mặc định của Applet quá nhỏ, chuỗi sẽ được hiển thị rất xấu. Sau đây chỉ là các lệnh vẽ các loại hình học cơ bản. Các giá trị rectHeight và rectWidth xác định kích thước mỗi vùng cho việc vẽ các hình ảnh đó. Các giá trị x và y được thay đổi cho mỗi hình, do đó các hình không được vẽ trên nhau. Color bg = getBackground(); Color fg = getForeground(); . . . // drawLine() g.drawLine(x, y+rectHeight-1, x + rectWidth, y); // x1, y1, x2, y2 . . . // drawRect() g.drawRect(x, y, rectWidth, rectHeight); // x, y, width, height . . . // draw3DRect() g.setColor(bg); g.draw3DRect(x, y, rectWidth, rectHeight, true); g.setColor(fg); . . . // drawRoundRect() g.drawRoundRect(x, y, rectWidth, rectHeight, 10, 10); // x, y, w, h, arcw, arch . . . // drawOval() g.drawOval(x, y, rectWidth, rectHeight); // x, y, w, h . . . // drawArc() g.drawArc(x, y, rectWidth, rectHeight, 90, 135); // x, y, w, h . . . // drawPolygon() Polygon polygon = new Polygon(); polygon.addPoint(x, y); polygon.addPoint(x+rectWidth, y+rectHeight); polygon.addPoint(x, y+rectHeight); polygon.addPoint(x+rectWidth, y); //polygon.addPoint(x, y); //don't complete; fill will, draw won't g.drawPolygon(polygon); . . . // fillRect() g.fillRect(x, y, rectWidth, rectHeight); // x, y, width, height . . . // fill3DRect() g.setColor(bg); g.fill3DRect(x, y, rectWidth, rectHeight, true); g.setColor(fg); . . . // fillRoundRect() g.fillRoundRect(x, y, rectWidth, rectHeight, 10, 10); // x, y, w, h, arcw, arch . . . // fillOval() g.fillOval(x, y, rectWidth, rectHeight); // x, y, w, h . . . // fillArc() g.fillArc(x, y, rectWidth, rectHeight, 90, 135); // x, y, w, h . . . // fillPolygon() Polygon filledPolygon = new Polygon(); filledPolygon.addPoint(x, y); filledPolygon.addPoint(x+rectWidth, y+rectHeight); filledPolygon.addPoint(x, y+rectHeight); filledPolygon.addPoint(x+rectWidth, y); //filledPolygon.addPoint(x, y); g.fillPolygon(filledPolygon); Làm việc với chuỗi Khi viết lệnh vẽ chuỗi, trước tiên bạn nên quan tâm có sử dụng thành phần có định hướng chuỗi hay không như Label, TextField, hoặc TextArea. Nếu các thành phần này không thích hợp, bạn có thể sử dụng các phương thức drawBytes(), drawChars(), hoặc drawString() của đối tượng Graphics. Sau đây là một đoạn lệnh ví dụ để vẽ một chuỗi ra màn hình: g.drawString("Hello World!", x, y); x,y là toạ độ nơi chuỗi hiển thị. Nhận biết thông tin về Font: FontMetrics Ví dụ : boolean fontFits = false; Font font = g.getFont(); FontMetrics fontMetrics = g.getFontMetrics(); int size = font.getSize(); String name = font.getName(); int style = font.getStyle(); while (!fontFits) { if ( (fontMetrics.getHeight() <= maxCharHeight) && (fontMetrics.stringWidth(longString) <= xSpace)) { fontFits = true; } else { if (size <= minFontSize) { fontFits = true; } else { g.setFont(font = new Font(name, style, --size)); fontMetrics = g.getFontMetrics(); } } } Đoạn lệnh trên sử dụng các phương thức getFont(), setFont(), và getFontMetrics() của đối tượng Graphics dể lấy và xác lập giá trị cho font hiện tại và lấy đối tượng FontMetrics tương ứng với Font. Từ các phương thức getHeight() và getStringWidth() của đối tượng FontMetrics, đoạn lệnh trên lấy kích thwocs ngang và dọc của Font đó. Hình ảnh sau minh hoạ vài thông tin về những thông tin về Font mà đối tượng FontMetrics cung cấp: Sau đây là các phương thức của FontMetrics có thể trả về thônh tin về kích thước dọc của Font: getAscent(), getMaxAscent() phương thức getAscent() trẻ về số Pixel nằm giữa ascender line và baseline. Nói chung, Ascender line miêu tả chiều cao điển hình của kí tự hoa. Đặc biệt, các giá trị ascent và descent được chọn bởi người thiết kế Font để miêu tả đúng chuỗi, hoặc độ dày của chữ, vì vậy chuỗi sẽ xuất hiện đúng với ý tưởng thiết kế. Ascent cung cấp đầy đủ khoảng trống cho kí tự, ngoại trừ khoảng trống cho các dấu của các kí tự hoa. Phương thức getMaxAscent() đếm chiều cao cho trường hợp này. getDescent(), getMaxDescent() phương thức getDescent() trả về số Pixel nằm giữa baseline và descender line. Trong hầu hết các loại Font, mọi kí tự đều kéo dài xuống Descender line tại điểm thấp nhất. Chỉ trong trường hợp bạn sử dụng phương thức getMaxDescent() để nhận khoảng không gian chắn cho kí tự đó được vẽ hết. getHeight() Trả về số Pixel được tìm thấy giữa Baseline của hai dòng chuỗi kí tự. getLeading() Trả về khoảng trống giữa hai dòng. getMaxAdvance() Chiều rộng nhất của kí tự trong bytesWidth(byte[], int, int) Chiều rộng của chuỗi được khai báo bởi một mảng các kí tự. Thông số Int đầu tiên xác định vị trí bắt đàu kí tự của chuỗi đó. Thông số Int thứ hai xác định số kí tự của chuỗi đó. charWidth(int), charWidth(char) Chiều rộng của một kí tự xác định. charsWidth(char[], int, int) Chiều rộng của kí tự trong mảng. stringWidth(String) Chiều rộng của chuỗi string. getWidths() Chiều rộng của mỗi kí tự trong ầ̉ kí tự đầu tiên. Sử dụng hình ảnh Nạp ảnh Sử dụng phương thức getImage() Lớp Applet cung cấp hai phương thức getImage(): public Image getImage(URL url) public Image getImage(URL url, String name) Chỉ có Applets mới có thể sử dụng phương thức getImage(). Hơn thế nữa, phương thức getImage() của Applet không làm việc cho đến khi nào Applet có một ngữ cảnh đầy đủ. Vì lí do này, những phương thức này không làm việc nếu nó được gọi trong một cấu trúc hoặc câu lệnh khai báo một biến minh hoạ. Bạn nên gọi phương thức init() thay vì gọi phương thức getImage(). Đoạn lệnh sau miêu tả việc sử dụng phương thức getImage() của Applet. //In a method in an Applet subclass: Image image1 = getImage(getCodeBase(), "imageFile.gif"); Image image2 = getImage(getDocumentBase(), "anImageFile.jpeg"); Image image3 = getImage(new URL("")); Lớp Toolkit khai báo hơn hai phương thức getImage(): public abstract Image getImage(URL url) public abstract Image getImage(String filename) bạn có thể nhận đối tượng Toolkit bằng cách gọi phương thức getDefaultToolkit() của lớp Toolkit hoặc gọi phương thức getToolkit() của các thành phần. Phương thức getToolkit() của thành phần trả về đối tượng Toolkit được sử dụng (hoặc sẽ được sử dụng) dể thực thi một thành phần. Sau đây là ví dụ minh hoạ việc sử dụng phương thức getImage() của Toolkit. Mỗi ứng dụng và Applet của Java có thể sử dụng các phương thức này, với Applet thwongf hạn chế vấn đề về bảo mật. Toolkit toolkit = Toolkit.getDefaultToolkit(); Image image1 = toolkit.getImage("imageFile.gif"); Image image2 = toolkit.getImage(new URL("")); Yêu cầu và theo đõi quá trình nạp ảnh: MediaTracker và ImageObserver AWT cung cấp hai cách thức cho việc theo dõi quá trình nạp ảnh: lớp MediaTracker và giao diện ImageObserver. Lớp MediaTracker đầy đủ cho mọi chương trình. Bạn có thể tạo một MediaTracker, và lệnh cho nó theo dõi một hoặc nhiều ảnh, và rồi yêu cầu nó cho biết tình trang cảu các ảnh này khi cần thiết. Giao diện ImageObserver cho phép bạn theo dõi sát nút hơn quá trình nạp ảnh so với lớp MediaTracker cho phép. Lớp tahnhf phần này sử dụng nó do đó các thành phần này vẽ lại các ảnh ngay sau khi ảnh được nạp. Để sử dụng giao diện ImageObserver, bạn thực thi phương thức imageUpdate() của ImageObserver và chắn chắn rằng các đối tượng thực thi phương thức đó được đăng kí như là một giao diện ImageOserver. Thôgn thường, sự đăng kí xảy ra khi bạn xác định một ImageObserver cho phương thức drawImage. Phương thức imageUpdate() được gọi bất cứ khi nào có các thông tin về ảnh Đây là một ví dụ thực thi phương thức imageUpdate()của giao diện Image Observer. Ví dụ này sử dụng phương thức imageUpdate() đẻ xác định vị trí của hai bức ảnh nagy sau khi biết kích thước của nó, và cử 100 milliseconds là vẽ lại nó cho đến khi nó được nạp hoàn chỉnh. public boolean imageUpdate(Image theimg, int infoflags, int x, int y, int w, int h) { if ((infoflags & (ERROR)) != 0) { errored = true; } if ((infoflags & (WIDTH | HEIGHT)) != 0) { positionImages(); } boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0); // Repaint immediately if we are done, otherwise batch up // repaint requests every 100 milliseconds repaint(done ? 0 : 100); return !done; //If done, no further updates required. } Tạo ảnh với MemoryImageSource Với sự trợ giúp của lớp MemoryImageSource, bạn có thể dễ dàng tạo ảnh. Đoạn lệnh ví dụ sau vẽ một ảnh kích thước 100x100 hiển thị mờ đi từ màu đen cho đến màu xanh theo trục X và mờ đi từ đen đến đỏ theo trục Y. int w = 100; int h = 100; int[] pix = new int[w * h]; int index = 0; for (int y = 0; y < h; y++) { int red = (y * 255) / (h - 1); for (int x = 0; x < w; x++) { int blue = (x * 255) / (w - 1); pix[index++] = (255 << 24) | (red << 16) | blue; } } Image img = createImage(new MemoryImageSource(w, h, pix, 0, w)); Hiển thị ảnh Sau đây là đoạn ví dụ minh hoạ việc hiển thị ảnh tại vị trí (0, 0) ở vùng quản lí của thành phần: g.drawImage(image, 0, 0, this); sau đây là ví dụ minh hoạ việc hiển thị ảnh với 300 pixel chiều rộng và 62 pixel chiều cao, và bắt đầu từ vị trí (90, 0): g.drawImage(myImage, 90, 0, 300, 62, this); Lớp Graphics khai báo phương thức drawImage() sau. Tất cả đều trả về giá trị Boolean, mặc dù giá trị này hiếm khi được sử dụng. Giá trị là true nếu ảnh đã hoàn toàn được nạp và haong toàn được vẽ; nếu khác, giá trị là false. public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer) public abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) public abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) Những phương thức drawImage()có các thông số sau: Image img Ảnh được vẽ. int x, int y Vị trí vẽ của ảnh. int width, int height Chiều rộng và chiều cao của ảnh được vẽ. Color bgcolor Màu được vẽ bên dưới của ảnh. Nó có thể cần thiết nếu ảnh chứa các pixel trong suốt. ImageObserver observer Đối tượng thực thi giao diện ImageObserver. Nó đăng kí đối tượng như là một ImageObserver vì thế nó không được thông báo bất cứ lúc nào mà có thông tin về ảnh. Mọi thành phần có thể đơn giản xác định vấn đề này. Lí do mà nó chỉ làm việc như là ImageObserver là vì lớp thành phần thực thi giao diện ImageObserver. Phương thức drawImage() trả về sau khi hiển thị ảnh hoàn toàn. Chế tác ảnh Hình ảnh trên minh hoạ dữ liệu ảnh được tạo như thế nào. Một image producer -- một đối tưong gắn chặt với giao diện ImageProducer – đưa ra một dữ liệu thô cho đối tượng Image. Image producer cung cấp dữ liệu này cho một image consumer -- một đối tương gắn chặt với giao diện ImageConsumer. Trừ khi bạn cần thiết phải chế tác hay tạo một hình ảnh cho mình, nếu không bạn không cần biết về image producers và consumers. AWT tự động sử dụng Image producers và consumers. AWT cung cấp công cụ chế tác ảnh bằng cách cho phép bạn chèn Image filters giữa các image producers và image consumers. Một image filter là một đối tượng ImageFilter có thể nằm giữa producer và consumer, sửa đổi dữ liệu ảnh trươvs khi consumer nhận nó. ImageFilter thực thi một giao diện ImageConsumer, từ khi image filters ngăn chặn các thông điệp mà producer gửi tới consumer. Hình sau minh hoạ image filter được đặt như thế nào ở giữa image producer và consumer. Sử dụng Image Filter Applet sau sử dụng một filter để quay một ảnh. public class ImageRotator extends Applet { . . . RotatorCanvas rotator; double radiansPerDegree = Math.PI / 180; public void init() { //Load the image. Image image = getImage(getCodeBase(), "../images/rocketship.gif"); ...//Create the component that uses the image filter: rotator = new RotatorCanvas(image); . . . add(rotator); . . . } public boolean action(Event evt, Object arg) { int degrees; ...//Get the number of degrees to rotate the image by. //Convert to radians. rotator.rotateImage((double)degrees * radiansPerDegree); return true; } } class RotatorCanvas extends Canvas { Image sourceImage; Image resultImage; public RotatorCanvas(Image image) { sourceImage = image; resultImage = sourceImage; } public void rotateImage(double angle) { ImageFilter filter = new RotateFilter(angle); ImageProducer producer = new FilteredImageSource( sourceImage.getSource(), filter); resultImage = createImage(producer); repaint(); } public void paint(Graphics g) { Dimension d = size(); int x = (d.width - resultImage.getWidth(this)) / 2; int y = (d.height - resultImage.getHeight(this)) / 2; g.drawImage(resultImage, x, y, this); } } Đoạn lệnh trên làm việc như thế nào nhận một đối tượng Image (thông thường dùng phương thức getImage()). Sử dụng phương thức getSource(), lấy dữ liệu (ImageProducer) cho đối tượng Image tạo một mô tả của Image filter, khởi tạo filter khi cần thiết. Tạo một đối tượng FilteredImageSource, bỏ qua cấu trúc của dữ liệu ảnh và đối tượng Filter. Với phương thức createImage(), tạo mới một đối tượng Image có một FilteredImageSource như là một Image producer. Trong ví dụ trên, phương thức rotateImage() của RotatorCanvasmethod thực thi các nhiệm vụ có quan hệ với việc sử dụng Image filter. Trừ bước đầu tiên ra, lấy đối tương Image thô, thực hiện bởi phương thức init() của Applet. Đối tượng Image này được chuyển tới RotatorCanvas, được đề cập tới như là sourceImage. Phưong thức rotateImage() thuyết minh cho image filter bằng cách gọi cấu trúc của Filter. Thông số cho cấu trúc này là một gócmà ảnh quay. ImageFilter filter = new RotateFilter(angle); Kế tiếp, phương thức rotateImage() tạo một minh hoạ FilteredImageSource của. thông số thứ nhất cho cấu trúc FilteredImageSource là nguồn ảnh, lấy được qua phương thức getSource(). Thông số thứ hai là đối tượng Filter. ImageProducer producer = new FilteredImageSource( sourceImage.getSource(), filter); Cuối cùng, câu lệnh tạo ảnh thứ hai, resultImage, bằng việc sử dụng phương thức createImage() của thành phần. Thông số duy nhất createImage() là FilteredImageSource được tạo bởi bước trên. resultImage = createImage(producer); Viết một Image Filter Tất cả các Image Filter phải là các lớp con của lớp ImageFilter. Nếu image filter sẽ được sửa đổi màu hoặc các Pixel trong suốt của ảnh, thì thay vì phải tạo trực tiếp một lớp con của ImageFilter, bạn có thể tạo một lớp con của RGBImageFilter. Tạo một lớp con ImageFilter Như đã đề cập ở phần trước, các Image filter thực thi giao diện ImageConsumer. ImageConsumer định nghĩa các phương thức sau: void setDimensions(int width, int height); void setProperties(Hashtable props); void setColorModel(ColorModel model); void setHints(int hintflags); void setPixels(int x, int y, int w, int h, ColorModel model, byte pixels[], int off, int scansize); void setPixels(int x, int y, int w, int h, ColorModel model, int pixels[], int off, int scansize); void imageComplete(int status); Lớp ImageFilter thực thi tất cả các phương thức trên. Ví dụ, ImageFilter thực thi phương thức setDimensions() như sau: public void setDimensions(int width, int height) { consumer.setDimensions(width, height); } Nhờ các phương thức của ImageFilter này, lớp con của bạn có thể không cần đến việc phải thực thi mọi phương thức của ImageConsumer. bạn chỉ cần thực thi một phương thức để chuyển giao dữ liệu mà bạn muốn thay đổi. Ví dụ, lớp CropImageFilter thực thi bốn phương thức: setDimensions(), setProperties(), và hai loại phương thức setPixels(). Nó cũng thực thi một cấu trúc với thông số là hình chữ nhật xác định cho việc cắt xén. Ví dụ khác, lớp RGBImageFilter thực thi vài phương thức trợ giúp, định nghĩa một phưong thức giúp đỡ trừu tượng để thực hiện việc thay đổi màu thật của mỗi pixel, và thực thi các phương thức sau của ImageConsumer: setColorModel() và hai loại phương thức setPixels(). Hầu hết Most, các filter thực thi những phương thức setPixels(). những phương thức này xác định chính xác dữ liệu ảnh được dùng để xây dựng một Image. một hoặc hai phương thức setPixels() có thể được gọi nhiều lần trong suốt quá trình xây dựng một Image. Mỗi lần gọi đều đưa tới ImageConsumer thông tin vùng bao hình chữ nhật của ảnh. Khi phương thức imageComplete() của ImageConsumer được gọi với mọi trạng thái trừ SINGLEFRAMEDONE, thì ImageConsumer có thể thừa nhận là nó có không thể nhận hơn nữa phương thức setPixels(). Một trạng thái imageComplete() của STATICIMAGEDONE xác định rằng không chỉ đã hoàn toàn nhận đầy đủ dữ kiệu ảnh, mà còn xác định rằng không có lỗi nào xảy ra. Hình ảnh minh hoạ và bảng sau mô tả cá c phương thức setPixels() và các thông số cho các phương thức đó. x, y Xác định vị trí của ảnh w, h Xác định chiều rộng và chiều cao cho mỗi vùng hình chữ nhật. model Xác định kiểu màu được sử dụng cho các Pixel. pixels[] Xác định một mảng các Pixel. Vùng bao hình chữ nhật của ảnh nằm trong mảng các Pixel này, nhưng mảng phải chứa hơn giá trị w*h hiện tại, phụ thuộc vào giá trị của offset và scansize. Sau đây là công thức tính cho việc xác định mảng các Pixel hiện tại của dữ liệu tại (x+i, y+j), nơi (0 <= i < w) và (0 <= j < h): offset + (j * scansize) + i offset xác định vị trí (trong mảng các pixels) của pixel đầu tiên trong vùng bao hình chữ nhật. scansize xác định chiều rông cho mỗi hàng của mảng các pixels.. The RotateFilter Image Filter Lớp RotateFilter quay một ảnh bởi một góc xác định. Nó dựa vào công thức hình học để tính vị trí cho mỗi pixel: newX = oldX*cos(angle) - oldY*sin(angle) newY = oldX*sin(angle) + oldY*cos(angle) RotateFilter thực thi các phương thức sau của ImageConsumer: setDimensions() Ghi lại chiều rộng và chiều cao của ảnh không được lọc trong phương thức setPixels() và imageComplete(). Tính chiều cao cuối cùng ảnh được lọc, ghi lại dùng cho việc sử dụng phương thức imageComplete() của nó, tạo một bộ đệm để chứa dữ liệu ảnh khi nó lọc được và gọi phương thức setDimensions() để xác lập chiều cao và chiều rộng mới. setColorModel() Nói cho biết các Pixel sử dụng màu của RGB. setHints() Xác định ảnh đã được sắp xếp thứ tự theo hàng và cột. setPixels() (cả hai loại của phương thức này) Chuyển đổi các Pixel sang kiểu RGB mặc định (nếu cần thiết) và sao chép các Pixel đó sang bộ đệm. imageComplete() Quay ảnh rồi gọi phương thức consumer.setPixels()gửi liên tục từng hàng của ảnh đến Consumer. Sau khi đã gửi hết, phương thức này gọi đến consumer.imageComplete(). Thực hiện các hoạt cảnh 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 một Animation Loop 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(); ... } Hoạt hình Bạn nên lưu ý rằng Graphics không thực hiện hoạt cảnh một cách trôi chảy – nghĩa là đôi khi một phần hay tất cảc vùng vẽ bị nháy. Loại trừ nháy hình Sự nháy hình là kết quả của hai sự kiện: Mặc định, nền của hoạt cảnh sẽ bị xoá (nó bao gồm cả vùng nền vẽ lại) trước khi phương thức paint() được gọi. Thao tác

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

  • docjavauivn_9815.doc