Swing参照Android采用XML的方式自动布局

原创
2016/05/20 16:21
阅读数 676

众所周知,java很强大,其强大性主要体现在成熟的社区组织、各类第三方开源的jar类库。所有的这些第三方的功能包,都极大地拓宽了java的适用范围。自动垃圾回收机制,让编写java应用变得轻松自然。

但桌面应用一直是java的软肋。长久以来,swing需要采用拖沓冗余的代码来实现复杂的界面布局、“重口味”的原生swing界面,均让Swing这一领域一直不愠不火。Swing界面刷新机制EDT里面的坑,均吓倒了一大批欲在这个领域做出点什么的新人。

个人认为,布局代码“不直观”,是摆在swing开发者尤其是面前的第一道大关。但是这个问题在安卓领域却早已拥有成熟的解决方案:采用xml方式布局。那么,比安卓历史更久的Swing技术为何还没有一个简单易用的xml布局工具?

 

举个例子:

为了实现以下的界面,

 

我们要写这么长的布局代码:

private void initViews()
{
    this.editServerIp = new JTextField(16);

    this.editServerPort = new JTextField(5);

    this.editServerIp.setForeground(new Color(13, 148, 252));

    this.editServerPort.setForeground(new Color(13, 148, 252));

    this.editServerIp.setText("rbcore.openmob.net");

    this.editServerPort.setText("7901");

    this.btnLogin = new JButton("登陆");

    this.btnLogin.setUI(new BEButtonUI().setNormalColor(BEButtonUI.NormalColor.blue));

    this.btnLogin.setForeground(Color.white);

    this.editLoginName = new JTextField(22);

    this.editLoginPsw = new JPasswordField(22);

    this.btnLogout = new JButton("退出");

    this.viewMyid = new JLabel();

    this.viewMyid.setForeground(new Color(255, 0, 255));

    this.viewMyid.setText("未登陆");

    this.btnSend = new JButton("发送消息");

    this.btnSend.setUI(new BEButtonUI().setNormalColor(BEButtonUI.NormalColor.green));

    this.btnSend.setForeground(Color.white);

    this.editId = new JTextField(20);

    this.editContent = new JTextField(20);

    this.debugPane = new JTextPane();

    this.debugPane.setBackground(Color.black);

    this.debugPane.setCaretColor(Color.white);

    Log.getInstance().setLogDest(this.debugPane);

    this.imInfoPane = new JTextPane();

    HardLayoutPane authPanel = new HardLayoutPane();

    JPanel serverInfoPane = new JPanel(new BorderLayout());

    JPanel portInfoPane = new JPanel(new BorderLayout());

    portInfoPane.add(new JLabel(":"), "West");

    portInfoPane.add(this.editServerPort, "Center");

    serverInfoPane.add(this.editServerIp, "Center");

    serverInfoPane.add(portInfoPane, "East");

    authPanel.addTo(serverInfoPane, 2, true);

    authPanel.nextLine();

    authPanel.addTo(new JLabel("用户名:"), 1, true);

    authPanel.addTo(this.editLoginName, 1, true);

    authPanel.nextLine();

    authPanel.addTo(new JLabel("密  码:"), 1, true);

    authPanel.addTo(this.editLoginPsw, 1, true);

    authPanel.nextLine();

    authPanel.addTo(this.btnLogin, 1, true);

    authPanel.addTo(this.btnLogout, 1, true);

    authPanel.nextLine();

    authPanel.addTo(new JLabel("我的id:"), 1, true);

    JPanel idAndVerPanel = new JPanel();

    idAndVerPanel.setLayout(new BoxLayout(idAndVerPanel, 2));

    JLabel lbVer = new JLabel("v2.1b151012.1O");

    lbVer.setForeground(new Color(184, 184, 184));

    idAndVerPanel.add(this.viewMyid);

    idAndVerPanel.add(Box.createHorizontalGlue());

    idAndVerPanel.add(lbVer);

    authPanel.addTo(idAndVerPanel, 1, true);

    authPanel.nextLine();

    HardLayoutPane toPanel = new HardLayoutPane();

    toPanel.addTo(new JLabel("对方ID号:"), 1, true);

    toPanel.addTo(this.editId, 1, true);

    toPanel.nextLine();

    toPanel.addTo(new JLabel("发送内容:"), 1, true);

    toPanel.addTo(this.editContent, 1, true);

    toPanel.nextLine();

    toPanel.addTo(this.btnSend, 4, true);

    toPanel.nextLine();

    HardLayoutPane oprPanel = new HardLayoutPane();

    oprPanel.addTitledLineSeparator("登陆认证");

    oprPanel.addTo(authPanel, 1, true);

    oprPanel.addTitledLineSeparator("消息发送");

    oprPanel.addTo(toPanel, 1, true);

    oprPanel.addTitledLineSeparator();

    JPanel leftPanel = new JPanel(new BorderLayout());

    leftPanel.add(oprPanel, "North");

    JScrollPane imInfoSc = new JScrollPane(this.imInfoPane);

    imInfoSc.setBorder(BorderFactory.createCompoundBorder(

    BorderFactory.createEmptyBorder(0, 7, 0, 7), imInfoSc.getBorder()));

    imInfoSc.setHorizontalScrollBarPolicy(31);

    leftPanel.add(imInfoSc, "Center");

    getContentPane().setLayout(new BorderLayout());

    getContentPane().add(leftPanel, "West");

    JScrollPane sc = new JScrollPane(this.debugPane);

    sc.setBorder(BorderFactory.createCompoundBorder(

    BorderFactory.createEmptyBorder(4, 0, 0, 2), sc.getBorder()));

    sc.setHorizontalScrollBarPolicy(31);

    getContentPane().add(sc, "Center");

    setLocationRelativeTo(null);

    setSize(1000, 700);

  }

 

