zurück zur Homepage

MiniPanelMaker

Download von MiniPanelMaker

MiniPanelMaker ist ein weiteres SNH-Programm ("sleepless-night-hack"), das dem Java-Swing-Programmierer helfen soll, in möglichst kurzer Zeit Oberflächen einfacherer Natur zu entwickeln. Das Programm ist selbst ebenfalls in Java entwickelt und als Standalone-JAR-Applikation verfügbar.

Wichtige Hinweise

Wie für jedes andere meiner Programme gilt auch für dieses: Die Nutzung erfolgt auf eigene Gefahr, ich hafte in keinster Weise für direkten oder indirekten durch dieses Programm erfolgten Schaden! Dennoch verbürge ich mich dafür, dass das Programm keinen absichtlich schadhaften Code enthält. Da das Programm jedoch innerhalb kurzer Zeit und ohne ausreichende Test-Phase entwickelt wurde, kann es durchaus noch etliche Fehler aufweisen. Für Hinweise hierauf bin ich wie immer dankbar!

Das Programm ist OpenSource und Freeware, außerdem komplett in Java geschrieben. Der Quelltext liegt in der JAR-Datei zusammen mit dem ausführbaren Programm. Wer das Programm nutzen möchte, muss also Java installiert haben. Wer sich den Quelltext anschauen möchte, kann die JAR-Datei entpacken. Der Quelltext liegt zwar offen, gehört jedoch mir. Wer ihn für eigene Zwecke nutzen und/oder verändern möchte, der möge bitte meine Erlaubnis einholen. Ich erteile sie gerne, möchte jedoch vorher gerne wissen, wer den Code zu welchem Zweck verwendet. Für die Nutzung des Programmes ist keine eigene Erlaubnis erforderlich, auch darf es beliebig weiter gegeben werden.

Entwickelt wurde das Programm unter WindowsXP, es sollte jedoch auch unter anderen Betriebssystemen laufen. Über entsprechende Hinweise wäre ich dankbar!

Intention

Relativ häufig stehe ich vor dem Problem, dass ich ein winziges Programm "mal eben" schreiben möchte, um eine wie auch immer gearteten Aufgabe zu lösen. Häufig benötige ich ein solches Programm auch wirklich nur ein Mal, manchmal jedoch entstehen hierdurch Programme, die es Wert sind, häufiger genutzt zu werden. Meist starte ich solche Programme jedoch direkt aus der Entwicklungsumgebung heraus und gebe alle Parameter "fest verdrahtet" mit, so dass eine weitere Nutzung schwer fällt. Da dies fast immer schlicht daran liegt, dass ich einem solchen Moment zu faul bin, eine GUI zu entwickeln, ist die Wahrscheinlichkeit sehr hoch, dass diese Programme dennoch in der Versenkung (auf einem ungenutzten Teil der Festplatte) verschwinden.

Natürlich wäre ein GUI-Designer genau das richtige, doch diese Programme sind häufig überladen. Schließlich benötige ich in der Regel nur eine Hand voll Komponenten, ein paar Listener und alles wäre in bester Ordnung.

Aus diesem Grund schrieb ich den MiniPanelMaker, wobei die Betonung tatsächlich auf Mini liegen muss. Diese Programm bietet die Möglichkeit, einfache Oberflächen in wirklich kurzer (!) Zeit zu entwickeln und eventuelle vorher erzeugte Programmlogik (also den eigentlichen Kern des gerade geschriebenen Programmes) darin einzubinden.

Funktionsweise

Die Vorgehensweise ist denkbar einfach: Man beschreibt die gewünschte Oberfläche in einer Textform ("GUI-Text"), lässt sich das ganze anzeigen, bessert es aus und korrigiert so lange, bis es der gewünschten Oberfläche entspricht. Anschließend kann man sich die erzeugte Klasse (die als Datei erzeugt wurde) nehmen und anpassen.

Der folgende Screenshot zeigt die Programmoberfläche. Man gibt einen Methoden- und einen Klassennamen an, wobei der Sourcecode automatisch in die Datei "[klassenname].java" geschrieben wird.

