文档章节

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

lnwazg
 lnwazg
发布于 2016/05/20 16:21
字数 1806
阅读 128
收藏 0

众所周知,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组件库,然后基于手里的工具箱快速生成新应用的界面,成就感爆棚!

 

总结:

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

© 著作权归作者所有

lnwazg

lnwazg

粉丝 20
博文 8
码字总数 13103
作品 4
南京
程序员
私信 提问
加载中

评论(2)

愚_者
愚_者
你这个布局框架是用的开源的组件,还是你自己开发的?有开源地址吗?
西米小娅
西米小娅
52
界面编程与视图(View)组件

Android应用的绝大部分UI组件都放在android.widget包及其子包、android.view包及其子包中,Android应用的所有UI组件都继承了View类,View组件非常类似于Swing编程的JPanel,它代表一个空白的...

谷飞
2012/11/05
306
0
android组建属性及使用许可

线性布局LinearLayout组件属性列表 线性布局参数LinearLayout_Layout 相对布局RalativeLayout 相对布局参数RalativeLayout_Layout 绝对布局参数AbsoluteLayout_Layout 框布局FrameLayout 框布...

xiahuawuyu
2013/01/06
228
0
谈论android java布局和xml布局的优缺点

今天遇到一个问题,讲讲 java布局和xml布局的优缺点。 我想了想,说不出太具体的来。我个人认为xml布局是google推荐的,也就习惯了,而且方便。现在纠结这个问题,细想来,也无非多了一步xml...

今幕明
2014/03/24
2K
0
解决android:background背景图片被拉伸问题

ImageView中XML属性src和background的区别: background会根据ImageView组件给定的长宽进行拉伸,而src就存放的是原图的大小,不会进行拉伸。src是图片内容(前景),bg是背景,可以同时使用...

JayPark不作死
2014/09/29
3.7K
0
Android Fragment的使用

可以分为下面的几部分: 使用支持库 创建一个Fragment 创建一个动态UI 多个Fragment之间的通信 1、使用支持库 如果您的应用需要运行在3.0及以上的版本,可以忽略这部分内容。 如果您的应用使...

娶到笨笨
2014/04/07
95
3

没有更多内容

加载失败,请刷新页面

加载更多

移动开发中的 Web:WebView、WebKit、JSCore、Web 优化、热修复、跨平台、Native、Hybrid……

移动开发领域近年来已经逐渐告别了野蛮生长的时期,进入了相对成熟的时代。而一直以来 Native 和 Web 的争论从未停止,通过开发者孜孜不倦的努力,Web 的效率和 Native 的体验也一直在寻求着...

编辑部的故事
27分钟前
14
0
MySQL8.0.17 - Multi-Valued Indexes 简述

本文主要简单介绍下8.0.17新引入的功能multi-valued index, 顾名思义,索引上对于同一个Primary key, 可以建立多个二级索引项,实际上已经对array类型的基础功能做了支持 (感觉官方未来一定...

阿里云官方博客
今天
11
0
make4.1降级 make-3.81、2错误

在编译 make-3.82 的时候出现如下错误提示 glob/glob.c:xxx: undefined reference to `__alloca'` 修改 /glob/glob.c // #if !defined __alloca && !defined __GNU_LIBRARY__ # ifdef __GNUC......

Domineering
今天
18
0
Rainbond集群的安装和运维的原理

本文将解读Rainbond集群的安装和运维的原理,使用户基本了解Rainbond的安装机制和运维重点,便于用户搭建大型Rainbond集群。 1.Rainbond集群节点概述 1.1 节点分类 属性 类型 说明 manage 管...

好雨云帮
今天
11
0
好程序员大数据学习路线分享UDF函数

1.为什么需要UDF? 1)、因为内部函数没法满足需求。 2)、hive它本身就是一个灵活框架,允许用自定义模块功能,如可以自定义UDF、serde、输入输出等。 2.UDF是什么? UDF:user difine fun...

好程序员官方
今天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部