Menu aus XML

zerix

Hausmeister
Moderator
Hallo,

ich weiß, dass Tom sowas schon mal gepostet hat. Aber ich dachte, ich schreib es mal mit dem SAX-Parser und erweitere es ein wenig.
Da es teilweise Standard ist, dass die meisten Menu-Punkte auch in einer Toolbar enthalten sind, wird hier auch die Möglichkeit gegeben, eine Menupunkte mit in eine Toolbar zu übernehmen. Dazu muss man nur den toolbar-schalter in der XML-File setzen.
Zusätlich können auch Mnemonics(Unterstrichene Buchstaben im Menu) und Acceleratoren(z.b. STRG+S) gesetzt werden. Allerdings müssen bei den Acceleratoren die englische Namen der Tasten verwendet werden (Strg -> CTRL). Zusätlich hab ich ein Schema-File geschrieben. Gegen dieses File wird die XML-File validiert, um sicherzustellen, dass die XML-File auch richtig aufgebaut ist.
Schaut es auch einfach mal an.

Java:
import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JToolBar;

import de.tutorials.menu.MenuCtrl;


public class MenuExample extends JFrame {

	public MenuExample() {
		super("MenuExample");
		setSize(300,300);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		MenuCtrl menuCtrl = new MenuCtrl();
		try {
			menuCtrl.createMenuBar("mymenu.xml");
		} catch (Exception e) {
			e.printStackTrace();
		}
		JToolBar toolbar = menuCtrl.getToolBar();
		toolbar.setFloatable(false);
		setJMenuBar(menuCtrl.getMenuBar());
		add(toolbar,BorderLayout.NORTH);
		
	}
	
	
	public static void main(String[] args) {
		new MenuExample().setVisible(true);
	}

}

Java:
package de.tutorials.menu;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import javax.swing.JMenuBar;
import javax.swing.JToolBar;
import javax.xml.XMLConstants;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

public class MenuCtrl {

	private JMenuBar menubar = null;

	private JToolBar toolbar = null;

	public JMenuBar getMenuBar() {
		return menubar;
	}

	public JToolBar getToolBar() {
		return toolbar;
	}

	public void createMenuBar(String file) throws Exception {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
				.newSchema(new File("menu.xsd"));
		factory.setValidating(false);
		factory.setNamespaceAware(true);
		factory.setSchema(schema);
		SAXParser parser = factory.newSAXParser();
		SwingMenuDocHandler handler = new SwingMenuDocHandler();
		parser.parse(new File(file), handler);

		menubar = handler.getMenuBar();
		toolbar = handler.getToolBar();

	}

}

Java:
package de.tutorials.menu;

