Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1168|回复: 0

[Swing学习]通过xml配置文件布局组件

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-10 23:57:02 | 显示全部楼层 |阅读模式
    开门见山,程序运行结果如下图。
      
       
       
         
       

         
       
      
       
          有4个组件,JButton、JScrollPane(内嵌JTree)、自定义组件ImageButton、一个JTextField。

          布局原则是JButton左边界距离容器左边界5像素、右边界距离容器左边界130像素、所以长度为130-5=125固定不变,JButton上边界距离容器上边界10像素,下边界距离容器下边界35像素,所以高度为35-10=25固定不变;JScrollPane位于容器的中央,其中左右两边距离容器两边均是20像素,所以JScrollPane的宽度随着容器宽度的变化而变化,JScrollPane上下两边距离容器中心高度均是50像素,所以整体高度是100像素;ImageButton的上边界距离容器的底部50像素,左边界距离容器右边界100像素,由于ImageButton会根据背景尺寸产生PreferredSize,所以右边界、下边界不用设置。剩下的JTextField不是通过配置产生,具体见后面介绍。下面来看看xml配置,如下。
       <components>     ⑴<layout class="org.swingframework.layout.FormLayout" />     ⑵<component id="1101" class="javax.swing.JButton">        ⑶<form-data>            <left percentage="0.0" offset="5" />            <right percentage="0.0" offset="130" />            <top percentage="0.0" offset="10"/>            <bottom percentage="0.0" offset="35"/>        </form-data>     </component>     <component id="1102" class="javax.swing.JScrollPane">        <form-data>            <left percentage="0.0" offset="20" />            <top percentage="0.5" offset="-50" />            <right percentage="1.0" offset="-20" />            <bottom percentage="0.5" offset="50"/>        </form-data>     </component>     <component id="1103" class="org.swingframework.component.ImageButton">        <form-data>            <left percentage="1.0" offset="-100" />            <top percentage="1.0" offset="-50" />        </form-data>     </component> </components> (1)指定容器的布局类,目前仅支持FormLayout、CenterLayout两种。
    (2)定义一个组件,指定唯一的id和完整类名。
    (3)为组件指定布局约束。

          由于xml文档结构是固定的,因此xml解析采用XPath。XPath已在JDK1.5中被集成,而且相比DOM更加简单,关于XPath的更多内容参考其他资料。

    定义布局注入LayoutInjection类,目的就是解释一个给定的xml文件,然后去给一个容器生成内部组件并布局这些组件。 public class LayoutInjection {
    private Container injectTarget;
      private InputStream layoutSource;
      private LayoutManager layoutManager;
      private Map<String, ComponentEntry> entryMap;  public LayoutInjection(Container injectTarget, InputStream layoutSource) {
       this.injectTarget = injectTarget;
       this.layoutSource = layoutSource;
      }
    ...... private class ComponentEntry {
       private Component component;
       private FormData formData;   ComponentEntry(Component component, FormData formData) {
        this.component = component;
        this.formData = formData;
       }   public Component getComponent() {
        return component;
       }   public FormData getFormData() {
        return formData;
       }
      }
    }

          单独定义一个ComponentEntry内部类是为了将组件-布局约束关联。定义一个injectLayout方法来完成布局,在injectLayout方法内部,首先读取外部配置文件并将组件与布局约束保存到entryMap,然后为容器设置根据配置得到的布局管理器,下一步插入自定义属性,包括非配置产生的组件,与组件修饰、组件事件监听器等。最后一步是遍历entryMap根据每个组件与其布局约束完成组件创建与布局。

    public final void injectLayout() throws Exception {
       loadComponents();
       injectTarget.setLayout(layoutManager);
       customProperties();
       synchronized (injectTarget.getTreeLock()) {
        Set<String> idSet = entryMap.keySet();
        for (String id : idSet) {
         Component component = getComponentById(id);
         FormData formData = getFormDataById(id);
         injectTarget.add((Component) component, formData);
        }
        injectTarget.doLayout();
       }
      }
    customProperties方法是空实现,需要自己去实现逻辑。 protected void customProperties() {  }

    injectLayout其他部分的实现参见完整源码。
    最后给一个Test测试这个类。
      import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.io.FileInputStream; import javax.swing.BorderFactory;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextField;
    import javax.swing.JTree;
    import javax.swing.WindowConstants; import org.swingframework.component.ImageButton;
    import org.swingframework.layout.FormAttachment;
    import org.swingframework.layout.FormData;
    import org.swingframework.layout.LayoutInjection; public class Test {  public static void main(String[] args) throws Exception {
       JFrame frm = new JFrame();
       frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
       final JPanel panel = new JPanel();
       panel.setPreferredSize(new Dimension(350, 250));
       frm.getContentPane().add(panel, BorderLayout.CENTER);
       FileInputStream input = new FileInputStream("C:/layout.xml");

       LayoutInjection injection = new LayoutInjection(panel, input) {
        @Override
        protected void customProperties() {
         JButton button = (JButton) getComponentById("1101");
         button.setText("this is a JButton");
         JScrollPane jsp = (JScrollPane) getComponentById("1102");
         jsp.setBorder(BorderFactory.createLineBorder(new Color(128,
           128, 128), 2));

         jsp.getViewport().add(new JTree());
         ImageButton imageButton = (ImageButton) getComponentById("1103");
         imageButton.setBackgroundImage(new ImageIcon("button_up.png"));
         imageButton.setRolloverBackgroundImage(new ImageIcon(
           "button_over.png"));

         imageButton.setPressedBackgroundImage(new ImageIcon(
           "button_down.png"));
         // add extend component
         JTextField jtf = new JTextField();
         jtf.setBorder(BorderFactory.createLineBorder(new Color(128,
           128, 128), 2));
         FormData jtfFormData = new FormData();
         jtfFormData.top = new FormAttachment(0.8f, 0);
         jtfFormData.left = new FormAttachment(0.2f, 0);
         jtfFormData.right = new FormAttachment(0.2f, 100);
         jtfFormData.bottom = new FormAttachment(0.8f, 25);
         panel.add(jtf, jtfFormData);
        }
       };

       injection.injectLayout();
       input.close();
       frm.pack();
       frm.setVisible(true);
      }
    }
          加红的需要解释以下,xml数据源是java.io.InputStream的实例,当然不局限与文件读取;一般地,都要实现customProperties完成自定义逻辑,本例是修饰了组件外观,另外以非配置方式加载了JTextField组件,以非配置方式添加组件是很必要的,因为实际应用的时候,你添加的更多的是已有的组件实例而不是xml文件中写死的。
      

      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/11/10/235701734.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 07:38 , Processed in 0.290957 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表