Swing Teile eines JPanel in eigene Klasse auslagern

Lorke

Mitglied
Hallo,

ich möchte einen Teil eines JPanel in eine eigene KLasse auslagern um ihn wiederzuverwenden.
Bsp. (hab' mehrere solcher 'Patienten'):
Java:
private JPanel getSuchString(){
    FormLayout lay = new FormLayout(
             "10dlu,50dlu,2dlu,90dlu,10dlu,p,2dlu,50dlu:g,10dlu,50dlu,5dlu,50dlu,5dlu,50dlu,2dlu,50dlu,2dlu,50dlu,10dlu",    // xwerte,
             "10dlu,p,2dlu,150dlu:g,5dlu,p,2dlu,80dlu,0dlu"                                                                    // ywerte
            );
    //PanelBuilder builder = new PanelBuilder(lay);
    PanelBuilder builder = new PanelBuilder(lay, new FormDebugPanel());
    builder.getPanel().setOpaque(false);
    CellConstraints cc = new CellConstraints();
    int colNb=2, rowNb=2;
//...   
    builder.addLabel("Suche", cc.xy(colNb, rowNb));

    colNb += 2;
    String[] args = {"dummy1","dummy2","dummy3","dummy4"};
    cBx = new JComboBox(args);
    cBx.setSelectedIndex( vorauswahl );
    builder.add(cBx, cc.xy(colNb,rowNb));       

// auslagern Start
    colNb += 2;
    builder.addLabel("in", cc.xy(colNb, rowNb));
   
    colNb += 2;
    cBoxA = new JCheckBox ("dummyA");
    builder.add(cBoxA,cc.xy(colNb, rowNb,CellConstraints.FILL,CellConstraints.DEFAULT));
    colNb += 2;
    cBoxB = new JCheckBox ("dummyB");
    builder.add(cBoxB,cc.xy(colNb, rowNb,CellConstraints.FILL,CellConstraints.DEFAULT));
    colNb += 2;
    cBoxC = new JCheckBox ("dummyC");
    builder.add(cBoxC,cc.xy(colNb, rowNb,CellConstraints.FILL,CellConstraints.DEFAULT));
// auslagern Ende

//...
    return builder.getPanel();
}
Die betreffenden Elemente zwischen den 'auslagern'-Kommentaren sollen auf ein (Sub-)Panel, das dann statt der einzelnen Elemente an gleicher Stelle eingebunden wird. Abfrage des Zustandes dann über entspr. get-Methoden.

Wie stell' ich das am geschicktesten an?
 
In welcher Klasse befindet sich denn die Methode? So aus dem Kontext gerissen ist es ziemlich schwierig, einen vernünftigen Rat zu geben.
Ich würde tendenziell zwei Wege versuchen:
1. Du übergibst der Klasse, zu der die Methode gehört, eine Instanz einer Klasse oder eines Interfaces (nennen wir sie mal "JPanelConfigurator") mit einer Methode "configure(PanelBuilder builder)" und delegierst den Aufbau der Gui zu einem geeigneten Zeitpunkt an den JPanelConfigurator, indem du in der getSuchString-Methode jPanelConfigurator.configure(builder) aufrufst.
2. Dieser "Halbsatz"
Abfrage des Zustandes dann über entspr. get-Methoden.
macht mich stutzig. Welchen Zustand möchtest du über entspr. get-Methoden abfragen? Den der JCheckBoxen? Wenn ja, würde ich einen anderen Ansatz empfehlen: Schreibe dir ein Datenmodell in Form eines Interfaces, welches getter und setter für boolesche Variablen deklariert, und hänge an die JCheckBoxen ActionListener, die die setter-Methoden aus dem Interface aufrufen. So was habe ich schon mal implementiert und fands ganz nützlich. Das SwitchableIndexPanel gestattet es dem Benutzer, aus einer JList etwas auszuwählen, und anhand der Auswahl entweder sofort oder nach Klick eines JButtons den Zustand eines SwitchableIndexModel zu verändern. Eine Anwendung wäre beispielsweise, in der JList Kunden einzutragen und das SwitchableIndexModel so zu implementieren, dass nach An/Abhaken der JCheckBoxes die Kunden z. B. für einen newsletter registriert werden oder aus der Empfängerliste gestrichen werden. Das ganze wurde mit MigLayout als LayoutManager implementiert (zu dem hatte ich dir schon früher mal geraten).
Java:
public interface SwitchableIndexModel {
  public void toggle(int index, boolean finished);
  public void on(int index, boolean finished);
  public void off(int index, boolean finished);
  public boolean get(int index);
  public String getTrueLabel();
  public String getFalseLabel();
  public String getSelectionLabel();
}
public class SwitchableIndexPanel extends ScrollablePanel{
  public final Icon SHOW_ALL = new ImageIcon(Object.class.getResource("/icons/ShowAllEntries.png"));
  public final Icon HIDE_ALL = new ImageIcon(Object.class.getResource("/icons/HideAllEntries.png"));
  public final Icon TOGGLE_ALL = new ImageIcon(Object.class.getResource("/icons/ToggleAllEntries.png"));
  public final Icon SHOW_MARKED = new ImageIcon(Object.class.getResource("/icons/ShowMarkedEntries.png"));
  public final Icon HIDE_MARKED = new ImageIcon(Object.class.getResource("/icons/HideMarkedEntries.png"));
  public final Icon TOGGLE_MARKED = new ImageIcon(Object.class.getResource("/icons/ToggleMarkedEntries.png"));
  private final JList view;

  public SwitchableIndexPanel(String text, final ListViewAndModel viewAndModel, final SwitchableIndexModel indexModel){
  super(new MigLayout("fill","[grow][]","[][][][][][][][][][][][grow]"));
  JLabel label = new JLabel(text);
  add(label, "split, span");
  add(new JSeparator(), "gapleft rel, growx,wrap");
  JScrollPane pane = new JScrollPane();
  view = new JList();
  view.setModel(viewAndModel);
  view.setCellRenderer(viewAndModel);
  pane.getViewport().setPreferredSize(new Dimension(96, 2));
  pane.setViewportView(view);
  add(pane, "grow, spany 11");
  final JCheckBox toggleOnClick = new JCheckBox("Toggle on click");
  final JCheckBox showSelectedOnly = new JCheckBox(indexModel.getSelectionLabel());
  view.addMouseListener(new MouseAdapter(){
  public void mouseClicked(MouseEvent me){
  int index = view.locationToIndex(me.getPoint());
  if(index < 0) return;
  if(!toggleOnClick.isSelected()) return;
  indexModel.toggle(index, true);
  view.repaint();
  }
  }
  );
  JButton showAllBtn = new JButton(SHOW_ALL);
  showAllBtn.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent ae) {
  for (int i = 0; i < view.getModel().getSize(); i++) {
  boolean flag = i < view.getModel().getSize() -1 ? false : true;
  indexModel.on(i, flag);
  }
  view.repaint();
  }
  });
  JButton hideMarkedBtn = new JButton(HIDE_MARKED);
  hideMarkedBtn.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent ae) {
  int[] selected = view.getSelectedIndices();
  for (int i = 0; i < selected.length; i++) {
  boolean flag = i < selected.length -1 ? false : true;
  int ii = selected[i];
  indexModel.off(ii, flag);
  }
  view.repaint();
  }
  });
  JButton toggleAllBtn = new JButton(TOGGLE_ALL);
  toggleAllBtn.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent ae) {
  for (int i = 0; i < view.getModel().getSize(); i++) {
  boolean flag = i < view.getModel().getSize() -1 ? false : true;
  indexModel.toggle(i, flag);
  }
  view.repaint();
  }
  });
  }
}
 
