无限分割面板,并略谈组合模式,顺谈数据结构中的链表
程序员文章站
2022-05-04 19:23:57
...
先看无限分割面板的效果图(请原谅我没考虑美观)
当在设计时发现:一个对象A有对象B,对象B中又有对象C……,并且这些对象操作相同时,可以使用组合模式。简单实现是:设计一个类,允许把该类的其他实例注入进去。 如果要按GOF中的组合模式设计,请自已参照相关代码,设计一些抽象类或接口等。
举例:
下面中的A类,就是一个简化了的组合模式。属性a与add方法,表明了,该类A允许注入本类的其他实例。如果你把属性a写成List 或Map时,可允许注入多个本类的其他实例。如果要用完整版的组合模式,请参见GOF的组合模式例子。
测试运行结果:
一个应用举例:
在设计中,由于要通过panel展现多种属性,而这些panel的或上下或左右可以移动,且个数不清楚。Panel中有可能还会再套一个属性,等等。 又由于为了简化使用,希望每一个panel中,都可以很快的访问到其他panel。
简化需求即得:
设计一个面板,该面板可以对其间指定的面板进行分割一个,并在新分割中增加指定面板;这个面板任一个子面板都可以访问到其他子面板或根面板。
下面就是一个满足此要求的无限分割面板。
当在设计时发现:一个对象A有对象B,对象B中又有对象C……,并且这些对象操作相同时,可以使用组合模式。简单实现是:设计一个类,允许把该类的其他实例注入进去。 如果要按GOF中的组合模式设计,请自已参照相关代码,设计一些抽象类或接口等。
举例:
下面中的A类,就是一个简化了的组合模式。属性a与add方法,表明了,该类A允许注入本类的其他实例。如果你把属性a写成List 或Map时,可允许注入多个本类的其他实例。如果要用完整版的组合模式,请参见GOF的组合模式例子。
public class CombinationModelTest { //在这里可以看出,可把A当作 数据结构之链表中的一个节点。 //里面的属性a可看作是存储下一个节点的指针。于是,数据结构可以很快的用在 //面向对象中了。 注意:本例旨在讲简化的组合模式实现,并没有列链表操作。 // 相应的代码实现,读者自行参照数据结库相应实现。 class A { private String name; public A (String name){ this.name=name; } A a;//当然了,你可以使用List ,或Map之类的进行存储,不是非得用变量保存 public void add(A a){ this.a=a; } public void remove(){ this.a=null; } public void operate (){ System.out.println("对象"+name+" 的操作。"); } public A getNext(){ return this.a; } } public void run(){ A a=new A("a"); A b=new A("b"); a.add(b); A c=new A("c"); b.add(c); b=new A("d"); c.add(b); while (a!=null){ a.operate(); a=a.getNext(); } } public static void main(String args[]) { CombinationModelTest dd =new CombinationModelTest(); dd.run(); } }
测试运行结果:
引用
对象a 的操作。
对象b 的操作。
对象c 的操作。
对象d 的操作。
对象b 的操作。
对象c 的操作。
对象d 的操作。
一个应用举例:
在设计中,由于要通过panel展现多种属性,而这些panel的或上下或左右可以移动,且个数不清楚。Panel中有可能还会再套一个属性,等等。 又由于为了简化使用,希望每一个panel中,都可以很快的访问到其他panel。
简化需求即得:
设计一个面板,该面板可以对其间指定的面板进行分割一个,并在新分割中增加指定面板;这个面板任一个子面板都可以访问到其他子面板或根面板。
下面就是一个满足此要求的无限分割面板。
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.FlowLayout; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.Box; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.SpringLayout; /** * 基于二分分割所做的 无限次分割面板。<br/> * 对已经存在的面板,新添一个分割,并填入指定panel.<br> * 组合模式---当在设计时,如果一个对象A中有对象B,B中又有C,等等,而这些对象<br> * 操作都相同,可以用组合模式。简化实现是:设计一个类,允许把该类型的其他有限个实<br> * 例注入进去。<br> * * * @author cloud */ public class FSplitPanel extends JPanel { //所有子组件,都存放于Map中。在新增时自动维护。 private int interval =3; public static final int HORIZONTAL_SPLIT=JSplitPane.HORIZONTAL_SPLIT; public static final int VERTICAL_SPLIT=JSplitPane.VERTICAL_SPLIT; private class UnitData { public boolean isFree=true; private JPanel panel; private String name; private JSplitPane parent; private boolean isFirst=false; public UnitData(){}; public UnitData( boolean isFree){ this.isFree=isFree;}; } private FSplitPanel root; private Map<String,UnitData> componentMap=new HashMap<String,UnitData>(); public FSplitPanel(){ this.root=this; UnitData data=new UnitData(); data.name="root"; data.panel=null; componentMap.put("root", data); } /** * 在指定且已经存在的分割中,新增一个分割。并在新得到分割区域中,加入指定panel。 * @param parent ----指定且已经存在的分割。 * @param name ------对新得到的分割进行定义。 * @param panel ------要用该panel去填充新分割 * @param splitSyle ----分割方向,方平分割还是竖直分割。 * @return true ---true,分割成功;false,分割失败。 */ public boolean add(String parent,String name,JPanel panel,int splitSyle){ UnitData data=componentMap.get(parent); if (data==null) return false; if (parent.equals("root") && (data.parent!=null ) ) return false; if (parent.equals("root")){ SpringLayout layout = new SpringLayout(); this.setLayout(layout); data.isFree=false; data.name=name; data.panel=panel ; data.isFirst=true; this.add(panel); layout.putConstraint(SpringLayout.WEST, panel, interval, SpringLayout.WEST, this); layout.putConstraint(SpringLayout.EAST, this, interval, SpringLayout.EAST,panel ); layout.putConstraint(SpringLayout.NORTH, panel, interval, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.SOUTH, this, interval, SpringLayout.SOUTH, panel); componentMap.put(name, data); } else { //当节点不为空,在当前节点使用JSplitPanel分割,并把当前结点,存放到 //JSplitPanel的左分割中。其右割存放新增的节点 JSplitPane splitPanel=new JSplitPane (splitSyle); splitPanel.setBorder(null); if (data.parent==null){ data.parent=splitPanel; Container c=data.panel.getParent(); c.removeAll(); if (data.isFirst){ SpringLayout layout = new SpringLayout(); c.setLayout(layout); c.add(splitPanel); layout.putConstraint(SpringLayout.WEST, splitPanel, interval, SpringLayout.WEST, c); layout.putConstraint(SpringLayout.EAST, c, interval, SpringLayout.EAST, splitPanel); layout.putConstraint(SpringLayout.NORTH, splitPanel, interval, SpringLayout.NORTH,c ); layout.putConstraint(SpringLayout.SOUTH, c, interval, SpringLayout.SOUTH, splitPanel); } else { c.add(splitPanel); } splitPanel.setLeftComponent(data.panel); UnitData tempData=new UnitData(); tempData.isFree=false; tempData.panel=panel; tempData.name=name; tempData.parent=splitPanel; splitPanel.setRightComponent(panel); componentMap.put(name, tempData); } else { Component c=data.parent.getLeftComponent(); data.parent.setLeftComponent(splitPanel); splitPanel.setLeftComponent(c); UnitData tempData=new UnitData();//为了阅读或以后维护,与前一个if重复 tempData.isFree=false; tempData.panel=panel; tempData.name=name; tempData.parent=splitPanel; splitPanel.setRightComponent(panel); componentMap.put(name, tempData); } } return true; } /** * 获得指定名称的JPanel.注意:仅返回JPanel。 * @param name ----分割区域名。在add方法中,通过name参数进行定义。<br> * 初始(即构造方法中)仅有一个名为root的区域。 */ public JPanel get(String name){ UnitData data=componentMap.get(name); if (data!=null){ return data.panel; } else { return null; } } /** * 获得所有分割名称 */ public List getSplitName(){ List<String> l=new ArrayList(); for (String t :componentMap.keySet()){ l.add(t); } return l; } //<editor-fold defaultstate="collapsed" desc="测试"> public static void createPanel() { JFrame f = new JFrame("d"); f.setSize(400, 300); JPanel p = (JPanel) f.getContentPane(); FSplitPanel pss=new FSplitPanel(); p.add( pss); JPanel t=new JPanel(); pss.add("root", "left", t, FSplitPanel.VERTICAL_SPLIT); t=new JPanel(new FlowLayout(FlowLayout.LEFT)); t.add(new JLabel("right")); pss.add("left", "right", t, FSplitPanel.VERTICAL_SPLIT); t=new JPanel(new FlowLayout(FlowLayout.LEFT)); t.add(new JLabel("left1")); pss.add("left", "left1", t, FSplitPanel.VERTICAL_SPLIT); t=new JPanel(new FlowLayout(FlowLayout.LEFT)); t.add(new JLabel("left11")); pss.add("left", "left11", t, FSplitPanel.HORIZONTAL_SPLIT); t=new JPanel(new FlowLayout(FlowLayout.LEFT)); t.add(new JLabel("right1")); pss.add("right", "right1", t, FSplitPanel.VERTICAL_SPLIT); t=new JPanel(new FlowLayout(FlowLayout.LEFT)); t.add(new JLabel("leftddd")); pss.add("right1", "leftddd", t, FSplitPanel.VERTICAL_SPLIT); t=new JPanel(new FlowLayout(FlowLayout.LEFT)); t.add(new JLabel("right11")); pss.add("right1", "right11", t, FSplitPanel.VERTICAL_SPLIT); t=pss.get("left"); t.setBackground(Color.blue); t=pss.get("right1"); t.setBackground(Color.red); t=pss.get("right11"); t.setBackground(Color.yellow); t=pss.get("left11"); t.setBackground(Color.pink); f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); f.setLocationRelativeTo (null); f.setVisible (true); } public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createPanel(); } }); } //</editor-fold> }