Võ Văn Hải's blog

Chỉ có một điều tuyệt đối đó là mọi thứ đều tương đối…

Tạo ứng ứng dụng đa cửa sổ (Multiple Document Interface – MDI)

Trong bài viết này, tôi sẽ giới thiệu đến các bạn cách chúng ta tạo ứng dụng GUI dạng MDI. Dạng ứng dụng này rất hay được dùng trong phát triển desktop application.

Việc thiết kế frame bình thường như khi chúng ta viết 1 ứng dụng GUI. Điểm khác biệt ở đây là ta dùng đối tượng javax.swing.JDesktopPane để chứa các child frame.

Đầu tiên ta khai báo và khởi tạo đối tượng JDesktopPane. Sau đó ta dùng đối tượng này để chứa các frame con. Ở đây các frame con là đối tượng javax.swing.JInternalFrame. Đối tượng này có constructor đầy đủ có dạng

public JInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable)

trong đó tham số title chỉ tiêu đề của frame con,
tham số resizable cho phép thay đổi kích thước của frame con nếu có giá trị true,
tham số closable cho phép người dùng đóng
frame con nếu có giá trị là true,
tham số maximizable cho phép người dùng có thể phóng lớn frame
con nếu có giá trị true,
tham số iconifiable cho phép người dùng có thể thu nhỏ frame con nếu có giá trị true.

Hình sau cho chúng ta cái nhìn tổng quát về các tham số của JInternalFrame khi chúng ta khai báo như sau

JInternalFrame frm=new JInternalFrame(“My Internal Frame”,true,true,true,true);

https://vovanhai.files.wordpress.com/2008/11/mdi_01.png

Sau đây là đoạn code cho chúng ta hình trên

package gui;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;

public class MDIExample extends JFrame{
private static final long serialVersionUID = 7911982594694375525L;

private JDesktopPane desktopPane;

public MDIExample() {
super(“MDI Example”);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);

desktopPane=new JDesktopPane();
this.setContentPane(desktopPane);
JInternalFrame frm=new JInternalFrame(“My Internal Frame”,true,true,true,true);
desktopPane.add(frm);frm.setSize(400,400);
frm.setVisible(true);
}
public static void main(String[] args) {
new MDIExample().setVisible(true);
}

}

Bây giờ chúng ta sẽ thiết kế 1 ứng dụng đơn giản với vài thứ liên quan đến kiểu MDI. Sau đây là hình minh họa
https://vovanhai.files.wordpress.com/2008/11/mdi_02.png
Code cho việc sắp xếp cascade

int x = 0;
int y = 0;
int FRAME_OFFSET = 20;
JInternalFrame allFrames[] = desktopPane.getAllFrames();

int frameHeight = (getBounds().height – 5) – allFrames.length * FRAME_OFFSET;
int frameWidth = (getBounds().width – 5) – allFrames.length * FRAME_OFFSET;
for (int i = allFrames.length – 1; i >= 0; i–) {
allFrames[i].setSize(frameWidth, frameHeight);
allFrames[i].setLocation(x, y);
x = x + FRAME_OFFSET;
y = y + FRAME_OFFSET;
}

Code cho việc sắp xếp tile

java.awt.Component allFrames[] =desktopPane.getAllFrames();
int frameHeight = getBounds().height / allFrames.length;
int y = 0;
for (int i = 0; i < allFrames.length; i++) {
allFrames[i].setSize(getBounds().width, frameHeight);
allFrames[i].setLocation(0, y);
y = y + frameHeight;
}

Code hoàn chỉnh

package gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;

public class MDIExample extends JFrame implements ActionListener{
private static final long serialVersionUID = 7911982594694375525L;

private JDesktopPane desktopPane;
private JMenuBar menubar;
private JMenu mnuFile,mnuWindow;
private JMenuItem itemNew,itemExit;
private JMenuItem itemCascade,itemTile;

private int i=1;

public MDIExample() {
super(“MDI Example”);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500,300);

desktopPane=new JDesktopPane();
desktopPane.setAutoscrolls(true);
this.setContentPane(desktopPane);
CreateMENU();
}
private void CreateMENU() {
this.setJMenuBar(menubar=new JMenuBar());
menubar.add(mnuFile=new JMenu(“File”));
mnuFile.add(itemNew=new JMenuItem(“New”,’N’));
itemNew.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,InputEvent.CTRL_MASK));
mnuFile.addSeparator();
mnuFile.add(itemExit=new JMenuItem(“Exit”,’x’));
itemNew.addActionListener(this);
itemExit.addActionListener(this);