Erstes Beispiel

Im Folgenden zeige ich ein kurzes Beispiel für eine generierte Oberfläche. Zunächst wird der GUI-Text angedruckt, anschließend der dazugehörige Screenshot und schließlich der hierdurch erzeugte Quellcode.

Klasse: Beispielklasse1
Methode: beispiel1

panel.border {
 center:
  button<beenden>("Exit")
 north:
  label("Drücke den Button zum Beenden des Programmes")
}

import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.*;
import javax.swing.event.*;

/**
 * MPM-Original-Source:
 *
 *     panel.border {
 *      center:
 *       button<beenden>("Exit")
 *      north:
 *       label("Drücke den Button zum Beenden des Programmes")
 *     }
 *
 @author MiniPanelMaker, (w) by Christian Packenius.
 */
public class Beispielklasse1 {
  /**
   * Start- und Testmethode.
   @param argv Ungenutzte Kommandozeilenparameter.
   */
  public static void main(String[] argv) {
    new Beispielklasse1();
  }

  /**
   * Konstruktor.
   */
  public Beispielklasse1() {
    JFrame frame = new JFrame("Test-Klasse, (w) by MiniPanelMaker");
    frame.setSize(300200);
    frame.getContentPane().setLayout(new BorderLayout());
    frame.getContentPane().add(beispiel1(), BorderLayout.CENTER);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }

  /**
   * Erzeugen des Panels und aller darin liegenden Komponenten.
   @return JPanel-Objekt mit allen Komponenten.
   */
  public JPanel beispiel1() {
    // Button.
    JButton beenden = new JButton();
    beenden.setText("Exit");
    beenden.addActionListener(new BeendenActionListener());

    // Label mit vorgegebenem Text "Drücke den Button zum Beenden des Programmes".
    JLabel label2 = new JLabel("Drücke den Button zum Beenden des Programmes");

    // Panel mit BorderLayout.
    JPanel panel1 = new JPanel();
    panel1.setLayout(new BorderLayout());
    panel1.add(beenden, BorderLayout.CENTER);
    panel1.add(label2, BorderLayout.NORTH);

    return panel1;
  }
}

/**
 * ActionListener für "beenden".
 */
class BeendenActionListener implements ActionListener {
  /**
   * Der Benutzer hat eine Aktion ausgelöst.
   @param e Der Event zur Aktion.
   */
  public void actionPerformed(ActionEvent e) {
    // TODO - Noch Event bearbeiten.
  }
}

Das schaut ja erstmal ganz ordentlich aus, fast wie ein richtiger Sourcecode-Generator. Um aber auf dem Teppich zu bleiben: Das Programm eignet sich tatsächlich nur für wirklich kleine und sehr einfache Oberflächen.

Es werden bisher die folgenden Swing-Komponenten unterstützt:

  • JPanel ("panel")
  • JSplitPane ("split")
  • JButton ("button")
  • JLabel ("label")
  • JTextField ("text")
  • JTextArea ("textarea")
  • JPasswordField ("password")
  • JCheckBox ("check")
  • JList ("list")
  • JComboBox ("combo")
  • JSlider ("slider")
  • JTree ("tree")

Diese können größtenteils auch schon mit Inhalten gefüllt werden. Die JPanel-Objekte können mit den folgenden LayoutManagern vorbelegt und gefüllt werden, wobei jedoch nicht alle Funktionalitäten unterstützt werden:

  • BorderLayout ("border", Default)
  • FlowLayout ("flow")
  • GridBagLayout ("gridbag")

Für die meisten kleinen Oberflächen reicht dies vollkommen aus.

Zwischendurch wie immer mein Hinweis: Sollte jemand etwas vermissen, kann ich auf Anfrage gerne weitere Komponenten und/oder LayoutManager einbinden und unterstützen. Fragen kostet nichts!

Doch zurück zum Beispiel, das ich nun kurz erläutern möchte, um die Arbeitsweise des Programmes klar zu machen:

panel.border {
 center:
  button<beenden>("Exit")
 north:
  label("Drücke den Button zum Beenden des Programmes")
}

