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);

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

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!
Like this:
Be the first to like this page.
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!
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);
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.
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!
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.
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!
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.
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
Võ Văn Hải said
Học mãi, mỗi ngày ít. Cứ làm nhiều sẽ nhuyễn.
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
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 ạ.
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()
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 ạ!
Võ Văn Hải said
Thay vì em Show() bình thường thì em chọn ShowDialog()