![]() |
|
|
Themen-Optionen |
|
|
Nach oben #1 |
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
Das PgsAction-Framework entstand als Nebenprodukt der SimpleEdit-IDE und ist auf einfache Benutzung, Erweiterbarkeit und Flexibilität optimiert.
Es erweitert die Swing Action-API um Kontext- und Statussensitivität und vereinfacht die Internationalisierung der Actions. Dabei ist es extrem klein (20kb) und einfach zu verwenden. Kommentare sind erwünscht. Download |
|
|
|
|
|
Nach oben #2 |
|
Erfahrener Benutzer
Registriert seit: 28.08.2004
Ort: konstanz am bodensee
Beiträge: 190
|
könntest du vieleicht ein kleines beispiel programm zur verfügung stellen.
habe gerade langweile (bin arbeiten) und wollte das mal ausprobieren, aber irgendwie weiß aber irgendwie nicht so genau wo und mit was ich anfangen soll... |
|
|
|
|
|
Nach oben #3 |
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
Theoretisch ne tolle Idee, aber praktisch bringts nicht viel, weil man bei nem kleinen Programm den Vorteil nicht sieht.
Viele Beispiele für Verwendung des Packages findest du in SimpleEdit (org.simpleedit.action.*-Packages + org.simpleedit.MainFrame) (Quellcode findest du hier). Mehr gibts aktuell nicht, hatte gehofft, die Doku wäre ausführlich genug. |
|
|
|
|
|
Nach oben #4 |
|
Erfahrener Benutzer
Registriert seit: 28.08.2004
Ort: konstanz am bodensee
Beiträge: 190
|
hm dann werd ich mich wenns ma wieder nichts zu tun gibt durch den source code des editors fummeln...
hatte mir das teil gestern schon runtergeladen aber nur n bischen mit gespielt aber nicht in den quellcode geschaut..... hierzu muss ich sagen, sieht ja wirklich sehr nice aus. und die startup time ist beeindruckend (für ein java programm...). ich kann mich erinnern das ding schonmal vor etwas mehr als einem halben jahr getestet zu habe, bezüglich der UI hat sich ja einiges getan. ein tip für die batch datei, wenn du den anfang der zeil "java" in "start javaw" umänderst verschwindet das commandozeilen fenster gleich wieder. wenn du es für debug zwecke noch haben willst kannst du "start java" verwenden so schließt sich das erste fenster gleich wieder und ein zweites öffnet sich in dem nur der java output angezeigt wird... |
|
|
|
|
|
Nach oben #5 |
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
Danke für den Tipp. Das ist echt hilfreich.
Gewollt war den Fenster nicht, nur ungekonnt. Ja, die GUI hat sich erheblich verändert, ist auch ne komplett andere Basis. Also, dass Prinzip bei PgsAction ist sehr simpel. Statt direkt AbstractAction zu erweitern, ist die Superklasse halt (meistens) AbstractSystemAction (in SimpleEdit ist es SystemAction, dass solltest du einfach ignorieren). Hier ein Beispiel: NewFileAction.java. Anhand des Beispiels lässt sich folgendes feststellen: Statt des "richtigen" Textes wird eine ID übergeben. Diese wird (standardmäßig) aus einem ResourceBundle mit dem Namen "Bundle" im gleichen Package, in der auch die Klasse ist, gelesen. In dem Beispiel müsste also eigentlich eine "org/simpleedit/action/file/Bundle.properties" existieren, die den Key "file.new" hat. Beispielwert wäre "&Neue Datei@control N". Das Zeichen direkt nach dem "&" wird als Mnemonic verwertet (das "&" wird entfernt). Das, was nach dem "@" steht, wird als Accelerator gesetzt (@see KeyStroke.getKeyStroke(String)). Ist also recht simpel alles. Prinzip ist bei PgsAction ist es, dass die Actions tatsächlich die Controller-Rolle übernehmen. Maximalen Nutzen erreichst du also, indem du in einer Action nicht einfach ne Methode einer anderen Klasse aufrufst, sondern schon ein bisschen hirnschmalz reinsteckst. Das verlinkte Beispiel ist dahingehend noch nichtmal optimal. Besseres Beispiel dafür könnte die OpenFTPConnectionAction.java sein. Nachdem das geklärt wurde, geht's dann weiter. Wenn du die Actions hast, brauchst du Menüs und Toolbars. Die generierst du dir in PgsAction nicht selbst, sondern du fügst sie einem ActionContainer hinzu (extends AbstractSystemAction, implements ListModel). Das könnte so aussehen: CodeMenuAction.java (ja, es ist tatsächlich so einfach). Dabei siehst du auch direkt eines der wichtigsten Merkmale: Actions sind Singletons (du kannst allerdings auch eine Instanz einer Action hinzufügen). Um nun an diesen Container zu kommen würdest du sowas schreiben: Code:
ActionContainer codeMenu = (ActionContainer)ActionManager.getDefaultInstance().get(CodeMenuAction.class); Code:
JMenu menu = codeMenu.createMenu(); Code:
codeMenu.add(MyAction.class); Weiter im Text... Jetzt mal ein Beispiel für eine "ContextAwareAction": Code:
public class OpenImageAction extends AbstractSystemAction implements ContextAwareAction, ListSelectionListener {
public OpenImageAction() {
super("openimage");
}
public void actionPerformed(ActionEvent e) {
JList list = (JList) e.getSource();
File file = (File) list.getSelectedValue();
try {
SimpleDemo.getInstance().getImagePanel().setImage(file);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
}
public void addContext(Object context, JComponent presentation) {
JList list = (JList) context; // "presentation" is just the JButton/JMenuItem whatever that gets an instance of this action
list.addListSelectionListener(this);
}
public void valueChanged(ListSelectionEvent e) {
JList list = (JList) e.getSource();
File file = ((File) list.getSelectedValue());
String name = null;
if(file != null) {
name = file.getName();
}
setEnabled(name != null && (name.endsWith("jpg") || name.endsWith("gif") || name.endsWith("png")));
}
}
addContext() kann manuell aufgerufen werden, oder du verwendest einfach die ContextSensitive*Provider als Parameter für die create*-Methode des ActionContainers, der die Action beinhaltet und gibst ihm den entsprechenden Context mit. *puh* Ok, eines noch. PgsAction kann auch mit JCheckBoxMenuItem und co umgehen. Dabei empfiehlt es sich, eine Oberklasse zu implementieren, die die entsprechende Gruppe verwaltet. Beispiel: TokenMarkerAction.java (statt SimpleAbstractStateAction würdest du allerdings AbstractStateAction schreiben). Die tatsächliche Implementierung ist dann ein Kinderspiel: TextTokenMarkerAction.java (als Beispiel für den vorselektierten Wert). Das ist alles, was man tun muss, um so ein Menü hinzubekommen, wie SimpleEdit es beim "Syntax"-Menü hat, und das ganze dann auch noch zu synchronisieren (SimpleEdit hat einmal das "Syntax"-Menü, es gibt aber auch noch nen entsprechenden Knopf, der das gleiche Menü anzeigt). Ok, ich hoffe das war jetzt irgendwie hilfreich. |
|
|
|
|
|
Nach oben #6 |
|
Erfahrener Benutzer
Registriert seit: 28.08.2004
Ort: konstanz am bodensee
Beiträge: 190
|
ahhh... man muss den leuten nur ein bischen honig ums maul schmieren und schon bekommt man den beispielcode
mach jetzt feierabend aber werd mir das montag oder am we wenn zeit bleibt mal anschauen... |
|
|
|
|
|
Nach oben #7 |
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
*g*
Das vereinfacht die Mühe, die das schreiben kostet, tatsächlich erheblich. Ich vergesse nur immer, dass andere meine APIs nicht kennen, folglich also die Beispiele nicht so einfach finden können. *g* |
|
|
|
|
|
Nach oben #8 |
|
Erfahrener Benutzer
Registriert seit: 28.08.2004
Ort: konstanz am bodensee
Beiträge: 190
|
soo hab mal ein paar minuten gefunden. das ganze macht einen guten eindruck... obwohl mir trotz deiner ausführlichen beschreibung nicht alles zu 100% klar geworden ist (scheint meistens so zu sein, wenn man den code nicht selber geschrieben hat)....
Ein ActionContainer erbt ja auch von der AbstractAction. Bei einer MenuBar würde dann ja z.B. ein ActionContainer für ein Menu Stehen, die in ihm hinzugefügten Actions sind die einzelnen MenuPunkte. Nun erwartete ich das beim öffnen des Menu's die actionPerformed methode des ActionsConteiners aufgerufen wird, was aber nicht der fall war. Hab ich was falsch gemach oder wird die actionPerformed Methode des ActionContainers anders/garnich verwendet? Was hat es mit den ActionGroups auf sich? Hab das nicht sinnvoll zum einsatz bringen können, aber das sollte doch irgendwie so funktionieren: Ich habe einen ActionContainer für eine JMenuBar, ihm kann ich mehrere ActionsGroups hinzufügen welche die einzelnen Menu's repräsentieren. Der ActionGroup kann ich dann für untermenu's weitere ActionsGroups hinzufügen oder für Menupunkte AbstractSystemActions. Vieleicht hab ich das auch falsch verstanden... Zu meckern gibts natürlich auch was, und zwar die Sprachbundels, auch wenn es der Standartweg ist finde ich es nicht gut die Bundels im dazugehörigen package aufzubewahren. Bei einem kleinen Framework oder ner Lib ist das noch ok. Aber bei einer größeren Applikation wird das unübersichtlich und bei installation/deinstallation von zusätzlichen Sprachpaketen müssen die dateien über die ganze Ordnerhirachie verteilt werden. Besser finde ich die Dateien in solch einer struktur zu sammeln Code:
lang
|-de
|- com.test.package1.properties
|- com.test.package2.properties
|-en
|- com.test.package1.properties
|- com.test.package2.properties
|-dk
|- com.test.package1.properties
|- com.test.package2.properties
es trägt auch gut zur übersichtlichkeit bei, die logik direkt in den Actions zu implementieren, da so alles was zu einer Aktion gehöhrt schön in einer Klasse gekapselt ist... (Siehe OpenFTPConnectionAction den Dialog zur eingabe der Verbindungsdaten als inner Klasse hällt). Als gegenbeispiel werde ich nun mal erklären wie ich das ganze in meinen Framework gelößt habe: - die Strukturen der ActionComponents werden in einer XML datei definiert - man kann gruppen in beliebiger tiefe bilden (untermenus) - jeder action kann ein titel, icon und ein actioncommand zugeordnet werden - Actions können über 2 verschiedene wegen realisiert werden 1. Im ActionManager wird eine von AbstractAction abgeleitete Klasse unter dem zugehörigen actioncommand registriert und aufgerufen 2. wenn man in der XML Datei dem command ein "CMD:" voranstellt wird das actions Command (ohne "CMD:") der CommandLine übergenen. In der CommandLine kann man nun entweder eine Klasse welche das Interface Command implementiert registrieren oder per annotation (@MethodCallCommandType(name="testCommand", descr="Test Command",numArgs=3)) eine statische methode einbinden. die xml dateien können dann im java programm wahlweise als MenuBar, PopupMenu, Toolbar oder l2fprod TaskPane über einen einfachen methodenaufruf zusammengebaut werden. das ganze hat den vorteil, das man die Commands zu debug/oder scripting zwecken auch über eine graphische console bzw script datei ausführen kann und man erst die struktur in der xml datei definiert und diese ohne die Actions überhaupt zu implementieren testen kann. auch ist es möglich schnell die actions zu ändern ohne den quellcode neu zu kompilieren. Code:
<group> <item name="test"> <action command="CMD:msg das ist ein test"> </item> </group> das action command in der xml datei ändern und das programm neustarten... beide methoden haben ihre vor und nachteil... letzendlich liegt es nur am geschmack des entwicklers welche man verwendet... puh, jetzt hab ich ja zu meinem kram fast mehr geschrieben als zu deinem kram |
|
|
|
|
|
Nach oben #9 | |||
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
Hi, danke für's Feedback.
ActionContainer erbt von AbstractAction, richtig. Es wird durch den ComponentProvider folgender Code zur Generierung eines Menüs erzeugt: Code:
new JMenu(theActionContainer); Über Sinn und Unsinn darf man streiten, aber das maximale, was ein Menü beim "draufklicken" machen könnte, wäre das Untermenü zu generieren ("on-demand", so zu sagen). Da weiß ich aber nicht, ob Swing das mitmacht. Du kannst einem ActionContainer übrigens auch einen anderen ActionContainer hinzufügen. Nur falls das nicht klar geworden ist. Dann bzgl. der ActionGroups. Es gibt ein Interface "StateAction" und Actions, die dieses Interface implementieren verfügen über eine "getGroup"-Methode. Die ActionGroup-Klasse ist mit der ButtonGroup-Klasse aus dem Standard-JDK vergleichbar, nur das sie mir ein paar mehr Möglichkeiten bietet. Alle Actions einer Gruppe müssen die selbe ("==") ActionGroup als Parameter dieser Methode zurückgeben. Das wird meist durch eine gemeinsame Oberklasse realisiert, die diese ActionGroup als statische Instanz besitzt und in der getGroup-Methode zurückgibt. Das gilt alles nur für "JRadioButton" und "JRadioButtonMenuItem". Für "JCheckbox" und "JCheckboxMenuItem" liefert "getGroup" den Wert "null". Du verwendest in jedem Fall aber noch "ganz normale" Actions, die StateAction implementieren. Bzgl. I18N: Ich hab mich als Standard an NetBeans orientiert, die das haargenau so machen. Und ich würde NetBeans nicht als kleines Projekt bezeichnen. Spielt aber auch keine Rolle, weil du das so machen kannst, wie du es haben möchtest. AbstractSystemAction besitzt ne statische Methode "setProvider(ActionResourceProvider)", die genau für diesen Fall existiert. Schau dir einfach mal das Interface und die Standard-Implementation an. Meistens reicht es, wenn du in getConfig "null" lieferst und in getString muss halt das ResourceBundle für das Action-Objekt gefunden und dann der entsprechende Text zurückgegeben werden. Allerdings frag ich mich da, ob du in deinem Beispiel nicht sowieso eine eigene ResourceBundle-Implementation vorliegen hast, in die du das Action-System integrieren könntest. Weil soweit ich weiß sucht ResourceBundle immer nach "Bundle_de_DE.properties", und nicht nach "/lang/de/DE/Bundle.properties". Beim "Standard" zu bleiben bringt aber z.B. den Vorteil, den Tool-Support verwenden zu können. Zugegeben, das funktioniert bei meinem Framework aktuell dank des ".name" am key-ende auch noch nicht, aber ich glaub das werd ich noch umändern... Sooo... jetzt zu deinem. Zitat:
XUL-Klon eskaliert. NetBeans macht das aber auch so - mag ich überhaupt nicht (ich denke einfach, dass meine Java-Version sehr einfach ist und das ganze etwas geordnerter hält - außerdem ist die Erweiterung etwas einfacher). Zitat:
(Deshalb am Anfang der Kommentar von mir bzgl. ActionContainer in ActionContainer einfügen) Ansonsten sehe ich da doch recht starke Konzeptions-Unterschiede. In meinem Konzept werden die Actions zuerst implementiert und die Struktur vernachlässigt, bzw. anderweitig festgehalten. Was man im Endeffekt bevorzugt ist natürlich wieder Geschmackssache. Wobei mich das auf die Idee bringt, dass ich mal versuchen könnte, etwas "ähnliches" zu integrieren. Also "Generierung von ActionContainern auf Basis einer Datei". Hmm... nach kurzem Nachdenken würde ich, denke ich, sowas hier recht gern haben: Code:
menu id="main" menu id="file" item id="open.file" action="com.pagosoft.demo.OpenFileAction" icon="icons/openfile.png" item id="close.file" action="com.pagosoft.demo.CloseFileAction" menu id="syntax" item id="syntax.php" action="org.simpleedit.actions.syntax.PHPTokenMarkerAction" group="syntax" item id="syntax.html" action="org.simpleedit.actions.syntax.HTMLTokenMarkerAction" group="syntax" menu id="help" item id="show.help" action="com.pagosoft.demo.ShowHelpAction" accel="F1" item ref="com.pagosoft.demo.SomeActionObject@id.of.action" erledigt werden soll. Wobei man meine Syntax oben vielleicht noch etwas anders machen könnte... ein bisschen mehr wie Lisp wäre schön... aber das wäre nur (unnötiger) Syntax-Sugar, denke ich. Ein Parser für das da oben ist schnell geschrieben, einen ActionContainer in sowas zu verwandeln auch. Hmm... API wäre in etwa so brauchbar: Code:
ActionFactory fac = ActionFactory.getInstance();
fac.parse(SimpleEdit.getResourceAsStream("core.paf")); // core.paf => beinhaltet code von oben
ActionContainer main = fac.get("main");
JMenuBar mb = main.createMenuBar();
Code:
ActionFactory.getInstance().parse("plugin.paf");
Lange Rede, kurzer Sinn: Mein Dateiformat da oben ist trotzdem noch ne Menge zu schreiben, mit XML wäre es noch mehr, außer man registriert die Actions in der Factory, was aber nur noch mehr Schreibarbeit ist. Speziell wo die IDE dir bei keinem der Formate wirklich helfen kann. Klar, du könntest dir Plugins dafür schreiben, aber so ganz viel Sinn macht das IMHO nicht. Das einzige Argument, wo ich dir voll und ganz zustimme, ist dieses hier: Zitat:
doch irgendwie einbauen möchte. |
|||
|
|
|
|
|
Nach oben #10 | |||
|
Erfahrener Benutzer
Registriert seit: 28.08.2004
Ort: konstanz am bodensee
Beiträge: 190
|
Zitat:
Zitat:
ich verwende die XML dateien nur bei menu's toolbars und taskpanes, der rest wird auch hardcodiert... der vorteil von xml gegenüber einen eigenen dateiformat ist das es halt standartisiert ist und jeder dem XML kein fremdwort ist sich auch relativ schnell in jede xml sprache einarbeiten kann. zur erklärung kann man noch eine DTD erzeugen, daraus lässt sich ganz gut erkennen welche elemente und attribute wo verwendet werden dürfen. Zitat:
alle aus einem bundel abgerufenen schlüssel werden wenn sie nicht existieren automatisch mit leerem inhalt hinzugefügt. wenn man die sprache erst hinterher definieren will ist das ganz nützlich, ich lass das prog einmal durchlaufen und hab schon (fast) alle schlüssel in der datei stehen, das erspart schreib/kopier arbeit... auch kann man variablen ein die strings einbinden. Code:
test.string1=Hier ein paar platzhalter: {1},{2} und {3}
Code:
LanguagePack lang = LanguagePack.get('app.core');
lang.getString('test.string1','bla1','bla2','bla3');
ausserdem werden alle <br>'s durch einen zeilenumbruch ersetzt, somit kann man mehrzeiligen text in einem schlüssel aufbewahren, da wenn man die zeilenumbrüche mit \n reinschreibt werden die zeilen auch in der datei umgebrochen und nicht mehr als ein schlüssel/weret paar erkannt LanguagePack beinhaltet einen PropertyManager, welcher die sprache in sich aufnimmt, wenn die sprache (zur laufzeit) gewechselt wird, werden alle angemeldeten language listeners benachrichtigt und können nun aus dem selben LanguagePack die Strings in der neuen sprache beziehen... wie hast du die internationalisierung in der gui gelößt? arbeitest du in den Klassen die sprache benötigen direkt mit den ResourceBundles oder hast du eine zwischenschicht, die teile der internationalisierung automatisiert? kann man die sprache zur laufzeit umschalten? |
|||
|
|
|
|
|
Nach oben #11 | ||
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
Du kannst auch sowas machen:
Code:
key = Text mit \
Zeilenumbruch
PgsAction verwendet direkt ResourceBundle. In SimpleEdit gibt es ein paar Hilfsfunktionen im Sinne von Code:
SimpleEdit.getString(SomeClass.class, "key", "arg1", "arg2", "argN"); Und wenn ich mich irgendwann dazu entschließen sollte, dass einzubauen, dann wird das nur nach Neustart greifen. Swing bietet keine besonders guten Möglichkeiten, sowas zu realisieren und ich denke nicht, dass ich das ändern möchte. Wenn ich es nämlich tun würde, dann wirklich gut und das beansprucht ne Menge arbeit. So ungefähr: Code:
LanguagePacks.setLocale(new Locale("de", "DE"));
Was anderes kommt mir nicht in die Tüte. Hmm... mit Annotations ließe sich das sogar vielleicht machen. Na ja. Muss ich mal ne Nacht drüber schlafen. Zitat:
Zitat:
Ich finde z.B. das Menü-Format von Blackbox/Fluxbox genauso einfach wie das von Openbox, nur dass das von den ersten beiden deutlich weniger Schreibarbeit bedeutet. Na ja, das Problem ist einfach, dass ich für ein Action-Framework schlecht ein eigenes Resource-Loading implementieren. Das würde zu weit gehen. |
||
|
|
|
|
|
Nach oben #12 | |
|
Erfahrener Benutzer
Registriert seit: 30.11.2005
Ort: Bottrop
Beiträge: 1.083
|
Man möge mir meine Faulheit verzeihen, aber noch ne Ankündigung pack ich heute nicht...
Zitat:
|
|
|
|
|
![]() |
| Lesezeichen |
| Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1) | |
| Themen-Optionen | |
|
|