import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public class SwingMenuDocHandler extends DefaultHandler {

	private final String EL_MENU = "menu";

	private final String EL_MENU_ITEM = "menuItem";

	private final String EL_SEPARATOR = "separator";

	private final String EL_ACTION_LISTENER = "actionListener";

	private final String ATT_TOOLBAR = "toolbar";

	private final String ATT_ACCELERATOR = "accelerator";

	private final String ATT_MNEMONIC = "mnemonic";

	private final String ATT_ICON = "icon";

	private final String ATT_ACTION = "action";

	private final String ATT_TEXT = "text";

	private JMenuBar bar = null;

	private JToolBar toolbar = null;

	private JButton toolbutton = null;

	private JMenuItem item = null;

	private ArrayList<JMenu> menus = new ArrayList<JMenu>();

	private HashMap<String, ActionListener> listeners = new HashMap<String, ActionListener>();

	private ImageIcon icon = null;

	private String text = null;

	private String action = null;

	private int last = -1;

	boolean hasAction = false;

	public void endDocument() throws SAXException {
	}

	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if (qName.equals(EL_MENU)) {
			if (last > 0) {
				menus.get(last - 1).add(menus.get(last));
			} else
				bar.add(menus.get(last));
			menus.remove(last);
			last--;
		} else if (qName.equals(EL_MENU_ITEM)) {
			toolbutton = null;
			item = null;
			icon = null;
			action = null;
		} else if (qName.equals(EL_ACTION_LISTENER)) {
			hasAction = false;
		}
	}

	public void startDocument() throws SAXException {
		bar = new JMenuBar();
	}

	public void startElement(String uri, String localName, String qName,
			Attributes atts) throws SAXException {
		if (qName.equals(EL_MENU)) {
			String icon = atts.getValue(ATT_ICON);
			JMenu menu = new JMenu(atts.getValue(ATT_TEXT));
			menu.setMnemonic(getKeyEvent(atts.getValue(ATT_MNEMONIC)));
			if(icon != null)
				menu.setIcon(new ImageIcon(icon));
			menus.add(menu);
			last++;
		} else if (qName.equals(EL_MENU_ITEM)) {
			addMenuItem(atts);
			if (new Boolean(atts.getValue(ATT_TOOLBAR)).booleanValue()) {
				addToolbarButton(atts);
			}
		} else if (qName.equals(EL_ACTION_LISTENER)) {
			hasAction = true;

		} else if (qName.equals(EL_SEPARATOR)) {
			menus.get(last).addSeparator();
		}
	}

	public JMenuBar getMenuBar() {
		return bar;
	}

	public JToolBar getToolBar() {
		return toolbar;
	}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		if (hasAction) {
			String text = new String(ch, start, length);
			text = text.trim();

			try {
				ActionListener listener = null;
				if (listeners.containsKey(text)) {
					listener = listeners.get(text);
				} else {
					listener = (ActionListener) Class.forName(text)
							.newInstance();
					listeners.put(text, listener);
				}
				
				item.addActionListener(listener);
				if (toolbutton != null) {
					toolbutton.addActionListener(listener);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void error(SAXParseException e) throws SAXException {
		System.out.println(e.getLineNumber());
		e.printStackTrace();
		throw new SAXException("XML-Datei entspricht nicht dem Schema");
	}

	@Override
	public void fatalError(SAXParseException e) throws SAXException {
		throw new SAXException("XML-Datei entspricht nicht dem Schema");
	}

	@Override
	public void warning(SAXParseException e) throws SAXException {
		super.warning(e);
	}

	private void addMenuItem(Attributes atts) {
		text = atts.getValue(ATT_TEXT);
		String iconPath = atts.getValue(ATT_ICON);
		if (iconPath != null)
			icon = new ImageIcon(iconPath);
		action = atts.getValue(ATT_ACTION);

		item = new JMenuItem();
		item.setText(text);
		if (icon != null) {
			item.setIcon(icon);
		}
		item.setActionCommand(action);
		item.setMnemonic(getKeyEvent(atts.getValue(ATT_MNEMONIC)));
		item.setAccelerator(getKeyStroke(atts.getValue(ATT_ACCELERATOR)));
		menus.get(last).add(item);
	}

	private void addToolbarButton(Attributes atts) {
		if (toolbar == null) {
			toolbar = new JToolBar();
		}

		toolbutton = new JButton();
		if (icon != null) {
			toolbutton.setIcon(icon);
		} else {
			toolbutton.setText(text);
		}

		toolbutton.setToolTipText(text);
		toolbutton.setActionCommand(action);
		toolbutton.setMargin(new Insets(0, 0, 0, 0));
		toolbutton.setBorderPainted(false);
		toolbutton.addMouseListener(new MouseAdapter() {
			public void mouseEntered(MouseEvent e) {
				if (((JButton) e.getSource()).isEnabled()) {
					((JButton) e.getSource()).setBorderPainted(true);
				}
			}

			public void mouseExited(MouseEvent e) {
				if (((JButton) e.getSource()).isEnabled()) {
					((JButton) e.getSource()).setBorderPainted(false);
				}
			}
		});
		toolbar.add(toolbutton);
	}

	private int getKeyEvent(String s) {
		if (s != null && !s.equals("")) {
			String keyEvent = "VK_" + s.toUpperCase();

			try {
				Field f = KeyEvent.class.getField(keyEvent);

				return f.getInt(null);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return KeyEvent.VK_UNDEFINED;
	}

	private KeyStroke getKeyStroke(String s) {
		if (s != null && !s.equals("")) {
			int i = s.indexOf('+');

			if (i == -1) {
				i = s.indexOf('-');
			}

			if (i == -1) {
				return KeyStroke.getKeyStroke(getKeyEvent(s),
						KeyEvent.VK_UNDEFINED);
			}

			String s1 = s.substring(i + 1);
			String actionEvent = s.substring(0, i).toUpperCase() + "_MASK";

			try {
				Field f = ActionEvent.class.getField(actionEvent);

				return KeyStroke.getKeyStroke(getKeyEvent(s1), f.getInt(null));
			} catch (Exception e) {

			}
		}

		return null;
	}

}

Java:
package de.tutorials.actions;

import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;

public class MenuAction extends AbstractAction {

	public void actionPerformed(ActionEvent e) {
		String action = e.getActionCommand();
		if(action.equals("file.save")){
			System.out.println("Save");
		}
		else if(action.equals("file.exit")){
			System.exit(0);
		}
	}

}

XML:
<?xml version="1.0" encoding="UTF-8"?>

<menubar xmlns="http://www.home.org/menu" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.home.org/menu menu.xsd ">
    <menu text="Datei">
        <menuItem text="Speichern" action="file.save"  icon="disk.png" mnemonic="s" accelerator="ctrl+s" toolbar="true">
            <actionListener>de.tutorials.actions.MenuAction</actionListener>
        </menuItem>
        <separator/>
        <menuItem text="Beenden" action="file.exit" icon="door_in.png">
            <actionListener>de.tutorials.actions.MenuAction</actionListener>
        </menuItem>
    </menu>
</menubar>

Das ist das Schemafile (menu.xsd)
XML:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.home.org/menu"
    xmlns:tns="http://www.home.org/menu" elementFormDefault="qualified">

    <attributeGroup name="menuAttributes">
        <attribute name="text" type="tns:estring" use="required"/>
        <attribute name="mnemonic" type="tns:mstring" use="optional"/>
        <attribute name="icon" type="tns:estring" use="optional"/>
    </attributeGroup>

    <attributeGroup name="menuItemExtension">
        <attribute name="action" type="tns:estring" use="required"/>
        
        <attribute name="toolbar" type="boolean" use="optional"/>
        <attribute name="accelerator" type="tns:estring" use="optional"/>
    </attributeGroup>

    <group name="menuItemMenuGroup">
        <choice>
            <element name="menuItem" type="tns:menuItemType"/>
            <element name="menu" type="tns:menuType"/>
        </choice>
    </group>
    
    <group name="menuItemGroup">
        <sequence>
            <element name="separator" type="tns:separatorType"/>
            <group ref="tns:menuItemMenuGroup" />
        </sequence>
    </group>

    <complexType name="menubarType">
        <sequence>
            <element name="menu" type="tns:menuType" minOccurs="1" maxOccurs="unbounded"> </element>
        </sequence>
    </complexType>

    <complexType name="menuType">
        <sequence>
            <group ref="tns:menuItemMenuGroup"/>
            <choice minOccurs="0" maxOccurs="unbounded">
                <group ref="tns:menuItemMenuGroup"/>
                <group ref="tns:menuItemGroup" minOccurs="0" maxOccurs="unbounded"> </group>
            </choice>
        </sequence>
        <attributeGroup ref="tns:menuAttributes"/>
    </complexType>

    <complexType name="menuItemType">
        <sequence>
            <element name="actionListener" type="tns:estring" minOccurs="0" maxOccurs="unbounded" />
        </sequence>
        <attributeGroup ref="tns:menuAttributes"/>
        <attributeGroup ref="tns:menuItemExtension"/>
    </complexType>

    <complexType name="separatorType"> </complexType>

    <simpleType name="estring">
        <restriction base="string">
            <minLength value="1"/>
        </restriction>
    </simpleType>
    
    <simpleType name="mstring">
        <restriction base="string">
            <minLength value="1"/>
            <maxLength value="1"/>
        </restriction>
    </simpleType>

    <element name="menubar" type="tns:menubarType"/>
</schema>



Man kann für jeden Menüpunkt eine eigene Action schreiben oder für Gruppen oder alle die gleiche Action nehmen.

Für Anregungen und Verbesserungsvorschläge bin ich dankbar.

Die nächsten Tage werde ich das gleiche mal für SWT posten.

MFG
zEriX
 
Zuletzt bearbeitet von einem Moderator:

Berger89

Grünschnabel
Ich versuche gerade eine XML Datei in ein SWT Menu umzuwandeln, aber ich komme nicht wirklich zur Lösung...
Versucht habe ich alle "menuitem" in eine Arraylist zu packen und alle "submenu" in eine Arraylist. Diese ArrayLists wollte ich dann im Menu aufrufen. Das Problem ist dass zwischen den ArrayLists kein Zusammenhang besteht und ich somit beim Aufbau des Menues keine Ahnung habe welche "menuitems" zu welchem "submenu" gehören.....

Eine Ahnung wie ich das besser hinbekomme um diese XML Datei als Popupmenu darzustellen?

XML-Datei:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<!--Aufbau Contextmenu für Auswahl Werte -->
<menu xsi:noNamespaceSchemaLocation="Untitled1.xsd"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<menuitem tableColumn="messdaten.energie" labelName="Energie"/>
	<menuitem tableColumn="messdaten.leistung" labelName="Leistung"/>
	<separator/>
	<submenu labelName="Temperatur(Grad Celsius)">
		<menuitem tableColumn="messdaten.gent" labelName="Generator"/>
		<menuitem tableColumn="messdaten.gent2" labelName="Generator 2"/>
		<menuitem tableColumn="messdaten.lagert" labelName="Lager"/>
		<menuitem tableColumn="messdaten.lagert2" labelName="Lager 2"/>
		<menuitem tableColumn="messdaten.aussent" labelName="Aussentemperatur"/>
		<menuitem tableColumn="messdaten.getrt" labelName="Getriebe"/>
		<menuitem tableColumn="messdaten.temp_gondel" labelName="Gondel"/>
		<menuitem tableColumn="messdaten.temp_kuehlwasser" labelName="Kühlwasser"/>
		<menuitem tableColumn="messdaten.temp_generatorlager" labelName="Generatorlager"/>
		<menuitem tableColumn="messdaten.temp_spinner" labelName="Spinner"/>
		<menuitem tableColumn="messdaten.temp_hydraulik" labelName="Hydraulik"/>
		<menuitem tableColumn="messdaten.temp_schleifring" labelName="Schleifring"/>
		<menuitem tableColumn="messdaten.temp_busbarsec" labelName="Busbarsection"/>
		<menuitem tableColumn="messdaten.temp_hub_controller" labelName="Hub Controller"/>
		<menuitem tableColumn="messdaten.temp_top_steuerung" labelName="Top Steuerung"/>
		<menuitem tableColumn="messdaten.temp_trafo_phase_1" labelName="Trafo Phase 1"/>		
		<menuitem tableColumn="messdaten.temp_trafo_phase_2" labelName="Trafo Phase 2"/>
		<menuitem tableColumn="messdaten.temp_trafo_phase_3" labelName="Trafo Phase 3"/>		
		<menuitem tableColumn="messdaten.temp_geno_phase_2" labelName="Generator Phase 2"/>
		<menuitem tableColumn="messdaten.temp_geno_phase_3" labelName="Generator Phase 3"/>
		<menuitem tableColumn="messdaten.temp_geno_lager_b" labelName="Generator Lager b"/>
		<menuitem tableColumn="messdaten.temp_pitch_motor_1" labelName="Pitch Motor 1"/>
		<menuitem tableColumn="messdaten.temp_pitch_motor_2" labelName="Pitch Motor 2"/>
		<menuitem tableColumn="messdaten.temp_pitch_motor_3" labelName="Pitch Motor 3"/>
		<menuitem tableColumn="messdaten.temp_pitch_box_1" labelName="Pitch Box 1"/>
		<menuitem tableColumn="messdaten.temp_pitch_box_2" labelName="Pitch Box 2"/>
		<menuitem tableColumn="messdaten.temp_pitch_box_3" labelName="Pitch Box 3"/>
		<menuitem tableColumn="messdaten.temp_turm_unten" labelName="Turm unten"/>
		<menuitem tableColumn="messdaten.temp_turm_oben" labelName="Turm oben"/>
		<menuitem tableColumn="messdaten.temp_lager_lw_rotor" labelName="Lager lw Rotor"/>
		<menuitem tableColumn="messdaten.temp_lager_lw_gen" labelName="Lager lw Generator"/>
		<menuitem tableColumn="messdaten.temp_lager_sw_rotor" labelName="Lager sw Rotor"/>
		<menuitem tableColumn="messdaten.temp_lager_sw_gen" labelName="Lager sw Generator"/>
		<menuitem tableColumn="messdaten.temp_lager_zw" labelName="Lager zw"/>
		<menuitem tableColumn="messdaten.temp_getr_oel_kuehl" labelName="Getriebe Öl Kühlung"/>
		<menuitem tableColumn="messdaten.temp_rotor_bremse" labelName="Rotor Bremse"/>
	</submenu>
	<submenu labelName="Kilowatt(kW)">
		<menuitem tableColumn="messdaten.energie" labelName="Energie"/>
		<menuitem tableColumn="messdaten.leistung" labelName="Leistung"/>		
		<menuitem tableColumn="messdaten.gen_leistung" labelName="Generator Leistung"/>
		<menuitem tableColumn="messdaten.gen_scheinleistung" labelName="Generator Scheinleistung"/>
		<menuitem tableColumn="messdaten.gen_blindleistung" labelName="Generator Blindleistung"/>
		<menuitem tableColumn="messdaten.prod1" labelName="Produktion 1"/>
		<menuitem tableColumn="messdaten.prod2" labelName="Produktion 2"/>
		<menuitem tableColumn="messdaten.prod_ges" labelName="Produktion Gesamt"/>
		<menuitem tableColumn="messdaten.abgab" labelName="Abgabe"/>
		<menuitem tableColumn="messdaten.bezug" labelName="Bezug"/>		
	</submenu>
	<separator/>
	<submenu labelName="Windgeschwindigkeit(m/s)">
		<menuitem tableColumn="messdaten.wind_geschw" labelName="Windgeschwindigkeit"/>
		<menuitem tableColumn="messdaten.wind_geschw_az" labelName="Windgeschwindigkeit Azimut"/>
		<menuitem tableColumn="messdaten.wind_geschw_mittel" labelName="Windgeschwindigkeit Mittel"/>
		<menuitem tableColumn="messdaten.wind_geschw_aneo_1" labelName="Windgeschwindigkeit Anemometer 1"/>
		<menuitem tableColumn="messdaten.wind_geschw_aneo_2" labelName="Windgeschwindigkeit Anemometer 2"/>
	</submenu>
	<separator/>
	<submenu labelName="Windrichtung(rpm)">
		<menuitem tableColumn="messdaten.wind_richtung_gondel" labelName="Windrichtung Gondel"/>
		<menuitem tableColumn="messdaten.wind_richtung_gondel_abs" labelName="Windrichtung ABS"/>
		<menuitem tableColumn="messdaten.wind_richtung_absolut" labelName="Windrichtung Absolut"/>
		<menuitem tableColumn="messdaten.wind_richtung_relativ" labelName="Windrichtung Relativ"/>
		<menuitem tableColumn="messdaten.wind_richtung_fahne_1" labelName="Windrichtung Fahne 1"/>
		<menuitem tableColumn="messdaten.wind_richtung_fahne_2" labelName="Windrichtung Fahne 2"/>
		<menuitem tableColumn="messdaten.azimut" labelName="Azimut"/>
	</submenu>
	<separator/>
	<submenu labelName="Umdrehungen(rpm)">
		<menuitem tableColumn="messdaten.rpm_gen" labelName="Generator "/>
		<menuitem tableColumn="messdaten.rpm_rotor" labelName="Rotor"/>
	</submenu>
	<separator/>
	<submenu labelName="Anstellwinkel(Grad)">
		<menuitem tableColumn="messdaten.pitch" labelName="Pitch"/>
		<menuitem tableColumn="messdaten.pitch_2" labelName="Pitch 2"/>
		<menuitem tableColumn="messdaten.pitch_3" labelName="Pitch 3"/>
	</submenu>
	<separator/>
	<submenu labelName="Stunden">
		<menuitem tableColumn="messdaten.stunden_betrieb" labelName="Betriebsstunden"/>
		<menuitem tableColumn="messdaten.stunden_netz_ok" labelName="Netz Ok"/>
		<menuitem tableColumn="messdaten.stunden_service" labelName="Service"/>
		<menuitem tableColumn="messdaten.stunden_drehen" labelName="Drehen"/>
		<menuitem tableColumn="messdaten.stunden_spannung_an" labelName="Spannung an"/>
		<menuitem tableColumn="messdaten.stunden_umgebung_ok" labelName="Umgebung Ok"/>
		<menuitem tableColumn="messdaten.stunden_summe" labelName="Summe"/>
		<menuitem tableColumn="messdaten.stunden_total" labelName="Total"/>
		<menuitem tableColumn="messdaten.btrstd1" labelName="Betriebsstunden 1"/>
		<menuitem tableColumn="messdaten.btrstd2" labelName="Betriebsstunden 2"/>
	</submenu>
	<separator/>
	<submenu labelName="Spannung(Volt)">
		<menuitem tableColumn="messdaten.spann1" labelName="Spannung 1"/>
		<menuitem tableColumn="messdaten.spann2" labelName="Spannung 2"/>
		<menuitem tableColumn="messdaten.spann3" labelName="Spannung 3"/>
	</submenu>
	<separator/>
	<submenu labelName="Strom(Ampere)">
		<menuitem tableColumn="messdaten.strom1" labelName="Strom 1"/>
		<menuitem tableColumn="messdaten.strom2" labelName="Strom 2"/>
		<menuitem tableColumn="messdaten.strom3" labelName="Strom 3"/>
	</submenu>
	<separator/>
	<submenu labelName="Blindenergie(var)">
		<menuitem tableColumn="messdaten.zaehler_blindenergie_gen_0" labelName="Zähler Generator Blindenergie 0"/>
		<menuitem tableColumn="messdaten.zaehler_blindenergie_gen_1" labelName="Zähler Generator Blindenergie 1"/>
		<menuitem tableColumn="messdaten.zaehler_blindenergie_gen_2" labelName="Zähler Generator Blindenergie 2"/>
		<menuitem tableColumn="messdaten.zaehler_blindenergie_prod" labelName="Zähler Generator Produktion"/>
	</submenu>
	<separator/>
	<menuitem tableColumn="messdaten.cosph" labelName="Cosinus Phi"/>
	<menuitem tableColumn="messdaten.gen_frequenz" labelName="Frequenz(Hz)"/>
</menu>