界面很漂亮,但是以上的代码长度让我不由得哼起来“这让我感到绝望,董小姐”。

难道写swing界面的人,真的要变成码农么?

画界面这么低级、无意义、费时费力的事情,为何要我们一遍又一遍地靠写代码完成?

难道就没有一种更好的方式去解决这个问题吗?

安卓早已有更成熟的做法,为何不能直接拿来用?

 

于是,经过一夜的苦思冥想,我终于找到了下面的方式:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Container>
<Container layout="BorderLayout">
    <JPanel id="leftPanel" position="West" layout="BorderLayout">
        <HardLayoutPane id="oprPanel" position="North">
            <TitledLineSeparator>登陆认证</TitledLineSeparator>
            <HardLayoutPane id="authPanel" w="1">
                <JPanel id="serverInfoPane" w="2" layout="BorderLayout">
                    <JTextField id="editServerIp" position="Center" columns="16" foreground="13, 148, 252">rbcore.openmob.net</JTextField>
                    <JPanel id="portInfoPane" position="East" layout="BorderLayout">
                        <JLabel position="West">:</JLabel>
                        <JTextField id="editServerPort" position="Center" columns="5" foreground="13, 148, 252">7901</JTextField>
                    </JPanel>
                </JPanel>
                <NextLine />
                <JLabel w="1">用户名:</JLabel>
                <JTextField id="editLoginName" columns="22" w="1"></JTextField>
                <NextLine />
                <JLabel w="1">密 码:</JLabel>
                <JPasswordField id="editLoginPsw" columns="22" w="1"></JPasswordField>
                <NextLine />
                <JButton id="btnLogin" w="1" UI="BEButtonUI|NormalColor.blue" foreground="white">登陆</JButton>
                <JButton id="btnLogout" w="1">退出</JButton>
                <NextLine />
                <JLabel w="1">我的id:</JLabel>
                <JPanel id="idAndVerPanel" layout="BoxLayout|2" w="1">
                    <JLabel id="viewMyid" foreground="255, 0, 255">未登陆</JLabel>
                    <horizontalGlue />
                    <JLabel id="lbVer" foreground="184, 184, 184">v2.1b151012.1O</JLabel>
                </JPanel>
                <NextLine />
            </HardLayoutPane>
            <TitledLineSeparator>消息发送</TitledLineSeparator>
            <HardLayoutPane id="toPanel" w="1">
                <JLabel w="1">对方ID号:</JLabel>
                <JTextField id="editId" columns="38" w="3"></JTextField>
                <NextLine />
                <JLabel w="1">发送内容:</JLabel>
                <JTextField id="editContent" columns="38" w="3"></JTextField>
                <NextLine />
                <JButton id="btnSend" UI="BEButtonUI|NormalColor.green" w="4" foreground="white">发送消息</JButton>
                <NextLine />
            </HardLayoutPane>
            <TitledLineSeparator>我的自定义</TitledLineSeparator>
            <HardLayoutPane id="refPanel" w="1" xmlRef="refPanel.xml" />
            <TitledLineSeparator />
        </HardLayoutPane>
        <JScrollPane id="imInfoSc" position="Center" border="CompoundBorder|0,7,0,7" horizontalScrollBarPolicy="31">
            <JTextPane id="imInfoPane" />
        </JScrollPane>
    </JPanel>
    <JScrollPane id="sc" position="Center" border="CompoundBorder|4,0,0,2" horizontalScrollBarPolicy="31">
        <JTextPane id="debugPane" background="black" caretColor="white" />
    </JScrollPane>
