Swing GUI 案例 - 5. 面板和布局

                  Swing GUI 案例 - 5. 面板和布局

经常看到有人说Swing的布局代码冗长而且变态,相对于.net标准的visual方式,不借助可视化工具的swing界面编写确实显得枯燥繁琐。

经过一年多断断续续的尝试,我对swing界面代码的编写也有了些感觉,在此晒一晒。

应用简述:实现如下界面,并提供相关的录入、查询、修改和删除等功能。

gui_win

分析一下,这个界面的主体应当是三个滚动面板(JScrollPane),一个容纳任务列表(左侧),一个容纳记录列表(右侧),一个容纳文本信息(右下)。(仅含有三个滚动面板的代码请参见这里

除此之外,上面还有一个菜单,菜单下方还有一个工具条。

菜单谈不上布局,工具条则要求月份控件靠左,按钮控件靠右,中间留白。

主体部分,右侧的两个滚动面板组成一个分割面板(JSplitPane),右侧的分割面板又与左边的滚动面板组成一个大的水平分割的JSplitPane。

由此,可以构思程序代码如下:

1、构建菜单

2、构建工具条

3、构建分割面板

4、构建主面板

由此得到直觉的布局代码:

 

……

ScrollPane 
s_index = new JScrollPane(new JTextArea()) ,
s_recs = new JScrollPane(new JTextArea()) , 
s_info = new JScrollPane(new JTextArea()) ;

JSplitPane 
right = new JSplitPane
(JSplitPane.VERTICAL_SPLIT,s_recs,s_info) ,
split = new JSplitPane
(JSplitPane.HORIZONTAL_SPLIT,s_index,right);

split.setPreferredSize(new Dimension(600,400)) ;
right.setDividerLocation(300) ;
split.setDividerLocation(300) ;

JPanel p = new JPanel() ;
p.setLayout(new BorderLayout()) ;
p.add(toolbar(),BorderLayout.PAGE_START) ;
p.add(split,BorderLayout.CENTER) ;

JFrame f = new JFrame("任务人III") ;
f.setJMenuBar(menu_bar()) ;
f.setContentPane(p) ;
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
f.pack() ;
f.setVisible(true) 

……

工具栏(一个面板)部分的代码:

JTextField 
c_month = new JTextField("0806") ;
JLabel l = new JLabel("当前月份(M):") ;
l.setLabelFor(c_month) ;
l.setDisplayedMnemonic(KeyEvent.VK_M) ;

JButton 
reverse = new JButton("逆序") ,
task_new = new JButton("新任务") , 
rec_new = new JButton("新任务") ;

JPanel p = new JPanel() ;
p.setLayout
(new BoxLayout(p,BoxLayout.LINE_AXIS)) ;
p.add(l) ;
p.add(c_month) ;
p.add(Box.createHorizontalGlue()) ;
p.add(reverse) ;
p.add(task_new) ;
p.add(rec_new) ;

试着运行,效果如下:

layout_1

熟悉visual的同志们看到这个界面,就会嘲笑并判断swing的愚昧落后了。

分析一下,现在界面的主要问题是:

1、面板无边

2、菜单、工具栏和分割面板之间过于紧密

3、工具栏中文本字段太长

4、按钮傻大

为了让swing程序的外观看起来好些,我用了如下一些方法:

1、EmptyBorder(解决1、2)

2、setMaximumSize()(解决3)

3、JButton.setMargin()(解决4)

相关代码如下:

        // 设置工具栏的下边框
        p.setBorder(new EmptyBorder(0,0,10,0)) ;
 
        // 设置主面板的边框       
        p.setBorder(new EmptyBorder(10,10,10,10)) ;
        
        // 限制JTextField的长度
        c_month.setColumns(3) ;
        c_month.setMaximumSize
        (c_month.getPreferredSize()) ;
        
        
    // 创建小按钮
    private static JButton make_button
    (String label, int key) {
        JButton b = new JButton(label) ;
        if (key>0) b.setMnemonic(key) ;
        b.setMargin(new Insets(0,0,0,0)) ;
        return b ;
    }

效果:

布局4

原来的4个问题解决了,但发现按钮显得很拥挤,三个滚动面板也不太匀称,这可以通过添加水平柱子(Box.createHorizontalStrut())和调整分隔条位置(<JScrollPane>.setDividerLocation)来实现。

完整源码如下:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class taskman5 {
    
    public static void main(String[] args) 
    throws Exception { 
        String lnf = UIManager
        .getCrossPlatformLookAndFeelClassName() ;
        UIManager.setLookAndFeel(lnf) ;
        JFrame.setDefaultLookAndFeelDecorated(true) ;
        JDialog.setDefaultLookAndFeelDecorated(true) ;
        
        SwingUtilities.invokeLater(new Runnable(){
            public void run() { 
                make_ui() ;
            } 
        }) ;
    }
    
    private static void make_ui () {
        JScrollPane 
        s_index = new JScrollPane(new JTextArea()) ,
        s_recs = new JScrollPane(new JTextArea()) , 
        s_info = new JScrollPane(new JTextArea()) ;
        
        JSplitPane 
        right = new JSplitPane
        (JSplitPane.VERTICAL_SPLIT,s_recs,s_info) ,
        split = new JSplitPane
        (JSplitPane.HORIZONTAL_SPLIT,s_index,right);

        split.setPreferredSize(new Dimension(600,350)) ;
        right.setDividerLocation(250) ;
        split.setDividerLocation(200) ;
    
        JPanel p = new JPanel() ;
        p.setLayout(new BorderLayout()) ;
        p.add(toolbar(),BorderLayout.PAGE_START) ;
        p.add(split,BorderLayout.CENTER) ;
        p.setBorder(new EmptyBorder(10,10,10,10)) ;
        
        JFrame f = new JFrame("任务人III") ;
        f.setJMenuBar(menu_bar()) ;
        f.setContentPane(p) ;
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
        f.pack() ;
        f.setVisible(true) ;
    }
    
    static private JMenuBar menu_bar() {
        JMenu 
        file = new JMenu("文件(F)") ,
        task = new JMenu("任务(T)") ,
        view = new JMenu("视图(V)") ;
        
        file.setMnemonic(KeyEvent.VK_F) ;
        task.setMnemonic(KeyEvent.VK_T) ;
        view.setMnemonic(KeyEvent.VK_V) ;
        
        JMenuBar bar = new JMenuBar() ;
        bar.add(file) ;
        bar.add(task) ;
        bar.add(view) ;
        
        return bar ;
    }

    static private JPanel toolbar() {
        JTextField 
        c_month = new JTextField("0806") ;
        c_month.setColumns(3) ;
        c_month.setMaximumSize
        (c_month.getPreferredSize()) ;
        JLabel l = new JLabel("当前月份(M):") ;
        l.setLabelFor(c_month) ;
        l.setDisplayedMnemonic(KeyEvent.VK_M) ;
        
        JButton 
        reverse = make_button("逆序",-1) ,
        task_new = make_button("新任务",-1) , 
        rec_new = make_button("新任务",-1) ;
        
        JPanel p = new JPanel() ;
        p.setLayout
        (new BoxLayout(p,BoxLayout.LINE_AXIS)) ;
        p.add(l) ;
        p.add(c_month) ;
        p.add(Box.createHorizontalGlue()) ;
        p.add(reverse) ;
        p.add(button_margin()) ;
        p.add(task_new) ;
        p.add(button_margin()) ;
        p.add(rec_new) ;
        p.setBorder(new EmptyBorder(0,0,10,0)) ;

        return p ;
    }
    
    private static JButton make_button
    (String label, int key) {
        JButton b = new JButton(label) ;
        if (key>0) b.setMnemonic(key) ;
        b.setMargin(new Insets(0,0,0,0)) ;
        return b ;
    }
    
    private static Component button_margin() { 
        return Box.createHorizontalStrut(5) ;
    }
}

效果如下:

布局5

这个外观已经可以作为原型使用了。

回顾上述步骤,使用纯代码手段设定整体布局,我经历了一个3步的求精过程。这样形成代码,虽然比可视化工具效率要低些,但却令java代码更好读,并且对窗口组件有了更好的程序控制。

相关:

概念模型

UIManager , Look and Feel , SwingUtilities

快速建立原型

Swing程序组织 原则和技巧

AWT/SWT/SWING 区别和联系

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值