In welcher Klasse befindet sich denn die Methode? [/code]

Da muß ich etwas weiter ausholen:
Bin grade dabei mich in die Sourcen einer bestehenden, komplexen Anwendung einzuarbeiten, die zwar in Java programmiert ist, wo das 'Vererben' aber meist mit copy&paste stattgefunden hat - ein riesiger Haufen Code :-/
Mache kleinere Änderungen/Ergänzungen und versuche in dem Zuge etwas aufzuräumen.
Die Klasse, aus der der Ausschnitt stammt, liefert den Inhalt eines Tabs in einem Tabbed Pane in dem erst eine Datenbankabfrage aus versch. Bestandteilen zusammengesetzt wird, dann das Ergebnis als Tabelle präsentiert und schließlich im dritten Teil versch. Aktionen mit einem der Datensätze möglich sind (Druck,...).
Die Checkboxen (Auswahl, welche Tabellen durchsucht werden; den Suchlauf startet ein Button) sind in 2 weiteren Tabs in anderem Kontext identisch vorhanden, u. dort separat ausprogrammiert.

Hatte auf 'nen Hinweis auf z.B. ein Template für die Klasse gehofft, die die auszulagernden Daten aufnimmt, da die Refactoring-Funktion von Eclipse nicht das liefert was ich mir vor- (bzw. ich mich einfach noch zu blöd an-) stelle...

1. Du übergibst der Klasse, zu der die Methode gehört, eine Instanz einer Klasse oder eines Interfaces (nennen wir sie mal "JPanelConfigurator") mit einer Methode "configure(PanelBuilder builder)" und delegierst den Aufbau der Gui zu einem geeigneten Zeitpunkt an den JPanelConfigurator, indem du in der getSuchString-Methode jPanelConfigurator.configure(builder) aufrufst.
2. Dieser "Halbsatz"

macht mich stutzig. Welchen Zustand möchtest du über entspr. get-Methoden abfragen? Den der JCheckBoxen?
[/code]

Ja. Mein Plan ist das zugehörige Label und die Checkboxen in eine eigene Klasse zu packen, die ein Mini-Panel liefert. Instanzen davon werden an den Stellen eingebunden, wo bisher Kopien des gleichen Codes stehen. *Listener habe ich nicht vor zu verwenden, da der Zustand der Auswahl abgefragt werden kann wenn die Suche startet.


anderen Ansatz empfehlen: Schreibe dir ein Datenmodell in Form eines Interfaces, welches getter und setter für boolesche Variablen deklariert, und hänge an die JCheckBoxen ActionListener, die die setter-Methoden aus dem Interface aufrufen.
[/code]
Vom Umbau der Grundstrukturen lass' ich vorerst noch die Finger - muß mir erst ein wenig 'Handwerkszeug' im Umgang mit Java und den ganzen Bibliotheken erarbeiten. Hab' zwar etliche Jahre uC programmiert, auf dieser Plattform hier bin ich aber noch relativ neu.

Inzwischen hab' ich's geschafft ein paar Subpanels für Fälle ähnlich dem beschriebenen zu bauen und einzubinden. Dabei schlage ich mich noch mit so Banalitäten 'rum wie "Subpanel skaliert nicht wenn ich das Fenster verändere, obwohl das verwendete FormLayout eine Spalte mit 'growing'-Attribut enthält". Muß ich das Subpanel dafür noch irgendwo registrieren?
 
Dabei schlage ich mich noch mit so Banalitäten 'rum wie "Subpanel skaliert nicht wenn ich das Fenster verändere, obwohl das verwendete FormLayout eine Spalte mit 'growing'-Attribut enthält". Muß ich das Subpanel dafür noch irgendwo registrieren?
Keine Ahnung. Mit FormLayout kenne ich mich nicht aus. Ich kann mich nur wiederholen: teste mal MigLayout. Wenn es damit konkrete Probleme gibt, bin ich gerne behilflich.
 

Zurück
Oben