SR-JRC | ein Framework für Java-Richclient-Anwendungen |
| eine ladbare Anwendung erstellen Der Einstieg in die GUI-Anwendung ist SRStarter, welcher zum Funktionsumfang von SRJRCFrames gehört. Es muss also "nur" der ladbare Teil der Anwendung erstellt werden. Für die Anwendungsentwicklung bedeutet dies, dass man kein eigenes Toplevel-Fenster erstellt, sondern das verwendet, was der Anwendungsrahmen SRStarter bereitstellt. Im Sinne von MVC entspricht die Anwendung dem "C" also dem Kontroller. Das Hauptfenster der Anwendung ist vom Typ Für die Zusammenarbeit mit dem Anwendungsrahmen stellt das Framework die Klasse public class BeispielApp extends AbstractApplication<BeispielCfg> { } Die Konfiguration wird im Kontext angelegt (siehe Konfiguration) und der Anwendungsrahmen SRStarter überschreibt die Vorgaben aus dem Kontext mit den aktuellen Benutzerdaten. Dies geschieht natürlich vor der Übergabe der Instanz an die Anwendungsklasse. Zutaten für eine Minimalanwendung:
Aber jetzt etwas ausführlicher ... Um der Gesamtanwendung ein einheitliches Gesicht zu geben, wird weder das Menü, noch die Toolbar über private enum Command { FILE_NEW, SEP_FILE, FILE_OPEN, EDIT_COPY, EDIT_RELEASE, SEP_EDIT, EDIT_DELETE, VIEW_REFRESH } Wie die Enum-Einträge vermuten lassen, wird der Text ausgewertet. Dies erfolgt durch den Der Anwendungsrahmen SRStarter mischt einige Menüeinträge selbstständig dazu. Hierzu gehören das Beenden der Anwendung, das Umschalten zu einer anderen geladenen Anwendung, ein gemeinsamer Konfigurationsdialog und natürlich die Hilfeseiten. Die Funktionen, die von einem Menüeintrag ausgeführt werden können müssen keine besonderen Voraussetzungen erfüllen, d.h. es können alle Methoden verwendet werden. Um durch die Auswahl eines Menüeintrages eine Funktion ausführen zu können, muss die Funktion mit dem Menüeintrag verheiratet werden. Hierzu ist u.a. der class BeispielActionHandler extends AbstractActionHandler implements ApplicationActionHandler { public BeispielActionHandler(String name) { super(name); } @Override public void init() { setupAction(getName(), Command.FILE_NEW, new AbstractActionCallback() { @Override public void actionPerformed(ActionEvent ae) { doCreateSample(ae); } }, KeyEvent.VK_N , AccessMode.APP_READ); ... } public Enum Der Konstruktor hat einen Namen-Parameter, sodass der In der Funktion Die Funktionen Um auch Kontextmenüs unterstützen zu können, gibt es eine Variante von init, die das Kontextobjekt als Parameter erhält: @Override public void init(Object contextObj) { setupAction(getName(), Command.FILE_OPEN, new AbstractActionContextCallback(contextObj) { @Override public void actionPerformed(ActionEvent ae) { doEditSample(new ActionContextEvent(ae, getContext())); } }, KeyEvent.VK_O); ... } Für diesen Fall gibt es auch eine erweiterte callback-Klasse public BeispielApp() { super(BeispielApp.class.getSimpleName()); setActionHandler(new BeispielActionHandler(getName())); } Eine grafische Anwendung ohne sichtbaren Inhalt ist wenig sinnvoll. Also brauchen wir noch etwas Fleisch in der Suppe. Für eine Anwendung mit einer übersicht als Standardansicht könnte dies so aussehen: @Override protected JComponent createPane() { if (content == null) { view = new AddressTableView(getInitialData(), EventSelectionModel.SINGLE_SELECTION, null); view.setSelectionChangedExecutor(new AbstractAction() { private static final long serialVersionUID = 713L; public void actionPerformed(ActionEvent e) { selectionChanged(e); } }); view.setPopDoubleLeftExecutor(new AbstractAction() { private static final long serialVersionUID = 713L; public void actionPerformed(ActionEvent e) { popupDoubleLeft(e); } }); view.setPopSingleRightExecutor(new AbstractAction() { private static final long serialVersionUID = 713L; public void actionPerformed(ActionEvent e) { popupSingleRight(e); } }); content = new ApplicationPage(getName(), view.getView()); } return content; } Wie man sehen kann, verwendet die Anwendung eine eigene View-Klasse, was dem "V" von MVC entspricht. Damit wäre unsere MVC-Anwendung komplett. Die Klasse Die Statusbar ist für einfache Meldungen zuständig, die keine Benutzeraktion erfordern. Die Statusbar wird unterhalb des Anwendungsfensters angezeigt und enthält im einfachsten Falle nur den Meldungsbereich. Der Meldungsbereich wird für alle Statusbar-Instanzen synchronisiert, d.h. eine Statusmeldung wird von allen Anwendungsfenstern angezeigt. Im einfachsten Falle erfordert eine Statusbar diese Deklaration: public class BeispielStatusBar extends AbstractStatusBar { private static final long serialVersionUID = 1L; @Override protected void checkExtends() {} @Override protected void updateExtends() {} } Bei SRJRCFrames gehört die Kommunikation zwischen den Anwendungen zum Konzept. Dazu gibt es die Möglichkeit, auf Nachrichten von anderen Anwendungen zu reagieren. Wer sich nicht für die Belange anderer interessiert, kann hier einfach eine leere Funktion verwenden: @Override public void onApplicationEvent(ApplicationEvent arg0) { // do nothing } Das Gegenstück dazu ist das Versenden von Nachrichten. Dazu wird jetzt ein Dienst vom Anwendungsrahmen angefordert: if (aePublisher == null) { aePublisher = (ApplicationEventPublisher) ApplicationServiceProvider.getService(ApplicationEventPublisher.class); } Wenn wir den Dienst erhalten haben, können wir die (möglichen) anderen Anwendungen von unserer Existenz unterrichten: aePublisher.publishEvent(new SampleAppStartedEvent("hello world")); Wird im Hauptmenü der Menüeintrag "Optionen" aktiviert, fragt der Anwendungsrahmen SRStarter jede geladene Anwendung nach einer Seite für den Dialog der Einstellungen. Der Dialog selbst, wie einige Standardseiten stammen vom Anwendungsrahmen selbst. Die Darstellung ähnelt einem Notebook, d.h. es kann zwischen den Seiten frei umgeschaltet werden. Die Funktion, mit der die Anwendung eine solche Seite zur Verfügung stellen kann, ist: public JComponent getConfigPage() { if (cfgEdit == null) cfgEdit = new ConfigEditor(getAppConfig()); return cfgEdit; } Wer keine Benutzereinstellungen zur Änderung anbieten will, kann bei dieser Methode einfach class ConfigEditor extends AbstractEditor<BeispielCfg> { private static final long serialVersionUID = 1L; public ConfigEditor(BeispielCfg instance) { super(instance, false); } @Override protected JComponent buildPanel() { if (msgSource == null) msgSource = ApplicationServiceProvider.getService(MessageSource.class); FormLayout layout = new FormLayout("left:max(100dlu;pref), 3dlu, 100dlu:grow"); DefaultFormBuilder builder = new DefaultFormBuilder(layout); String prefix = BeispielCfg.class.getSimpleName() + "."; PresentationModel In der Funktion Die erstellte Beispielanwendung sieht jetzt komplett so aus: public class BeispielApp extends AbstractApplication<BeispielCfg> { private enum Command { FILE_NEW, SEP_FILE, FILE_OPEN, EDIT_COPY, EDIT_RELEASE, SEP_EDIT, EDIT_DELETE, VIEW_REFRESH } class BeispielActionHandler extends AbstractActionHandler implements ApplicationActionHandler { public BeispielActionHandler(String name) { super(name); } @Override public void init() { setupAction(getName(), Command.FILE_NEW, new AbstractActionCallback() { @Override public void actionPerformed(ActionEvent ae) { doCreateSample(ae); } }, KeyEvent.VK_N , AccessMode.APP_READ); ... } @Override public void init(Object contextObj) { setupAction(getName(), Command.FILE_OPEN, new AbstractActionContextCallback(contextObj) { @Override public void actionPerformed(ActionEvent ae) { doEditSample(new ActionContextEvent(ae, getContext())); } }, KeyEvent.VK_O); ... } public Enum |