easySwing

在这里插入图片描述

easySwing

实现过程:

在本人之前的博文中,分别介绍了 XML文件的解析窗口编程(Swing)
那么,我们在学习XML文件的解析的时候,可能会想:
XML文件有什么用呢?
若是存储属性的话性能还不如properties文件。
但是,XML文件能够在保证属性的同时,还能够保证级别所属。

而我们在学习窗口编程的时候,也深刻地体会到了窗口编程代码量之大。
那么,在本篇博文中,本人就来讲解下如何 通过扫描一个XML文件来实现 窗口编程的一些基本操作:

首先,本人来展示下我们需要扫描的XML文件的模板:

<?xml version="1.0" encoding="UTF-8"?>
<menu_bar>
    <menu caption="文件">
        <menu caption="新建">
            <item caption="工程" action="dealProject"></item>
            <item caption="包" action="dealPackage"></item>
            <separator></separator>
            <item caption="类" action="dealClass"></item>
        </menu>
        <item caption="打开" action="dealOpen"></item>
        <item caption="关闭" action="exitApp"></item>
    </menu>
    <menu caption="编辑"></menu>
    <menu caption="资源"></menu>
</menu_bar>

现在,本人来给本人之前博文《XML 解析》所讲的XMLParser类中增加两个方法:

	/* 处理根标签 */
	public void parseRoot(Document document) {
		Element root = (Element)document.getChildNodes().item(0);
		dealElement(root, 0);
	}
	
	/* 处理每一层标签 */
	public void parseElement(Element element) {
		NodeList nodeList = element.getChildNodes();
		for (int index = 0; index < nodeList.getLength(); index++) {
			Node node = nodeList.item(index);
			if (node instanceof Element) {	//处理紧接下来一层的标签
				dealElement((Element) node, index);
			}
		}
	}

那么,现在,本人为了防止 新同学 或者 已经遗忘了本人之前所讲的知识点的不明白XMLParser都在做什么,本人现在来展示下完整版XMLParser:

package com.mec.util;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


public abstract class XMLParser {
	private static volatile DocumentBuilder db;
	
	public XMLParser() {
	}
	
	private static DocumentBuilder getDocumentBuilder() throws ParserConfigurationException {
		if (db == null) {
			synchronized (XMLParser.class) {
				if (db == null) {
					db = DocumentBuilderFactory
							.newInstance()
							.newDocumentBuilder();
				}
			}
		}
		return db;
	}
	
	public static Document getDocument(String xmlPath) {
		InputStream is = XMLParser.class.getResourceAsStream(xmlPath);
		if (is == null) {
			System.out.println("xmlPath[" + xmlPath + "]不存在!");
			return null;
		}
		
		return getDocument(is);
	}
	
	public static Document getDocument(InputStream is) {
		Document document = null;
		try {
			document = getDocumentBuilder().parse(is);
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		
		return document;
	}
	
	public abstract void dealElement(Element element, int index);
	
	public void parseTag(Document document, String tagName) {
		NodeList nodeList = document.getElementsByTagName(tagName);
		for (int index = 0; index < nodeList.getLength(); index++) {
			Element ele = (Element) nodeList.item(index);
			dealElement(ele, index);
		}
	}
	
	public void parseRoot(Document document) {
		Element root = (Element)document.getChildNodes().item(0);
		dealElement(root, 0);
	}
	
	public void parseElement(Element element) {
		NodeList nodeList = element.getChildNodes();
		for (int index = 0; index < nodeList.getLength(); index++) {
			Node node = nodeList.item(index);
			if (node instanceof Element) {	//处理紧接下来一层的标签
				dealElement((Element) node, index);
			}
		}
	}
	
	public void parseTag(Element element, String tagName) {
		NodeList nodeList = element.getElementsByTagName(tagName);
		for (int index = 0; index < nodeList.getLength(); index++) {
			Element ele = (Element) nodeList.item(index);
			dealElement(ele, index);
		}
	}
	
}

那么,我们现在可以通过 parseRoot 方法 和 parseTag 方法来调用抽象方法dealElement,从而实现构建窗口的功能。

本人现在给出一个用于存储从XML文件中读取出来的单个信息的类:

package com.mec.util;

import java.lang.reflect.Method;

public class MenuActionDefinaton {
	private Method method;
	private Object object;
	
	public MenuActionDefinaton() {
	}

	public Method getMethod() {
		return method;
	}

	public void setMethod(Method method) {
		this.method = method;
	}

	public Object getObject() {
		return object;
	}

	public void setObject(Object object) {
		this.object = object;
	}
	
		
}

现在,看到本人给出的这个类和上面的讲解,就应该能明白:
本人要通过单例-工厂模式来存储所有从XML文件上所读取的信息。
那么,现在,本人给出一个存储所有从XML文件上读取出来的信息的类:

package com.mec.util;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Map;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.mec.about_xmlparse.core.XMLParser;

public class MenuFactory {
	private static final Font menuFont = new Font("宋体", Font.PLAIN, 12);
	private JMenuBar bar;
	
	private Map<String, MenuActionDefinaton> menuActionPool;
	private Object object;
	private Class<?> klass;
	
	public MenuFactory() {
	}
	
	public void setObject(Object object) {
		this.object = object;
		this.klass = object.getClass();
	}

	public void setBar(JMenuBar bar) {
		this.bar = bar;
	}
	