</Container>

 

我将上述的复杂界面代码,转换成为一个完整的xml描述文件。 所有组件的属性,均可以在xml的节点中自由增加。配合自己写的高度定制的布局xml解析器,从此界面布局这一“Boring Zone”终于可以自动化啦!

 

终于,写Swing应用不再那么费时费力,而布局,将清晰呈现。配合采用反射技术写成的xml解析器,可以实现xml里面的组件ID与后台的组件声明自动绑定。写Swing程序,从此将和开发Web应用一样容易。今后的开发步骤基本为:

1.       写xml描述文件

2.       后台事件绑定

 

其基本原理,已经和web的jquery开发相当接近!加入组件双向绑定之后,其开发体验将和angularJS接近!

后台要获取一个组件,可以采用类似Jquery的方式:

         JButton btnSend = (JButton)X$.get(“btnSend”);

                  

绑定事件照旧这样写:

         btnSend.addActionListener(new ActionListener(){

                   …

});

 

好了,这样做之后,就真正做到了布局代码XML化,如果需要修改界面布局,只需要轻松地修改XML代码即可。后台强大的XML解析器会自动读取最新的xml布局文件,并重绘整个新的布局文件!

 

 

采用XML布局方式只会带来了哪些变化?

《Swing参照Android采用XML的方式自动布局》这样带来了什么变化呢?变化就是,这样的思想可以大大加快Java桌面应用的开发效率。从今往后,用java写桌面应用再也不用枯燥地用手工代码搭积木了,取而代之的,是层次化非常清晰的XML代码。一个XML布局描述文件就是一个JAVA桌面软件的界面!用此法开发桌面程序,省下来的时间将会相当可观!并且XML的树形结构特性很适合做布局文件组件化,这样,我们可以构建出一些XML组件库,然后基于手里的工具箱快速生成新应用的界面,成就感爆棚!

 

总结:

时间就是金钱,合理地使用框架,可以化繁为简,让以往让人畏惧的繁琐工作不再可怕。

展开阅读全文
打赏
3
0 收藏
分享
加载中
你这个布局框架是用的开源的组件,还是你自己开发的?有开源地址吗?
2017/06/27 09:12
回复
举报
52
2016/08/01 22:00
回复
举报
更多评论
打赏
2 评论
0 收藏
3
分享
返回顶部
顶部