Java ToolBar Buttons abhängig von Dokumentart an und abschalten / mit Funktionen belegen

PEASANT KING

Commander
Registriert
Okt. 2008
Beiträge
2.412
Hallo Leute,

ich bastel mal wieder an meiner eigens programmierten Swing Desktopapplikation herum.
Bis jetzt ist eine Kundenverwaltung für meine Mutter dabei rausgekommen mit Embedded Derby Anbindung und einem Embedded Browsermodul, welches später die Startseite des Programms sein soll, mit aktuellen News zum Programm und der Version usw.

Anbei hab ich ein paar Bilder angefügt.

Was ich nun gerne hätte ist, eine dynamische ToolBar, die die speziefischen Funktionen der einzelnen Dokumentarten bereit stellt. Heißt wenn ich im Kundenstamm bin soll ich oben auf speichern klicken können und dann wird der Datensatz gespeichert. So halb ist es auch implementiert, allerdings ist mein Problem z.B., das wenn ich die Buttons der Toolbar nicht deaktiviere ich auch wenn der Tab mit dem Kundenstamm geschlossen ist, ich immernoch Veränderungen am zuvor geöffneten Datensatz anstellen könnte. Was absolut nicht gut ist.
Ausserdem könnte es ja passieren das wenn ich im Kundenstamm zuvor war, was verändert habe, es dann gespeichert habe und danach den Artikelstamm öffnen würde, die Anwendung denke ich nicht mit bekommen würde das ich mich nun im Artikelstamm befinde und daher nun die Speicherfunktion des Artikelstamms genommen werden sollte.

Hier mal ein paar Bilder. Ich reiche auch gerne später Code nach, allerdings geht es mir erstmal voranging um eine Designtechnische Lösung in der Theorie.

Grüße DJ
 

Anhänge

  • startseite.jpg
    startseite.jpg
    82,1 KB · Aufrufe: 194
  • kundenübersicht.jpg
    kundenübersicht.jpg
    98,7 KB · Aufrufe: 166
  • kundendetail.jpg
    kundendetail.jpg
    94,3 KB · Aufrufe: 153
Mal eine andere Frage, welche "Look&Feel" Variante ist das, wenn du mit Swing arbeitest?
 
Windows 8 mit erweiterter JTabbedPane Variante, die ich selbst geschrieben habe. Also ist das native L&F damit es in jedem BS aussieht wie das System selber. Die Icons sind von Open Icon Library.

Code:
try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (UnsupportedLookAndFeelException |
                ClassNotFoundException |
                InstantiationException |
                IllegalAccessException ex) {
            Logger.getLogger(Controller.class.getName())
                    .log(Level.SEVERE, null, ex);
        }
 
DJ_We$t schrieb:
Windows 8 mit erweiterter JTabbedPane Variante, die ich selbst geschrieben habe.
Die Icons sind von Open Icon Library

Achso Win8, den Rahmen habe ich gar nicht erkannt^^

Vielen Dank DÜSSELDORFER :P
 
ToolBar Buttons abhängig von Dokumentart an und abschalten / mit Funktionen b...

Gern geschehen! Keiner ne Idee oder so ?
 
Zuletzt bearbeitet:
Hey,

also wenn ich's richtig verstehe möchtest du, dass dein Speicher-Button, je nachdem in welchem Tab (Startseite, Kundenverwaltung, Artikelstamm, ...) du dich befindest unterschiedliche Funktionalität besitzt? Also etwa einmal um neue Kunden zu speichern und einmal um neue Artikel zu speichern, oder so ähnlich.

In dem Fall kommt es doch nur darauf an, welcher Tab momentan aktiv ist.
Schau mal ob dir das hier evtl hilft:
http://docs.oracle.com/javase/7/docs/api/javax/swing/JTabbedPane.html#getSelectedComponent%28%29

Pseudo-Code für die Speichern-Funktion könnte dann u.U. so aussehen:

- Mit getSelectedComponent().getName() den Namen des gerade aktiven Tabs (bzw. der Component) abfragen
- innerhalb der Speichern-Methode dann mit if/else unterscheiden
- z.B. if(nameOfCurrentlyActiveTab.equals("Kundenverwaltung")) then [Code für diesen Fall] else if (nameOfCurrentlyActiveTab.equals("Artikelstamm")) then [anderer Code]
- ...

Gruß, Bob_
 
Zuletzt bearbeitet:
Genauso ist es gemeint @SilentBob_