Zunächst einmal wurde hier mit dem obigen GUI-Text ein panel erzeugt, dessen Inhalte mit Hilfe des BorderLayouts angezeigt werden sollen. In der Mitte des Panels (center:) wird ein einzelner button dargestellt, auf dem der Text Exit angezeigt wird und der im Sourcecode den (Variablen-) Namen beenden erhalten soll. Oben im Panel (north:) wird ein einzelnes label angezeigt, das den Text Drücke den Button zum Beenden des Programmes darstellen soll.

Dieses Beispiel soll vor allem verdeutlichen, wie man sich mit sehr wenig Aufwand (der im Eintippen des obigen kurzes GUI-Textes besteht) das Tippen von einer Menge Sourcecode (siehe obiger Quelltext) ersparen kann.

LayoutManager

Das Programm interpretiert den vorgegebenen GUI-Text (der, um mal ein Buzz-Wort zu verwenden, natürlich in einer eigenen DSL geschrieben wird), indem er eine einzelne Swing-Komponente erzeugt. Das liest sich jetzt seltsam, aber um es klarer zu sagen: Alles, was sich "hinter" der ersten Swing-Komponente im GUI-Text befindet, wird ignoriert! Einfach mal versuchen: Den obigen Text (beginnend mit panel.border [...]) kopieren und irgend etwas Beliebiges dahinter schreiben. Dies wird nicht beachtet. "Aber da steht doch mehr als nur das Panel, oder?..." - Ja! Aber alles andere ist dem Panel untergeordnet und gehört daher dazu.

Wie man sieht, kann man hinter einem Panel getrennt mit einem Punkt direkt das Layout angeben. Hier steht .border, das für das BorderLayout steht. Da dies bei allen Paneln immer vorgegeben ist, kann man es auch weg lassen.

Bei Paneln, also auch bei JSplitPane ("split"), werden die weiteren Inhalte in geschweiften Klammern angegeben. Dass bei obigem Beispiel nach der geschweiften Klammer-Auf ein Zeilenwechsel erfolgt, dient nur der Optik. Zeilenwechsel, Tabulatoren und Spaces werden als WhiteSpace-Zeichen interpretiert und somit ignoriert.

Je nach Layout wird das Innere eines Panels verschieden interpretiert. Beim BorderLayout werden Einzelangaben zur Richtung ("north", "south", "east", "west" und/oder "center") gefolgt von einer einzelnen Komponente angegeben. Wie zu sehen ist, müssen nicht alle Richtungen angegeben werden, außerdem ist die Reihenfolge der Richtungsangaben beliebig.

Beim GridBagLayout muss man hinter dem Layoutnamen in runden Klammern angeben, wie viele Felder das Layout enthalten soll (beispielsweise erzeugt panel.gridbag(2*1) zwei Spalten und eine Zeile) und gibt dann einfach in den geschweiften Klammern alle im GridBag liegenden Komponenten an. Bei diesen kann man dann auch noch zusätzlich angeben, wie viele Felder des GridBags sie verwenden sollen: 3:button erzeugt einen drei Felder breiten Button, bei 3*2:button ist der Button sechs Felder groß (drei Felder breit und zwei Felder hoch).

Beim FlowLayout ("flow") kann man in runden Klammern angeben, wie die Komponenten ausgerichtet werden sollen ("left", "right" oder "center") und schreibt in die geschweiften Klammern dann nur noch die Komponenten. Beispiel: panel.flow(center){label text button}

Referenz

Hier noch eine kurze Auflistung aller vom Programm unterstützten GUI-Elemente und ihrer Attribute; die kursiven Einträge müssen mit entsprechendem Inhalt gefüllt werden, eckige Klammern stehen für wahlfreie Attribute:

panel[.border]  { [center : component_1] [north : component_2] [south : component_3] [east : component_4] [west : component_5] }
panel.flow [(left | center | right)] { [component_1 component_2 [...]] }
panel.gridbag (width * height) { [[width[*height] : ] component_1 [width[*height] : ] component_2 [...]] }
split [(horizontal | vertical)] { component_1 component_2 }

