前言随着Internet的飞速发展,Java技术也得到了越来越广泛的应用。
而无论我们是采用J2SE、J2EE还是J2ME,GUI都是不能回避的问题。
现在的应用软件越来越要求界面友好、功能强大而又使用简单。
而众所周知,在Java中进行GUI设计相对于其跨平台、多线程等特性的实现要复杂和麻烦许多。
这也是很多Java 程序员抱怨的事情。
但GUI已经成为程序发展的方向,所以我们也必须了解Java 的GUI设计方法和特点。
其实,采用Java提供的布局管理器接口和相应的布局管理类,我们也可以做出相当漂亮的界面来,当然实现起来肯定要比VB麻烦许多。
本文试图通过自己的开发经历介绍一些具体的应用实例,希望能给那些曾经象我一样苦闷的Java痴迷者一些帮助。
2 Java中的布局管理器2.1 为什么要使用布局在实际编程中,我们每设计一个窗体,都要往其中添加若干组件。
为了管理好这些组件的布局,我们就需要使用布局管理器。
比如说,设计一个简单的计算器,或一个文本编辑器等等。
这些组件是让JVM 自己任意安排呢?还是按照一定的位置关系进行规范的安排呢?当然应该选择后者。
将加入到容器的组件按照一定的顺序和规则放置,使之看起来更美观,这就是布局。
在Java中,布局由布局管理器 (LayoutManager) 来管理。
那么,我们在什么时候应该使用布局管理器?应选择哪种布局管理器?又该怎样使用布局管理器呢?如果你写的是GUI程序,在使用AWT/Swing组件时就不应硬性设置组件的大小和位置,而应该使用Java的布局管理器(LayoutManager)来设置和管理可视组件的大小和位置,否则就有可能造成布局混乱。
不信,你可以新建一个Frame(或JFrame),通过setBounds()方法往其中添加几个Button(或JButton),一旦你将窗体拉大或缩小时,你会发现组件的排列完全不是按你所预想的那样。
为了解决这个问题,即当窗体(或容器)缩放时,组件位置也随之合理调整,我们就需要使用布局管理器。
为此,我们首先要知道Java的布局方式,Java提供的API中有些什么布局管理器,它们的布局特点是什么。
2.2 Java的布局方式我们都知道,Java的GUI界面定义是由AWT类包和Swing类包来完成的。
它在布局管理上采用了容器和布局管理分离的方案。
也就是说,容器只管将其他组件放入其中,而不管这些组件是如何放置的。
对于布局的管理交给专门的布局管理器类(LayoutManager)来完成。
现在我们来看Java中布局管理器的具体实现。
我们前面说过,Java中的容器类(Container),它们只管加入组件(Component),也就是说,它只使用自己的add()方法向自己内部加入组件。
同时他记录这些加入其内部的组件的个数,可以通过container.getComponentCount()方法类获得组件的数目,通过container.getComponent(i)来获得相应组件的句柄。
然后LayoutManager类就可以通过这些信息来实际布局其中的组件了。
Java已经为我们提供了几个常用的布局管理器类,例如: FlowLayout、BorderLayout、GridLayout、GridBagLayout等。
下面列表说明它们的布局特点:包类特点java.awt CardLayout 将组件象卡片一样放置在容器中,在某一时刻只有一个组件可见java.awt FlowLayout 将组件按从左到右而后从上到下的顺序依次排列,一行不能放完则折到下一行继续放置java.awt GridLayout 形似一个无框线的表格,每个单元格中放一个组件java.awt BorderLayout 将组件按东、南、西、北、中五个区域放置,每个方向最多只能放置一个组件java.awt GridBagLayout 非常灵活,可指定组件放置的具体位置及占用单元格数目Javax.swing BoxLayout 就像整齐放置的一行或者一列盒子,每个盒子中一个组件Javax.swing SpringLayout 根据一组约束条件放置子组件Javax.swing ScrollPaneLayout 专用于JScrollPane,含一个Viewport,一个行头、一个列头、两个滚动条和四个角组件Javax.swing OverlayLayout 以彼此覆盖的形式叠置组件Javax.swing ViewportLayout JViewport的默认布局管理器事实上,在大多数情况下,综合运用好这些布局管理器已可以满足需要。
当然对于特殊的具体应用,我们可以通过实现LayoutManager或LayoutManager2接口来定义自己的布局管理器。
下面我们通过几个实例来了解几个常用的布局管理器的使用方法。
3 GUI设计应用实例3.1 FlowLayout/GridLayout/BorderLayout的应用实例3.1.1应用背景假设我们要编写一个简单的计算器JApplet,其基本界面如下3.1.2解决方法通过其界面要求可知,我们可以通过将"BackSpace"和"Clear"JButton放置在一个JPanel(1)中,采用FlowLayout布局;将显示结果的JTextField和该JPanel 一起放置到另外一个JPanel(2),采用GridLayout布局;而将其它的JButton 则放置在另外一个JPanel(3)中,采用GridLayout布局;再将JPanel(2)和JPanel(3)加入该JApplet,即可实现界面需求。
具体实现方法如下:/**以FlowLayout布局JPanel(1)*/JPanel p1 = new JPanel(new FlowLayout()); //默认组件从居中开始//加入"BackSpace"和"Clear"JButtonp1.add(backButton);p1.add(clearButton);/**以GridLayout布局JPanel(2)*/JPanel p2 = new JPanel(new GridLayout(2, 1)); //放置2行,每行1个组件//加入显示结果的JTextField和JPanel(1)p2.add(displayField);p2.add(p1);/**以GridLayout布局JPanel(3)*/JPanel p3 = new JPanel(new GridLayout(4, 5)); //放置4行,每行5个组件String buttonStr = "789/A456*B123-C0.D+=";for (int i = 0; i < buttonStr.length(); i++)this.addButton(p3, buttonStr.substring(i, i + 1));//addButton方法private void addButton(Container c, String s){JButton b = new JButton(s);if (s.equals("A"))b.setText("sqrt");else if (s.equals("B"))b.setText("1/x");else if (s.equals("C"))b.setText("%");else if (s.equals("D"))b.setText("+/-");b.setForeground(Color.blue);c.add(b);b.addActionListener(this);}/**以BorderLayout布局JApplet*/this.setLayout(new BorderLayout());this.add(p2, "North");this.add(p3, "Center");这样,就一切OK啦。
具体的实现代码可参见附件中的CalculateApplet.java 文件。
3.2 带工具栏和状态栏的GridLayout/BorderLayout应用实例3.2.1实际问题在很多情况下我们需要动态设置工具栏和状态栏,看下面的应用实例:以上是在视图的工具栏和状态栏都被复选的时候,以下分别为某一个没选或都未选的情况。
3.2.2解决方法1./**工具栏JToolBar采用从左开始的FlowLayout布局*/2.JToolBar toolBar = new JToolBar();3.toolBar.setBorderPainted(false); //不画边界4. toolBar.setLayout(new FlowLayout(FlowLayout.LEFT));5.6./**窗体采用动态的BorderLayout布局,通过获取工具栏或状态栏的复选标记进行界面的动态调整*/7.JSplitPane splitPane = new JSplitPane();8.splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); //设置统计窗口分隔条的方向9.splitPane.setDividerLocation(300); //设置分隔条的位置10.splitPane.setOneTouchExpandable(true);11.JCheckBoxMenuItem toolBarItem = new JCheckBoxMenuItem("工具栏(T)",true);12. JLabel statusLabel = new JLabel("当前统计目标:");13. JCheckBoxMenuItem statusBarItem = new JCheckBoxMenuItem("状态栏(S)", true);14.15./**设置系统窗体布局并动态设置工具栏和状态栏*/16. private void setLayout()17. {18. if(toolBarItem.getState() &&am;'statusBarItem.getState())19. {20. this.getContentPane().add(BorderLayout.NORTH,toolBar);21. this.getContentPane().add(BorderLayout.CENTER,splitPane);22. this.getContentPane().add(BorderLayout.SOUTH,statusLabel);23. }24. else if(toolBarItem.getState()&& !statusBarItem.getState())25. {26. this.getContentPane().add(BorderLayout.NORTH,toolBar);27. this.getContentPane().remove(statusLabel);28. }29. else if(statusBarItem.getState()&& !toolBarItem.getState())30. {31. this.getContentPane().add(BorderLayout.SOUTH,statusLabel);32. this.getContentPane().remove(toolBar);33. }34. else if(!toolBarItem.getState()&& !statusBarItem.getState())35. {36. this.getContentPane().remove(toolBar);37. this.getContentPane().remove(statusLabel);38. }39. this.show(); //添加或移去组件后刷新界面40. }通过该方法即可实现界面的动态刷新与调整。