menubar.add(mnuWindow=new JMenu(“Window”));
mnuWindow.add(itemCascade=new JMenuItem(“Cascade”));
itemCascade.addActionListener(this);
mnuWindow.add(itemTile=new JMenuItem(“Tile”));
itemTile.addActionListener(this);
}

@Override
public void actionPerformed(ActionEvent e) {
Object o=e.getSource();
if(o.equals(itemNew)) {
JInternalFrame frm=new MyDocument(“Document “+(i++));
desktopPane.add(frm);
frm.setVisible(true);
}
else if(o.equals(itemCascade)) {
int x = 0;
int y = 0;
int FRAME_OFFSET = 20;
JInternalFrame allFrames[] = desktopPane.getAllFrames();

int frameHeight = (getBounds().height – 5) – allFrames.length * FRAME_OFFSET;
int frameWidth = (getBounds().width – 5) – allFrames.length * FRAME_OFFSET;
for (int i = allFrames.length – 1; i >= 0; i–) {
allFrames[i].setSize(frameWidth, frameHeight);
allFrames[i].setLocation(x, y);
x = x + FRAME_OFFSET;
y = y + FRAME_OFFSET;
}
}
else if(o.equals(itemTile)) {
java.awt.Component allFrames[] =desktopPane.getAllFrames();
int frameHeight = getBounds().height / allFrames.length;
int y = 0;
for (int i = 0; i < allFrames.length; i++) {
allFrames[i].setSize(getBounds().width, frameHeight);
allFrames[i].setLocation(0, y);
y = y + frameHeight;
}
}
}

public static void main(String[] args) {
new MDIExample().setVisible(true);
}
}

Chúc thành công!