label [("text")]
check [("text")]
list [("text1" "text2" [...])]
combo [("text1" "text2" [...])]
button [("text")]
text [(["text"] [columns])]
password [(["text"] [columns])]
textarea [(["text"] [columns])]
slider [(minimum - maximum [: startValue])]
tree [(root (sub-node-1 (sub-node-1-a sub-node-1-b [...]) sub-node-2 [...]))]

Namen und Listener

Im obigen Beispiel kann man recht gut sehen, wie im erzeugten Quellcode Variablennamen vergeben werden: Der Button wurde von uns durch die Angabe von <beenden> schon direkt mit einem Namen versehen. Im Gegensatz dazu erhielten das Label und das Panel automatisch erzeugte Namen, an denen man den Typ der Komponente erkennen kann und der weiterhin eine laufende Nummer erhielt.

Weiterhin werden auch Listener erzeugt. Diese werden als benannte Klasse eingerichtet, so dass man sie auf Wunsch auch einfach auslagern kann. Allerdings erhalten nicht automatisch alle Komponenten auch Listener. Nur für solche Komponenten, bei denen der Name explizit angegeben wurde und bei denen es auch sinnvoll ist, erhalten auch entsprechende Listener. Diese werden direkt per addXYZListener() registriert und die entsprechende Klasse eingerichtet.

Man kann also allen Komponenten durch spitze Klammern hintern der Typangabe Namen geben, es werden jedoch nur für folgende Komponenten dann auch die angegebenen Listener eingerichtet:

ActionListener (JButton, JCheckBox, JComboBox)
DocumentListener (JTextField, JTextArea, JPasswordField)
ListSelectionListener (JList)
ChangeListener (JSlider)
TreeSelectionListener (JTree)

Weitere Besonderheiten

Strings werden wie in den meisten Sprachen in doppelten Anführungsstrichen angegeben. Allerdings gibt es hier keine Escape-Zeichen. Man kann also weder Zeilenwechsel noch doppelte Anführungsstriche in Strings einfügen.

Es gibt zwei Methoden, Bemerkungen in GUI-Text einzufügen: Einmal kann man hinter dem eigentlichen GUI-Text beliebigen Text einfügen, der vom Generator ignoriert wird. Außerdem kann man zu Beginn einer Zeile das Zeichen # schreiben; diese Zeile wird dann ebenfalls ignoriert.

Weitere Beispiele

Im Folgenden stehen noch ein paar Beispiele mit Screenshot und GUI-Text, allen voran der GUI-Text zum MiniPanelMaker selbst.

panel.border {
 center: textarea
 north:  panel.border {
  center: panel.gridbag(1*2) {text text}
  west:   panel.gridbag(1*2) {label("Klasse:  ") label("Methode:  ")}
 }
 south:
  label
}
panel.border {
 north:
  label("Beispiel für FlowLayout")
 center:
  panel.flow(center) {
   button("abc") button("def") button("ghi") 
   button("jkl") button("mno") button("pqr") 
   button("stu") combo("a" "b" "c" "d" "e" "f")
  }
}
panel {
 north: label("north")
 south: label("south")
 east: label("east")
 west: label("west")
 center: label("center")
}
panel {
 north: button("north")
 south: button("south")
 east: button("east")
 west: button("west")
 center: button("center")
}
panel {
 west:
  tree("root" 
   ("eins" 
    "zwei" ("mitte-1") 
    "drei"))
 center:
  textarea("In der Mitte...")
}
panel.gridbag(2*1) {
 split {
  label("links")
  button("rechts")
 }
 split (vertical) {
  label("oben")
  button("unten")
 }
}
panel.gridbag(4*4) {
 1*4:button("links") 2:button("unten") 1*4:button("rechts")
 2*2:button("Mittelteil")
 2:button("oben")
}

Abspann

Nochmals der Hinweis: Sollte es Probleme oder Änderungswünsche geben, bin ich für alles offen und helfe gerne, insofern es meine Zeit zulässt!