	private void creatMenuItem(Element element, JMenu parentMenu) {
		String captionName = element.getAttribute("caption");
		String actionCommand = element.getAttribute("action");
		JMenuItem menuItem = new JMenuItem(captionName);
		menuItem.setActionCommand(actionCommand);
		parentMenu.add(menuItem);
		
		if (menuActionPool.get(actionCommand) == null) {
			try {
				
				Method method = klass.getDeclaredMethod(actionCommand, new Class<?>[] {});
				MenuActionDefinaton miad = new MenuActionDefinaton();
				miad.setObject(object);
				miad.setMethod(method);
				menuActionPool.put(actionCommand, miad);
			} catch (Exception e1) {
				// TODO 处理异常
			}
		}
		
		menuItem.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				String command = menuItem.getActionCommand();
				MenuActionDefinaton miad = menuActionPool.get(command);
				if (miad == null) {
					System.out.println("菜单项没有与[" + command+ "]对应的方法");
					return;
				}
				Object object = miad.getObject();
				Method method = miad.getMethod();
				try {
					method.invoke(object, new Object[] {});
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
					e1.printStackTrace();
				}
			}
		});
		
	}
	
	private JMenu creatMenu(Element element, JMenu parentMenu) {
		String captionName = element.getAttribute("caption");
		JMenu menu = new JMenu(captionName);
		menu.setFont(menuFont);
		if (parentMenu == null) {
			bar.add(menu);
		} else {
			parentMenu.add(menu);
		}
		
		return menu;
	}
	
	private void dealMenu(Element element, JMenu parentMenu) {
		new XMLParser() {
			@Override
			public void dealElement(Element element, int index) {
				String tagName = element.getTagName();
				String captionName = element.getAttribute("caption");
				if (tagName.equalsIgnoreCase("menu")) {	// 处理菜单
					JMenu menu = creatMenu(element, parentMenu);
					dealMenu(element, menu);	//处理菜单/菜单项
					return;
				}
				if (tagName.equalsIgnoreCase("item")) {	// 处理菜单项
					creatMenuItem(element, parentMenu);
					return;
				}
				if (tagName.equalsIgnoreCase("separator")) {	// 处理分隔线
					if (parentMenu == null) {
						return;
					}
					parentMenu.addSeparator();
				}
			}
		}.parseElement(element);
	}
	
	public void loadMenu(String menuConfigFile) {
		Document document = XMLParser.getDocument(menuConfigFile);
		if (document == null) {
			return;
			//TODO 可以报/指定异常
		}
		
		menuActionPool = new Hashtable<String, MenuActionDefinaton>();
		new XMLParser() {
			
			@Override
			public void dealElement(Element element, int index) {
				dealMenu(element, null);
			}
		}.parseRoot(document);;
	}
	
}

那么,现在,本人来给出一个测试窗口:

package com.mec.menu.test.simple;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.WindowConstants;

import com.mec.util.FrameIsNullException;
import com.mec.util.IMecView;
import com.mec.util.MenuFactory;
import com.mec.util.ViewTool;

public class SimpleMenuView implements IMecView {
	private JFrame jf;
	private JMenuBar jmnbBar;
	
	public SimpleMenuView() {
		initView();
	}
	
	@Override
	public void init() {
		jf = new JFrame("测试窗口");
        jf.setSize(400, 400);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        jf.setLayout(new BorderLayout());
        
        jmnbBar = new JMenuBar();
        jf.setJMenuBar(jmnbBar);
        
        
        jf.setJMenuBar(jmnbBar);
        MenuFactory menuFactory = new MenuFactory();
        menuFactory.setBar(jmnbBar);
        menuFactory.setObject(this);
        menuFactory.loadMenu("/menu.cfg.xml");

	}
	
	protected void doShow(String actionCommand) {
		System.out.println(actionCommand);
	}

	public void doProject() {
		ViewTool.showWarnning(jf, "暂未开放此功能");
	}
	
	public void doPackage() {
		ViewTool.showError(jf, "暂未开放此功能");
	}
	
	public void doClass() {
		ViewTool.showMessage(jf, "暂未开放此功能");
	}
	
	public void doOpen() {
		ViewTool.showMessage(jf, "暂未开放此功能");
	}
	
	public void exitApp() {
		closeView();
	}
	
	private void closeView() {
		try {
			exitView();
		} catch (FrameIsNullException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void reinit() {}

	@Override
	public void dealEvent() {
		jf.addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				closeView();
			}
			
		});
	}

	@Override
	public JFrame getFrame() {
		return jf;
	}

}

现在,本人再来给出一个测试类:

package com.mec.menu.test.simple;

import javax.swing.JMenuBar;

import org.w3c.dom.Element;

import com.mec.about_xmlparse.core.XMLParser;
import com.mec.util.FrameIsNullException;
import com.mec.util.MenuFactory;


public class SimpleTest {

	public static void main(String[] args) {
		SimpleMenuView testView = new SimpleMenuView();
		try {
			testView.showView();
		} catch (FrameIsNullException e) {
			e.printStackTrace();
		}
	}

}

那么,我们来看一下运行结果:
在这里插入图片描述

当我们点击菜单选项时,由于本篇博文主要用于简单讲解下实现思路,并不深究其它功能的实现,所以就会弹出如下界面:
在这里插入图片描述

(注:上述代码中的ViewTool小工具 和 IMecView接口 以及 FrameIsNullException小工具在本人的博文《浅谈Swing —— 窗口编程》的最后有具体代码)


完整代码:

需要完整代码的同学,请点击下方链接:
Easy-Swing


那么,本篇博文的所有知识点就讲解完毕了!!!
觉得有所帮助的同学请留下👍,谢谢!!!

posted @ 2020-04-21 23:57  在下右转,有何贵干  阅读(44)  评论(0编辑  收藏  举报