Swing还提供我们许多特殊容器方便我们编程,JSplitPane(分割面板),JTabbedPane(多选项卡),JLayeredPane(层容器,允许组件互相重叠),***讲两个复杂的容器JDesktopPane和JInternalFrame这些多是为了实现MDI(多文档界面),这些容器不是三言两语能说清楚的,所以我将以举例的方式(其中多是书中的例子,举的都不错,自己一个一个写可吃不消),如还有不懂的,请多查阅API文档。
eg:JSplitPane(分割面板)
- public class TestSplitPane
- {
- Book[] books = new Book[]{
- new Book("Struts2权威指南" , new ImageIcon("ico/struts2.jpg") ,
- "全面介绍Struts2的各方/n面知识"),
- new Book("轻量级J2EE企业应用实战" , new ImageIcon("ico/j2ee.jpg") ,
- "介绍Struts、Spring和/nHibernate整合开发的知识"),
- new Book("基于J2EE的Ajax宝典" , new ImageIcon("ico/ajax.jpg") ,
- "全面介绍J2EE平台上Ajax/n开发的各方面知识")
- };
- JFrame jf = new JFrame("测试JSplitPane");
- JList bookList = new JList(books);
- JLabel bookCover = new JLabel();
- JTextArea bookDesc = new JTextArea();
- public void init()
- {
- //为三个组件设置***大小
- bookList.setPreferredSize(new Dimension(150, 300));
- bookCover.setPreferredSize(new Dimension(300, 150));
- bookDesc.setPreferredSize(new Dimension(300, 150));
- //为下拉列表添加事件监听器
- bookList.addListSelectionListener(new ListSelectionListener()
- {
- public void valueChanged(ListSelectionEvent event)
- {
- Book book = (Book)bookList.getSelectedValue();
- bookCover.setIcon(book.getIco());
- bookDesc.setText(book.getDesc());
- }
- });
- //创建一个垂直的分割面板,
- //将bookCover放在上面,将bookDesc放在下面 , 支持连续布局
- JSplitPane left = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true ,
- bookCover, new JScrollPane(bookDesc));
- //打开“一触即展”的特性
- left.setOneTouchExpandable(true);
- //下面代码设置分割条的大小。
- //left.setDividerSize(50);
- //设置该分割面板根据所包含组件的***大小来调整布局
- left.resetToPreferredSizes();
- //创建一个水平的分割面板
- //将left组件放在左边,将bookList组件放在右边
- JSplitPane content = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
- left, bookList);
- jf.add(content);
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- jf.pack();
- jf.setVisible(true);
- }
- public static void main(String[] args)
- {
- new TestSplitPane().init();
- }
- }
- class Book
- {
- private String name;
- private Icon ico;
- private String desc;
- public Book(){}
- public Book(String name , Icon ico , String desc)
- {
- this.name = name;
- this.ico = ico;
- this.desc = desc;
- }
- public void setName(String name)
- {
- this.name = name;
- }
- public String getName()
- {
- return this.name;
- }
- public void setIco(Icon ico)
- {
- this.ico = ico;
- }
- public Icon getIco()
- {
- return this.ico;
- }
- public void setDesc(String desc)
- {
- this.desc = desc;
- }
- public String getDesc()
- {
- return this.desc;
- }
- public String toString()
- {
- return name;
- }
- }
eg:JTabbedPane(多选项卡)
- public class TestJTabbedPane
- {
- JFrame jf = new JFrame("测试Tab页面");
- //创建一个Tab页面的标签放在左边,采用换行布局策略的JTabbedPane
- JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.LEFT , JTabbedPane.WRAP_TAB_LAYOUT);
- ImageIcon icon = new ImageIcon("ico/close.gif");
- String[] layouts = {"换行布局" , "滚动条布局"};
- String[] positions = {"左边" , "顶部" , "右边" , "底部"};
- Map<String , String> books = new LinkedHashMap<String , String>();
- public void init()
- {
- books.put("ROR敏捷开发***实践" , "ror.jpg");
- books.put("Struts2权威指南" , "struts2.jpg");
- books.put("基于J2EE的Ajax宝典" , "ajax.jpg");
- books.put("轻量级J2EE企业应用实战" , "j2ee.jpg");
- books.put("Spring2.0宝典" , "spring.jpg");
- String tip = "可看到本书的封面照片";
- //向JTabbedPane中添加5个Tab页面,指定了标题、图标和提示,但该Tab页面的组件为null
- for (String bookName : books.keySet())
- {
- tabbedPane.addTab(bookName, icon, null , tip);
- }
- jf.add(tabbedPane, BorderLayout.CENTER);
- //为JTabbedPane添加事件监听器
- tabbedPane.addChangeListener(new ChangeListener()
- {
- public void stateChanged(ChangeEvent event)
- {
- //如果被选择的组件依然是空
- if (tabbedPane.getSelectedComponent() == null)
- {
- //获取所选Tab页
- int n = tabbedPane.getSelectedIndex();
- //为指定标前页加载内容
- loadTab(n);
- }
- }
- });
- //系统默认选择***页,加载***页内容
- loadTab(0);
- tabbedPane.setPreferredSize(new Dimension(500 , 300));
- //增加控制标签布局、标签位置的单选按钮
- JPanel buttonPanel = new JPanel();
- ChangeAction action = new ChangeAction();
- buttonPanel.add(new ButtonPanel(action , "选择标签布局策略" ,layouts));
- buttonPanel.add (new ButtonPanel(action , "选择标签位置" ,positions));
- jf.add(buttonPanel, BorderLayout.SOUTH);
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- jf.pack();
- jf.setVisible(true);
- }
- //为指定标签页加载内容
- private void loadTab(int n)
- {
- String title = tabbedPane.getTitleAt(n);
- //根据标签页的标题获取对应图书封面
- ImageIcon bookImage = new ImageIcon("ico/" + books.get(title));
- tabbedPane.setComponentAt(n, new JLabel(bookImage));
- //改变标签页的图标
- tabbedPane.setIconAt(n, new ImageIcon("ico/open.gif"));
- }
- //定义改变标签页的布局策略,放置位置的监听器
- class ChangeAction implements ActionListener
- {
- public void actionPerformed(ActionEvent event)
- {
- JRadioButton source = (JRadioButton)event.getSource();
- String selection = source.getActionCommand();
- if (selection.equals(layouts[0]))
- {
- tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
- }
- else if (selection.equals(layouts[1]))
- {
- tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
- }
- else if (selection.equals(positions[0]))
- {
- tabbedPane.setTabPlacement(JTabbedPane.LEFT);
- }
- else if (selection.equals(positions[1]))
- {
- tabbedPane.setTabPlacement(JTabbedPane.TOP);
- }
- else if (selection.equals(positions[2]))
- {
- tabbedPane.setTabPlacement(JTabbedPane.RIGHT);
- }
- else if (selection.equals(positions[3]))
- {
- tabbedPane.setTabPlacement(JTabbedPane.BOTTOM);
- }
- }
- }
- public static void main(String[] args)
- {
- new TestJTabbedPane().init();
- }
- }
- //定义一个JPanel类扩展类,该类的对象包含多个纵向排列的JRadioButton控件
- //且Panel扩展类可以指定一个字符串作为TitledBorder
- class ButtonPanel extends JPanel
- {
- private ButtonGroup group;
- public ButtonPanel(TestJTabbedPane.ChangeAction action , String title, String[] labels)
- {
- setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), title));
- setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
- group = new ButtonGroup();
- for (int i = 0; labels!= null && i < labels.length; i++)
- {
- JRadioButton b = new JRadioButton(labels[i]);
- b.setActionCommand(labels[i]);
- add(b);
- //添加事件监听器
- b.addActionListener(action);
- group.add(b);
- b.setSelected(i == 0);
- }
- }
- }
eg:JLayeredPane(层容器,允许组件互相重叠)
- public class TestJLayeredPane
- {
- JFrame jf = new JFrame("测试JLayeredPane");
- JLayeredPane layeredPane = new JLayeredPane();
- public void init()
- {
- //向layeredPane中添加3个组件
- layeredPane.add(new ContentPanel(10 , 20 , "Struts2权威指南" ,
- "ico/struts2.jpg"), JLayeredPane.MODAL_LAYER);
- layeredPane.add(new ContentPanel(100 , 60 , "RoR敏捷开发***实践",
- "ico/ror.jpg"), JLayeredPane.DEFAULT_LAYER);
- layeredPane.add(new ContentPanel(190 , 100 , "轻量级J2EE企业应用实战",
- "ico/j2ee.jpg"), 4);
- layeredPane.setPreferredSize(new Dimension(400, 300));
- layeredPane.setVisible(true);
- jf.add(layeredPane);
- jf.pack();
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- jf.setVisible(true);
- }
- public static void main(String[] args)
- {
- new TestJLayeredPane().init();
- }
- }
- //扩展了JPanel类,可以直接创建一个放在指定位置,
- //且有指定标题、放置指定图标的JPanel对象
- class ContentPanel extends JPanel
- {
- public ContentPanel(int xPos , int yPos , String title , String ico)
- {
- setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), title));
- JLabel label = new JLabel(new ImageIcon(ico));
- add(label);
- setBounds(xPos , yPos , 160, 200);
- }
- }
以上3例子由于都是广告,我就不贴给大家了,没图片不影响程序的效果。
***是JDesktopPane和JInternalFrame来实现MDI
- public class TestInternalFrame
- {
- final int DESKTOP_WIDTH = 480;
- final int DESKTOP_HEIGHT = 360;
- final int FRAME_DISTANCE = 30;
- JFrame jf = new JFrame("MDI界面");
- //定义一个虚拟桌面
- private MyJDesktopPane desktop = new MyJDesktopPane();
- //保存下一个内部窗口的座标点
- private int nextFrameX;
- private int nextFrameY;
- //定义内部窗口为虚拟桌面的1/2大小
- private int width = DESKTOP_WIDTH / 2;
- private int height = DESKTOP_HEIGHT / 2;
- //为主窗口定义2个菜单
- JMenu fileMenu = new JMenu("文件");
- JMenu windowMenu = new JMenu("窗口");
- //定义newAction用于创建菜单和工具按钮
- Action newAction = new AbstractAction("新建", new ImageIcon("ico/new.png"))
- {
- public void actionPerformed(ActionEvent event)
- {
- //创建内部窗口
- final JInternalFrame iframe = new JInternalFrame("新文档",
- true, // 可改变大小
- true, // 可关闭
- true, // 可***化
- true); // 可最小化
- iframe.add(new JScrollPane(new JTextArea(8, 40)));
- //将内部窗口添加到虚拟桌面中
- desktop.add(iframe);
- //设置内部窗口的原始位置(内部窗口默认大小是0X0,放在0,0位置)
- iframe.reshape(nextFrameX, nextFrameY, width, height);
- //使该窗口可见,并尝试选中它
- iframe.show();
- //计算下一个内部窗口的位置
- nextFrameX += FRAME_DISTANCE;
- nextFrameY += FRAME_DISTANCE;
- if (nextFrameX + width > desktop.getWidth()) nextFrameX = 0;
- if (nextFrameY + height > desktop.getHeight()) nextFrameY = 0;
- }
- };
- //定义exitAction用于创建菜单和工具按钮
- Action exitAction = new AbstractAction("退出", new ImageIcon("ico/exit.png"))
- {
- public void actionPerformed(ActionEvent event)
- {
- System.exit(0);
- }
- };
- public void init()
- {
- //为窗口安装菜单条和工具条
- JMenuBar menuBar = new JMenuBar();
- JToolBar toolBar = new JToolBar();
- jf.setJMenuBar(menuBar);
- menuBar.add(fileMenu);
- fileMenu.add(newAction);
- fileMenu.add(exitAction);
- toolBar.add(newAction);
- toolBar.add(exitAction);
- menuBar.add(windowMenu);
- JMenuItem nextItem = new JMenuItem("下一个");
- nextItem.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent event)
- {
- desktop.selectNextWindow();
- }
- });
- windowMenu.add(nextItem);
- JMenuItem cascadeItem = new JMenuItem("级联");
- cascadeItem.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent event)
- {
- //级联显示窗口,内部窗口的大小是外部窗口的0.75
- desktop.cascadeWindows(FRAME_DISTANCE , 0.75);
- }
- });
- windowMenu.add(cascadeItem);
- JMenuItem tileItem = new JMenuItem("平铺");
- tileItem.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent event)
- {
- //平铺显示所有内部窗口
- desktop.tileWindows();
- }
- });
- windowMenu.add(tileItem);
- final JCheckBoxMenuItem dragOutlineItem = new JCheckBoxMenuItem("仅显示拖动窗口的轮廓");
- dragOutlineItem.addActionListener(new ActionListener()
- {
- public void actionPerformed(ActionEvent event)
- {
- //根据该菜单项是否选择来决定采用哪种拖动模式
- desktop.setDragMode(dragOutlineItem.isSelected()
- ? JDesktopPane.OUTLINE_DRAG_MODE
- : JDesktopPane.LIVE_DRAG_MODE);
- }
- });
- windowMenu.add(dragOutlineItem);
- desktop.setPreferredSize(new Dimension(480, 360));
- //将虚拟桌面添加到***JFrame容器中
- jf.add(desktop);
- jf.add(toolBar , BorderLayout.NORTH);
- jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- jf.pack();
- jf.setVisible(true);
- }
- public static void main(String[] args)
- {
- new TestInternalFrame().init();
- }
- }
- class MyJDesktopPane extends JDesktopPane
- {
- //将所有窗口以级联方式显示,
- //其中offset是两个窗口的位移距离,scale是内部窗口与JDesktopPane的大小比例
- public void cascadeWindows(int offset , double scale)
- {
- //定义级联显示窗口时内部窗口的大小
- int width = (int)(getWidth() * scale);
- int height = (int)(getHeight() * scale);
- //用于保存级联窗口时每个窗口的位置
- int x = 0;
- int y = 0;
- for (JInternalFrame frame : getAllFrames())
- {
- try
- {
- //取消内部窗口的***化,最小化
- frame.setMaximum(false);
- frame.setIcon(false);
- //把窗口重新放置在指定位置
- frame.reshape(x, y, width, height);
- x += offset;
- y += offset;
- //如果到了虚拟桌面边界
- if (x + width > getWidth()) x = 0;
- if (y + height > getHeight()) y = 0;
- }
- catch (PropertyVetoException e)
- {}
- }
- }
- //将所有窗口以平铺方式显示
- public void tileWindows()
- {
- //统计所有窗口
- int frameCount = 0;
- for (JInternalFrame frame : getAllFrames())
- {
- frameCount++;
- }
- //计算需要多少行、多少列才可以平铺所有窗口
- int rows = (int) Math.sqrt(frameCount);
- int cols = frameCount / rows;
- //需要额外增加到其他列中的窗口
- int extra = frameCount % rows;
- //计算平铺时内部窗口的大小
- int width = getWidth() / cols;
- int height = getHeight() / rows;
- //用于保存平铺窗口时每个窗口在横向、纵向上的索引
- int x = 0;
- int y = 0;
- for (JInternalFrame frame : getAllFrames())
- {
- try
- {
- //取消内部窗口的***化,最小化
- frame.setMaximum(false);
- frame.setIcon(false);
- //将窗口放在指定位置
- frame.reshape(x * width, y * height, width, height);
- y++;
- //每排完一列窗口
- if (y == rows)
- {
- //开始排放下一列窗口
- y = 0;
- x++;
- //如果额外多出的窗口与剩下的列数相等,则后面所有列都需要多排列一个窗口
- if (extra == cols - x)
- {
- rows++;
- height = getHeight() / rows;
- }
- }
- }
- catch (PropertyVetoException e)
- {}
- }
- }
- //选中下一个非图标窗口
- public void selectNextWindow()
- {
- JInternalFrame[] frames = getAllFrames();
- for (int i = 0; i < frames.length; i++)
- {
- if (frames[i].isSelected())
- {
- // 找出下一个非最小化的窗口,尝试选中它,
- //如果选中失败,则继续尝试选中下一个窗口
- int next = (i + 1) % frames.length;
- while (next != i)
- {
- //如果该窗口不是处于最小化状态
- if (!frames[next].isIcon())
- {
- try
- {
- frames[next].setSelected(true);
- frames[next].toFront();
- frames[i].toBack();
- return;
- }
- catch (PropertyVetoException e)
- {}
- }
- next = (next + 1) % frames.length;
- }
- }
- }
- }
- }
大家注意看继承JDesktopPane的类MyJDesktopPane
其中的3个方法非常有用,这是对窗口控制的基本方法(级联,平铺,选下个窗口),大家可以保留下来,以备后用。
原文链接:http://blog.csdn.net/terryzero/article/details/3770982
【编辑推荐】