Ah jaa so ähnlich hatte ich das schon, allerdings designtechnisch muss ich es wohl anders programmieren dann, denn zur Zeit befinden sich die einzelnen Speicherfunktionen in meinen jeweiligen Modulen, sprich Kundenstamm ist ein eigenes Modul an das ich eine global verfügbare Instanz der ToolBar mitgebe um dann mittels ActionListener auf Anwendereingaben zu reagieren.

Leider komm ich nicht wirklich voran, ich frage mittels
Code:
view.getJCloseTabbedPane().getSelectedComponent().getName();
den Namen ab, der komischer Weise immer null ist oder Form, was natürlich totaler Quatsch ist, denn die Komponenten haben ja eigene Titel.
 
Zuletzt bearbeitet:
Hm naja, kannst du dann nicht einfach trotzdem jeweils die Speicherfunktion pro Modul nach dem Muster ändern?
Also z.B. im Kundenstamm - wieder Pseudocode:
if(nameOfCurrentlyActiveTab.equals("Kundenverwaltung")) then [Code für diesen Fall] else {//do nothing}
Analog dann für den Artikelstamm etc.

Du könntest evtl. auch mit Vererbung arbeiten, aber da musst du selbst entscheiden ob das bei deiner Architektur vernünftig umsetzbar und sinnvoll ist.
Du könntest z.B. ein "Vater-Modul" erstellen, welches dann die Speicherfunktion - ähnlich meines ersten Beitrags - bereitstellt. Alle weiteren Module wie Kundenstamm, Artikelstamm... erben ja dann diese Methode und können sie verwenden. Die global verfügbare Instanz deiner ToolBar übergibst du dann halt auch geeignet ans "Vater-Modul".

Gruß, Bob_


Edit:
Zu deinem Fehler - benutzt du für deine Components auch mal die setName(String name) Methode um den Namen festzulegen?
 
Zuletzt bearbeitet:
In meiner JCloseTabbedPane gibts eine Methode:
Code:
    /**
     *
     * @param title
     * @param component
     */
    public void addCloseTab(String title, Component component) {
        add(title, component);
        setTabComponentAt(getTabCount() - 1, new JCloseTabbedPane.ButtonTabComponent(this));
        setSelectedIndex(getTabCount() - 1);
    }

Mittels dieser Methode können beliebig JPanels der TabbedPane hinzugefügt werden.

EDIT:

Das mit setName hat sich erledigt, ich habe den Panels noch einen Namen gegeben, ich dachte mit Title wäre das schon geschehen, weil ich dachte es wäre beides das gleiche, was nicht der Fall ist.

Jetzt habe ich nur noch ein Problem, das ich ein Index out of Bounds bekomme, wenn ich einen Tab schließe, versteh aber nicht warum. Es passiert nur wenn ich mit if bzw. switch case arbeite:
Code:
    private void setToolBarActions() {

        while (true) {
            String name = view.getjCloseTabbedPane().getSelectedComponent().getName();
            System.out.println(name);
            
            switch (name) {
                case "Kundenverwaltung":
                    toolBar.getjButton1().setEnabled(true);
                    toolBar.getjButton3().setEnabled(true);
                    toolBar.getjButton4().setEnabled(true);
                    break;
                case "Startseite":
                    toolBar.getjButton1().setEnabled(true);
                    toolBar.getjButton3().setEnabled(false);
                    toolBar.getjButton4().setEnabled(false);
                    break;
            }

        }
    }
 
Zuletzt bearbeitet:
Speicherst du deine Components irgendwo in einer Liste oder so?
Was genau macht denn die Methode getjCloseTabbedPane() ?

Vllt. musst du einen Tab bei Schließen eben an geeigneter Stelle wieder "entfernen".
 
Die Methode getJCloseTabbedPane() ist ein simpler Getter, der mit return JCloseTabbedPane; mit die Komponente JCloseTabbedPane zurück gibt. Es funktioniert ja auch, allerdings nur solange ich das System.out.println(); drin stehen lasse. Entferne ich dies bekomme ich nach dem Schließen des Tabs den OutOfBounds
 
Ok, also das mit dem System.out kann ja egtl. nur Zufall sein.
Ich tippe mal drauf, dass die Zeile drüber den Fehler verursacht, weil du auf einen Tab zugreifen willst der bereits geschlossen wurde.

Du kannst die Anweisung ja mal ein bisschen entzerren, damit du siehst an welcher Stelle genau die Exception geworfen wird:
Code:
JCloseTabbedPane j = view.getjCloseTabbedPane();
Component c = j.getSelectedComponent();
String name = c.getName();

Was genau passiert in deinem Programm beim Schließen eines Tabs? Ist der dann nur solange unsichtbar bis man ihn wieder öffnet, oder wird der komplett deaktiviert bzw. gelöscht?


Edit:
Du könntest natürlich auch etwas einfacher vorgehen. Allerdings wäre die Variante jetzt natürlich nicht so schön wie das Deaktivieren von Buttons etc.
Du könntest auf das Deaktivieren der Buttons z.B. komplett verzichten. Heißt unabhängig vom gerade geöffneten Tab, zeigt deine ToolBar immer alle Buttons an. Erst wenn man jetzt auf einen Button drückt, setzt die Programmlogik ein und differenziert welcher Tab gerade aktiv ist. Dann müsstest du nicht permanent in einer While-Schleife überprüfen welcher Tab gerade aktiv ist, sondern machst das "nur" bzw. erst im Listener des Buttons...
 
Zuletzt bearbeitet:
Code:
            @Override
            public void actionPerformed(ActionEvent e) {
                int i = JCloseTabbedPane.ButtonTabComponent.this.pane.indexOfTabComponent(JCloseTabbedPane.ButtonTabComponent.this);
                if (i != -1) {
                    JCloseTabbedPane.ButtonTabComponent.this.pane.remove(i);
                }
            }

Das Panel wird von der TabbedPane entfernt, die Instanz des Panels selber ist allersdings noch vorhanden.
Leider weiß ich nicht wie ich eine Instanz zerstöre, denn eigentlich macht das doch der Garbage Collector für mich.

Da die Instanz aber bestehen bleiben soll und nicht jedes Mal neu geöffnet werden soll, muss ich es so bewerkstelligen.
Weil sonst könnte ich unendlich Kundenverwaltungsinstanzen auf der Pane adden, was ja Mist ist.
 
Teste doch mal den Vorschlag mit dem "Code-Entzerren" bitte.
Dann sollten wir wenigstens entwas genauer wissen wann und wo der Fehler auftritt.

Edit:
Schau dir mal hier die Antwort an: http://stackoverflow.com/questions/15312252/jtabbedpane-arrayindexoutofboundsexception
Deine Remove-Methode arbeitet ja auch über einen Index. Vllt. liegt da der Fehler.
Arbeitet dein simpler Getter getJCloseTabbedPane() zufällig auch über den Index?
 
Zuletzt bearbeitet:
Die Exception tritt bei getSelectedComponent auf, was für mich auch logisch ist, denn wenn ich das Panel schließe gibt es die selectedComponent ja nicht mehr, also das geschlossene Panel ist ja nicht mehr selectiert.
 
Zuletzt bearbeitet:
Logisch ist es für mich nur so halb^^
getSelectedComponent() sollte ja egtl. entweder den aktiven Tab oder eben null zurückgeben. Ein Nullpointer würd für mich mehr Sinn ergeben irgendwie.
IndexOutOfBounds deutet ja eben an, dass auf einen nicht (mehr) vorhandenen Index zugegriffen wird.
Die einzigen Passagen in deinem Code (den du bisher zur Verfügung gestellt hast) die mit einem Index arbeiten, sind deine Remove-Methode und ggf. noch der Getter (?), wobei das bei dem glaube ich eher nicht der Fall ist.

Es ist natürlich auch die Frage was genau passiert, wenn man einen Tab schließt.
Für mich würde Sinn ergeben, dass dann entweder ein anderer automatisch der neue aktive Tab wird, oder eben vorerst keiner aktiv ist, aber dann sollte es egtl. einen Nullpointer geben...
Hab aber keine Ahnung, wie Java das umsetzt. Kannst du aber sicher an deinem Programm leicht nachvollziehen.

Du kannst ja mal etwas in deiner Remove-Methode hinzufügen wie: setSelectedComponent(TabDerStartseite).
Dann wird automatisch die Startseite (oder vergleichbar) immer als aktiv gesetzt, sobald man einen der anderen Tabs schließt und somit sollte immer mindestens ein aktiver Tab vorhanden sein. (Es sei denn du schließt auch mal den Startseiten-Tab (k.A. ob das gewünscht/erlaubt etc. ist bei dir). Dann könntest du halt einen beliebigen anderen, noch vorhanden Tab als aktiv setzen. Sollte auch der Fall eintreten können, dass nach dem Schließen gar kein Tab mehr vorhanden ist, so müsstest du halt noch eine Abfrage an geeigneter Stelle einfügen, ob überhaupt noch irgendwelche Components vorhanden sind - hierzu hilft evtl. http://docs.oracle.com/javase/7/docs/api/java/awt/Container.html#getComponentCount%28%29)
 
Zuletzt bearbeitet:
Wenn ich den Kunden Tab schließe switcht die Anwendung direkt auf den Startseite Tab. Somit sollte der Startseite Tab der aktive dann sein.
Wenn ich das println(); ausführe macht die Anwendung auch genau das was ich will in meiner Methode zum Abfragen des aktiven Tabs.
Mir werden auch die Namen des jeweils aktiven Tabs auf Konsole ausgegeben.

In der Getter Methode passiert keine Indexierung, warum auch ? Die Getter Methode liefert mir ja schließlich nur eine Instanz der TabbedPane.
Code:
    public JCloseTabbedPane getjCloseTabbedPane() {
        return closeTabbedPane;
    }

Und mittels
Code:
pane.addCloseTab(title, panel);

Wird ein Tab der TabbedPane hinzugefügt.

Removed wird das Tab ja dann über den Button im Tab mit dem Code
Code:
            @Override
            public void actionPerformed(ActionEvent e) {
                int i = JCloseTabbedPane.ButtonTabComponent.this.pane.indexOfTabComponent(JCloseTabbedPane.ButtonTabComponent.this);
                if (i != -1) {
                    JCloseTabbedPane.ButtonTabComponent.this.pane.remove(i);
                }
            }
 
Zuletzt bearbeitet:
Ok, ich hab mir mal hier http://developer.classpath.org/doc/javax/swing/JTabbedPane-source.html den Sourcecode zu JTabbedPane angeschaut und getSelectedComponent() arbeitet eben auch über den Index.
Vermutlich tritt deswegen dann der Fehler auf, weil deine While-Schleife ja permanent läuft...

Catch doch mal die Exception und lass dir im Catch-Block über einen counter ausgeben wie oft die Exception schlussendlich fliegt. Wenn das immer nur einmal passiert, wenn man einen Tab schließt, und keine unerwünschten Folgen für's Programm nach sich zieht, ist es wohl zu verschmerzen bei Benutzung von while(true).

Achso und wie gesagt, der Teil mit dem println() muss ja egtl. zufällig auftreten; wär ja noch schöner sonst.
Bin mir recht sicher, wenn du das Programm an nem anderen PC oder nach nem Neustart nochmal testest, dass dann auch das println() keine Abhilfe mehr schafft.
 
Zuletzt bearbeitet:
Danke für deine Geduld, aber ich habe das Problem etwas unsauber, aber gut für mich denke ich gelöst.

Ich habe der TabbedPane nen ChangeListener verpasst, der beim wechsel immer das aktuelle Tab abfragt und je nachdem, welches Tab geöffnet bzw. den Fokus hat, Funktionen in der ToolBar belegt werden.
Hier der Code:
Code:
    private void setToolBarActions() {
        view.getjCloseTabbedPane().addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                String name = view.getjCloseTabbedPane().getSelectedComponent().getName();

                if (name.equals("Kundenverwaltung")) {
                    toolBar.getjButton1().setEnabled(true);
                    
                    toolBar.getjButton3().setEnabled(true);
                    toolBar.saveDataSet(ccontrol.new SaveDatensatz());
                    
                    toolBar.getjButton4().setEnabled(true);
                    toolBar.deleteDataSet(ccontrol.new DeleteDatensatz());
                } else {
                    toolBar.getjButton3().setEnabled(false);
                    toolBar.saveDataSet(null);
                    toolBar.getjButton4().setEnabled(false);
                    toolBar.deleteDataSet(null);
                }
            }
        });
    }
 
Kein Problem ;)
Hauptsache ist doch es funktioniert jetzt.

Sooo unsauber etc. finde ich's persönlich gar nicht unbedingt. Du sparst dir ja so u.a. performance-technisch das permanente Durchlaufen in einer While-Schleife und stößt die benötigte Programmlogik - über den ChangeListener - auch nur dann an, wenn du sie die halt eben brauchst. Einen ähnlichen Vorschlag hab ich vorhin ja schonmal gemacht in die Richtung, dass du in der ToolBar immer alle Buttons anzeigst und erst bei Klick differenzierst.
Prinzipiell läuft das jetzt vergleichbar ab bei dir, nur dass du nichts bei der Ansicht einbüst, weil eben nicht immer alles in der ToolBar zu sehen ist - von daher: Gut gelöst!

Die View von dem Programm find ich ohnehin ganz nett. Schlicht und gut. :)
 
Zuletzt bearbeitet:
Zurück
Oben