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
那么,本篇博文的所有知识点就讲解完毕了!!!
觉得有所帮助的同学请留下👍,谢谢!!!