14 Responses to “Tạo ứng ứng dụng đa cửa sổ (Multiple Document Interface – MDI)”

  1. Nguyễn Thế Sơn said

    cho em hỏi chút. Em tạo Internal Frame nhưng nó chỉ được một cửa sổ Frame con, mở cửa sổ mới nó đè lên cửa sổ cũ. Làm thế nào để mở được nhiều cửa sổ con!

  2. vovanhai said

    Đây là methods thêm 1 form vào trong 1 MDI parent. Nếu như chưa có cửa sổ đó trong frame cha, nó sẽ thêm mới ngược lại nó sẽ active frame.

    private void AddForm(JInternalFrame wnd){
    boolean isExist=false;
    try {
    for (JInternalFrame frm : desktop.getAllFrames())
    {
    if(wnd.getTitle().equals(frm.getTitle()))
    {
    isExist=true;
    break;
    }
    }
    if(isExist==true){
    desktop.setSelectedFrame(wnd);
    wnd.setSelected(true);
    }
    else{
    desktop.add(wnd);
    wnd.setMaximum(true);
    wnd.setVisible(true);
    }
    }
    catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    tất nhiên trong frame cha, bạn phải có 1 JDesktopPane:
    private JDesktopPane desktop=new JDesktopPane();
    sau đó bạn qui định ContentPane cho frame cha là desktoppane này.
    this.setContentPane(desktop);

  3. Nguyễn Thế Sơn said

    Cảm ơn thầy em làm được rồi! Lúc trước em không khởi tạo private JDesktopPane desktop=new JDesktopPane() ngay khi khai báo mà mỗi lần gọi hiển thị form mới em khởi tạo lại và setcontentPane nên nó chỉ có 1 form MDI hiển thị.

    Còn phần sắp xếp các form MDI, em cũng thử làm nhưng khi chọn sắp xếp thì tất cả các form biến mất, em đang thử làm lại.

  4. Bạch Ngọc Toàn said

    Thầy cho em hỏi đoạn code mà khi bật internal frame lên thì cái tiêu đề của internal mất đi!trông sẽ liền với cái JDesktop Frame với ạh!em cảm ơn thầy!

  5. lucky said

    Chào thầy: thầy ơi!sao e không thấy có một tài liệu nào nói về php trong bolg hết vậy. Nó hấp dẫn làm mà thầy. xin thầy chỉ giáo. cám ơn.

  6. Nguyễn Trần Vũ said

    Chào thầy, cho em hỏi chút, em sắp làm 1 đồ án bằng JavaSE, hiện tại thì chưa có đề tài cụ thể, nhưng em đang phân vân nên viết kiểu nhiều frame hay là dùng đến internal frames.

    Thầy có lời khuyên nào về việc thiết kế GUI không thầy ? Theo em nghĩ, việc thiết kế GUI như thế nào rất quan trọng, nó ảnh hưởng đến cách người dùng sẽ dùng ứng dụng mình viết ra.

    Em có một số bạn, lập trình khá tốt nhưng thiết kế GUI thì hơi kém, dẫn đến ứng dụng kém thân thiện với người dùng, từ đó hiệu năng sử dụng ứng dụng kém hẳn đi.

    Sinh viên tụi em chưa có kinh nghiệm về việc này nhiều lắm, phần lớn chỉ là làm theo cảm tính. Lời khuyên của thầy sẽ rất hữu ích với em. Cảm ơn thầy!

  7. vovanhai said

    Cũng tùy vào nhìn nhận của người dùng hoặc chủ quan của người lập trình. MDI thì được cái là làm việc dễ dàng, thống nhất và cũng là 1 dạng khá là “truyền thống”. Tuy nhiên, trong 1 số ứng dụng, người lập trình sử dụng nguyên tắc tạo các components (gần như là các patterns) trên các containers không phải Jframe rồi add chúng 1 cách dynamic vào 1 JFrame duy nhất tùy vào hành vi.
    Tuy nhiên, cần nhấn mạnh rằng xu hướng bây giờ chính là WEB, bạn nên cân nhắc để chọn viết ứng dụng web thay vì các application dùng cơ chế GUI.

  8. nguyễn khắc điệp said

    Em chào thầy!thầy cho em hỏi java nên học từ đâu.thường thì thầy học như thế nào mà được nhiều thế, chỉ giúp em được không?em rất muốn tìm hiểu sâu vê môn này nhưng không hiểu sao nó quá nhiều phương thức mà em đã đọc nhiều tài liệu mà chưa hiểu nổi

  9. Võ Văn Hải said

    Học mãi, mỗi ngày ít. Cứ làm nhiều sẽ nhuyễn.🙂

  10. Xuân Huy said

    Em chào thầy, Thầy có thể cho em hỏi chủ đề không liên quan gì đến cái này được không ạ? Thầy có thể mở một chủ đề về lớp Robot trong java được không ạ? Em đang cần tìm hiểu về lớp này nhưng thực sự em không biết lớp đó có tác dụng gì cả? Em cảm ơn Thầy

  11. phuongnt said

    Em chào thầy, thầy cho em hỏi, em đang làm một bài tập về tạo notepad. Khi ấn vào menu con Font trên Format thì sẽ có một cửa sổ mới mở ra(cửa sổ tên Font), vậy làm thế nào để khi ấn nút Cancel trong c.sổ Font thì c/s này tự đóng lại, mà ứng dụng Notepad vẫn chạy ạ???.Em cảm ơn thầy ạ.

  12. Võ Văn Hải said

    thay vì chọn EXIT_ON_CLOSE, bạn chọn DISPOSE_ON_CLOSE hoặc viết code gọi phương thức this.dispose()

  13. Cuong said

    thầy cho em hỏi em muốn tạo 1 cửa sổ mới từ 1 Frame chính, mà chỉ thao tác được trên cửa sổ đó và không thao tác được trên cửa sổ chính thì phải làm thế nào ạ!

  14. Võ Văn Hải said

    thầy cho em hỏi em muốn tạo 1 cửa sổ mới từ 1 Frame chính, mà chỉ thao tác được trên cửa sổ đó và không thao tác được trên cửa sổ chính thì phải làm thế nào ạ!

    Thay vì em Show() bình thường thì em chọn ShowDialog()

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: