# DockingFrames



## PollerJava (12. Jan 2008)

Hallo,

ich habe die DockingFrames von der Seite http://dock.javaforge.com/help.html verwendet.
Mein Problem ist jetzt, dass, wenn ich den JButton vom Programm unten drücke, ein neuer DockingFrame hinzugefügt werden soll (station.drop(new DefaultDockable( "Beschreibung" ), SplitDockProperty.EAST );
);
Das funktioniert auch aber das Problem ist, wenn ich die Größe des DockingFrames in East ändere, ein neuer JFrame in East erzeugt wird und nicht ein JFrame zu den bestehenden hinzugefügt wird,

Hat da jemmand eine Idee, wie man das machen kann,

Vielen Dank,

lg

(PS: Das Programm unten funktioniert)





```
package javaapplication15;

import bibliothek.gui.dock.station.split.SplitDockProperty;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import bibliothek.gui.DockController;
import bibliothek.gui.dock.station.SplitDockStation;
import bibliothek.*;
import bibliothek.extension.gui.dock.theme.EclipseTheme;
import bibliothek.gui.DockTheme;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.station.SplitDockStation;
import java.awt.event.ActionListener;
import javax.swing.JButton;

class Main implements ActionListener
{
    SplitDockStation station;
    
    public Main()
    {
     JButton button = new JButton("addPanel");
     button.setBounds(20,20,200,80);
     button.addActionListener(this);
     DockController controller = new DockController();
     controller.setSingleParentRemove( true );
     station = new SplitDockStation();
     DockTheme theme = new EclipseTheme();
     controller.setTheme( theme );
     controller.add(station);   
     controller.add( station );
     DefaultDockable dD = new DefaultDockable( "One");
     dD.getContentPane().add(button);
     station.drop(dD , SplitDockProperty.NORTH );
     station.drop( new DefaultDockable( "Two" ), SplitDockProperty.NORTH );
     station.drop( new DefaultDockable( "Three" ), SplitDockProperty.EAST );
     station.drop( new DefaultDockable( "Four" ), SplitDockProperty.EAST );


     JFrame frame = new JFrame();
     frame.add( station.getComponent() );

     frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
     frame.setBounds( 20, 20, 400, 400 );
     frame.setVisible( true );  
    }

public static void main( String[] args ){
    Main main = new Main();
}

    public void actionPerformed(ActionEvent e) {
        station.drop(new DefaultDockable( "Beschreibung" ), SplitDockProperty.EAST );
    }
}
```


----------



## Beni (12. Jan 2008)

Ich muss leider sagen, dass es dafür keine optimale Lösung gibt.

Diese Konstanten "EAST", "NORTH", ... mögen zwar implizieren, dass eine SplitDockStation mit dem BorderLayout verwandt wäre... dem ist aber nicht so. Der Benutzer kann diese Dockables ja frei bewegen, und spätestens wenn er z.B: "Three" nach rechts oben, und "Four" nach rechts unten setzt, macht die Position "EAST" nicht mehr viel Sinn.

Die SplitDockStation versucht deshalb folgendes: EAST beschreibt das Rechteck welches das neue Dockable gerne einnehmen würde. Falls sich dieses Rechteck zu mindestens 75% mit einem anderen Rechteck (eines Dockables) überschneidet, werden die  Elemente aufeinandergestappelt - sonst nicht.

Wenn du weisst, mit welchem anderen Dockable das neue Dockable "vereinigt" (oder gestappelt) werden soll, kannst du aber folgendes Stücklein Code anwenden:


```
Dockable oldDockable = ...
Dockable newDockable = ...
SplitDockStation station = ...

// alte Position lesen
DockableProperty location = DockUtilities.getPropertyChain( station, oldDockable );

// neues Dockable absetzen
if( !station.drop( location, newDockable ) ){
  // failsave
  station.drop( newDockable );
}
```


----------



## PollerJava (12. Jan 2008)

Vielen Dank Beni, das war genau das was ich brauche,
Ich hätte da noch ein paar Fragen und zwar, ist es möglich, ein Schließen- Kreuz auf den Tabs zu plazieren 
und wie kann ich die Größe von EAST beim starten des Programms angeben (momentan ist bei mir der EAST- Bereich zu schmal).
Ist der Code von den ScreenShots eigentlich frei verfügbar?

Find die DockFrames echt super, ist ideal für viele Anwendungen.

Vielen Dank für Deine Hilfe,

lg


----------



## Beni (12. Jan 2008)

PollerJava hat gesagt.:
			
		

> ist es möglich, ein Schließen- Kreuz auf den Tabs zu plazieren


Die einfachste Variante: verwende ein DockFrontend anstelle des DockControllers. Das wird dann ungefähr so aussehen:

```
SplitDockStation station = ...

// brauchen wir nichtmehr
// DockController controller = new DockController();
DockFrontend frontend = new DockFrontend();
frontend.addRoot( station, "station-id" );

DefaultDockable dock = new DefaultDockable( "One" );
frontend.add( dock, "one" );
frontend.setHideable( dock, true );
```

Die etwas komplizierte Variante ist eine eigene DockAction zu schreiben. Das würde dann ungefähr so gehen:

```
// die Annotation sagt, dass diese Action auf die Tabs
// kommt (funktioniert aber nur beim EclipseTheme).
@EclipseTabDockAction
public class CloseAction extends SimpleButtonAction{
  public CloseAction(){
    setText( "Close" );
    setIcon( ... );
  }

  public void action( Dockable dockable ){
    // schliessen
    dockable.getDockParent().drag( dockable );
  }
}
```

Und später:

```
DefaultDockable dock = new DefaultDockable( "one" );
CloseAction close = new CloseAction();
dock.setActionOffers( new DefaultDockActionSource( close ));
```




> und wie kann ich die Größe von EAST beim starten des Programms angeben (momentan ist bei mir der EAST- Bereich zu schmal).


EAST selbst kannst du nicht ändern, aber eine neue Position generieren:

```
double size = ...
SplitDockProperty east = new SplitDockProperty( 1-size, 0, size, 1 );
```
(P.S. size ist besser < 0.75, ansonsten schlägt die 75%-Regel der SplitDockStation zu)



> Ist der Code von den ScreenShots eigentlich frei verfügbar?


Nein. Das Programm von dem die Screenshots stammen entstand fast zeitgleich mit den DF, und wurde deshalb auch oft als Experimentierkaninchen missbraucht... *du willst den Code nicht sehen* :wink:

Der Code zu den Demonstrationen findest du aber im Repository (theoretisch gäbe es einen anonymen Zugang mit "User=anonymous", "pw=anon", praktisch scheint das mal mehr mal weniger gut zu funktionieren. Auf der download-Seite gibt es sonst einen checkout des gesammten Projektes, da sind die Demos auch drin).


----------



## PollerJava (12. Jan 2008)

Viele Dank für Deine schnellen Antworten,

lg


----------



## PollerJava (14. Jan 2008)

Hallo Beni,

ich hätte noch eine Frage und zwar wie bekomme ich das Schließen- Kreuz auf die DockingFrames, ich habs jetzt so ausprobiert, wie du geschrieben hast, funkt aber irgendwie noch nicht:
Könntest Du mir vielleicht schreiben, was ich da noch falsch mache?

Hier mein Programm


```
package javaapplication83;

import bibliothek.extension.gui.dock.theme.eclipse.EclipseTabDockAction;
import bibliothek.gui.DockFrontend;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DockableProperty;
import bibliothek.gui.dock.action.DefaultDockActionSource;
import bibliothek.gui.dock.action.actions.SimpleButtonAction;
import bibliothek.gui.dock.station.split.SplitDockProperty;
import bibliothek.gui.dock.util.DockUtilities;
import java.awt.event.ActionEvent;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import bibliothek.gui.DockController;
import bibliothek.gui.dock.station.SplitDockStation;
import bibliothek.*;
import bibliothek.extension.gui.dock.theme.EclipseTheme;
import bibliothek.gui.DockTheme;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.station.SplitDockStation;
import java.awt.event.ActionListener;
import javax.swing.JButton;

class Main implements ActionListener
{
    SplitDockStation station;
    DefaultDockable testdD;
   
    public Main()
    {
     JButton button = new JButton("addPanel");
     button.setBounds(20,20,200,80);
     button.addActionListener(this);
     DockController controller = new DockController();
     controller.setSingleParentRemove( true );
     station = new SplitDockStation();
     DockTheme theme = new EclipseTheme();
     controller.setTheme( theme );
     controller.add(station);   
     controller.add( station );
     DefaultDockable dD = new DefaultDockable( "One");
     dD.getContentPane().add(button);
     station.drop(dD , SplitDockProperty.NORTH );
     station.drop( new DefaultDockable( "Two" ), SplitDockProperty.NORTH );
     testdD = new DefaultDockable( "Three" );
     station.drop(testdD, SplitDockProperty.EAST );
     station.drop( new DefaultDockable( "Four" ), SplitDockProperty.EAST );     
     CloseAction close = new CloseAction();
     testdD.setActionOffers( new DefaultDockActionSource( close )); 
     JFrame frame = new JFrame();
     frame.add( station.getComponent() );
     frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
     frame.setBounds( 20, 20, 400, 400 );
     frame.setVisible( true );  
    }

public static void main( String[] args ){
    Main main = new Main();
}

    public void actionPerformed(ActionEvent e) {
        DockableProperty location = DockUtilities.getPropertyChain( station, testdD);
        DefaultDockable testdD1 = new DefaultDockable("Test");
        if( !station.drop(testdD1,  location ) ){
            station.drop( testdD1 );
        } 
    }
}

@EclipseTabDockAction
class CloseAction extends SimpleButtonAction{
  public CloseAction(){
    setText( "Close" );
        try {
            setIcon(new ImageIcon(new URL("C:/Projekte/DMerstellung.png") ));
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
  }

  public void action( Dockable dockable ){
    // schliessen
    dockable.getDockParent().drag( dockable );
  }
}
```


----------



## Beni (14. Jan 2008)

Wenn das Dockable bereits angezeigt wird, dann hat "setActionOffers" keinen direkten Effekt mehr (wenn das Dockable einen neuen Parent bekommt, würde die Action aber auftauchen). Zuerst die DockActionSource verändern, dann das Dockable anzeigen.


```
testdD = new DefaultDockable( "Three" );
     CloseAction close = new CloseAction();
     testdD.setActionOffers( new DefaultDockActionSource( close ));
     
     station.drop(testdD, SplitDockProperty.EAST );
     station.drop( new DefaultDockable( "Four" ), SplitDockProperty.EAST );
```

Das ist ein Bug den es in der nächsten Version nicht mehr gibt.


----------



## PollerJava (14. Jan 2008)

Vielen Dank, es funktioniert!!!

lg


----------



## PollerJava (15. Jan 2008)

Hallo Beni,

hätte noch eine Frage zu den DockingFrames,

Funktioniert so weit sehr gut, ich möchte aber jetzt, dass 2 DockingFrames untereinander in EAST sind, also genau das Gegenteil wie vorher, 
Ist das irgendwie möglich, 2 DockingFrames untereinander zu plazieren?

Vielen Dank für Deine Antworten,

lg


----------



## Beni (15. Jan 2008)

Platziere das erste in EAST. Für das zweite musst du dann eine eigene Position anlegen. Das sollte dann etwa so gehen:

```
SplitDockProperty southeast = new SplitDockProperty( 0.75, 0.5, 0.25, 0.5 );
station.drop( dockable, southeast );
```

[Edit: oder wenn das gleich beim Start des Programmes so sein soll, benutze ein SplitDockGrid: da werden die Koordinaten der Dockables einmal angegeben, und später so gut wie möglich umgesetzt. Auf der Homepage gäbe es ein Beispiel, aber da JavaForge gerade umgebaut wird habe ich es jetzt mal rauskopiert:


```
import java.awt.Color;

import javax.swing.JFrame;
import javax.swing.JPanel;

import bibliothek.gui.DockFrontend;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.DefaultDockable;
import bibliothek.gui.dock.station.SplitDockStation;
import bibliothek.gui.dock.station.split.SplitDockGrid;

public class Dock {
	public static void main( String[] args ){
		JFrame frame = new JFrame( "Demo" );
		DockFrontend frontend = new DockFrontend( frame );
		SplitDockStation station = new SplitDockStation();
		
		frame.add( station.getComponent() );
		frontend.addRoot( station, "station" );
		
// Das hier wäre für dich wichtig:
		SplitDockGrid grid = new SplitDockGrid();
		grid.addDockable( 0, 0, 1, 1, createDockable( "Red", Color.RED ) );
		grid.addDockable( 0, 1, 1, 1, createDockable( "Green", Color.GREEN ) );
		grid.addDockable( 1, 0, 1, 1, createDockable( "Blue", Color.BLUE ) );
		grid.addDockable( 1, 1, 1, 1, createDockable( "Yellow", Color.YELLOW ) );
		station.dropTree( grid.toTree() );
// ab hier ist es nicht mehr wichtig
		
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setBounds( 20, 20, 400, 400 );
		frame.setVisible( true );
	}
	
	public static Dockable createDockable( String title, Color color ) {
		JPanel panel = new JPanel();
		panel.setOpaque( true );
		panel.setBackground( color );
		return new DefaultDockable( panel, title );
	}
}
```

]


----------



## PollerJava (15. Jan 2008)

Vielen Dank!!

lg


----------



## PollerJava (21. Jan 2008)

Hallo Beni,

Ich hätte noch eine Frage zu den DockingFrames und zwar wenn ich mehrere 


```
DefaultDockable pV = new DefaultDockable()
```

hinzufüge (quasi wenn ich mehrere Tabs auf einem DockingFrame habe)


```
DockableProperty location = DockUtilities.getPropertyChain( station, dummy);

station.drop(pV);
```

kann ich dann irgenwie bestimmen, welcher DefaultDockable gerade im Vordergrund ist, also den Focus hat??

lg und vielen dank für Deine Antworten,


----------



## Beni (21. Jan 2008)

"setFocusedDockable" sollte helfen:

```
DockController controller = ...
controller.setFocusedDockable( einDockable, true );
```


----------



## PollerJava (21. Jan 2008)

Ahhh. tut mir leid, ich hab die Frage falsch formuliert,

wenn ich mehrere Tabs habe, wie könnte ich da in Erfahrung bringen, welcher gerade den Fokus hat also welcher gerade im Vordergrund ist,

vielen Dank


----------



## Beni (21. Jan 2008)

Zwei Varianten: "DockController#getFocusedDockable()", und alle DockStationen haben eine Methode "getFrontDockable", welche das selektierte Dockable (falls vorhanden) zurückgibt.


----------



## PollerJava (21. Jan 2008)

Vielen dank!!

eine kleine Frage hätte ich noch und zwar habe ich intern ein JPanel "mainPanel" und diese JPanel geben ich auf das DefaultDockable:


```
DefaultDockable pV = new DefaultDockable();
 pV.getContentPane().add(mainPanel);
```

und dieses DefaultDockable setze ich dann, wo ich es haben will:


```
DockableProperty location = DockUtilities.getPropertyChain( station, dummy);
                if( !station.drop(pV,  location ) ) {
                    station.drop(pV);
```


Wenn ich jetzt z.B.: 3 Tabs auf einer "location" habe und zwischen diesen Tabs umschalte, dann möchte ich immer, dann 
"mainPanel" eine Referenz auf das JPanel im DefaultDockable hat, welches gerade im Vordergrund ist,

Ist das irgendwie möglich zu dedektieren, dass mit der Maus zwischen den Tabs hin und hergeschalten wird und ich dann eben meine Referenz JPanel mainPanel immer auf das aktuelle JPanel im DefaultDockable setze,

Vielen Dank,

lg


----------



## PollerJava (21. Jan 2008)

Hättest Du da noch eine Idee?? 



Bzw. kann ich z.B.: von East herausfinden, welcher Tab im Vordergrund ist?

lg


----------



## Beni (21. Jan 2008)

Ich bin mir jetzt nicht ganz sicher was du machen willst, aber ich denke folgendes wird dir helfen:
Du kannst dem  DockController einen DockControllerListener hinzufügen. Der DockControllerListener wird über "dockableFocused" informiert, wenn ein Dockable den Fokus gewinnt. Und wenn man auf so ein Tab klickt, gewinnt das angeklickte Dockable meistens den Fokus.


----------



## PollerJava (21. Jan 2008)

ist es irgenwie möglich, von EAST herauszufinden, welcher Tab im Vordergrund ist,

mit DockController#getFocusedDockable() bekomme ich ja den Dockable(), welcher allgemein (von EAST, WEST, NORTH und SOUTH) den Fokus hat, ich möchte aber nur den von EAST haben,

Ist das möglich?

lg


----------



## Beni (21. Jan 2008)

Nein, da EAST, WEST, etc. nur beim Hinzufügen eine Bedeutung haben. Der Benutzer kann das ja später auseinanderreissen...


----------

