|
Die Klasse TSplitWindow realisiert eine Fensterklasse, die ein vertikal oder horizontal geteiltes Fenster haben kann. TSplitWindow ist von TLayoutWindow abgeleitet. Diese Klasse ermöglicht das Verwalten zweier Fenster auf einfache Art und Weise.
| Überblick |
|
TSplitWindow stellt eine Laufleiste zur Einstellung der Fenstergrößen bereit. Diese Leiste wird benutzt, indem mit der Maus auf den Rahmen zwischen den beiden Fenstern geklickt und der Rahmen mit der Maus gezogen wird. Nach dem Loslassen des Mausbuttons werden die beiden Kindfenster in den neuen Größen dargestellt.
| Größeneinstellung |
|
In den nachfolgenden Beschreibungen wird von linkem und rechtem Kindfenster die Rede sein. Dieser Sprachgebrauch ist natürlich nur dann korrekt, wenn die beiden Fenster horizontal geteilt werden. Bei vertikaler Teilung entspricht das linke Fenster dem oberen Fenster und das rechte dem unteren.
| Benennungskonvention |
TSplitWindow(TWindow* parent,
const char far* title,
TWindow* client1,
TWindow* client2,
client1Size = 50,
isVert = true,
isfixed = false,
TModule* module = 0);
Dem Konstruktor werden in client1 und client2 zwei Zeiger auf die beiden Kindfenster übergeben. Client1Size spezifiziert die Ausgangsgröße des linken Kindfensters in Prozent bezogen auf den Bildschirm. Per Default steht dieser Parameter auf 50, so daß beide Kindfenster gleich groß werden. isVert zeigt an, ob eine vertikale (true) oder horizontale (false) Teilung erfolgen soll. Vorgabe ist hier eine vertiakle Teilung, so daß die beiden Kindfenster übereinander zu liegen kommen. IsFixed schließlich legt fest, ob die Größe der beiden Fenster veränderbar (true) oder auf das übergebene Größenverhältnis festgelegt ist. Der Wert true beläßt das linke Fenster auf einer konstanten Größe auch dann, wenn das übergeordnete Elternfenster in bezug auf die Größe verändert wird. In diesem Fall erfolgt dann eine Anpassung des rechten Kindfensters, während das linke Fenster in bezug auf die absolute Größe unverändert bleibt.
| Konstruktor |
|
Der Konstruktor setzt die privaten Variablen auf die entsprechenden Werte der übergebenen Parameter. Zusätzlich wird überprüft, ob eines der beiden Kindfenster ein TListBox-Objekt ist. Ist dies der Fall, wird der Fensterstil des entsprechenden Fensters auf LBS_NOINTEGRALHEIGHT gesetzt. Dies ist notwendig, um sicherzustellen, daß die Listbox auch tatsächlich die gesamte Höhe des Fensters beansprucht.
Anschließend setzt der Konstruktor das Parentfenster beider Kindfenster auf sich selbst. Damit wird sichergestellt, daß beide Kindfenster der Fensterliste des TLayoutWindow-Objekts hinzugefügt werden.
Zu guter Letzt setzt der Konstruktor minWndSize auf 5 und die private Variable dragging auf false sowie den TWindowDC-Zeiger dc auf 0.
| Initialisierungen |
TSplitWindow::TSplitWindow(
const TSplitWindow& sw)
: TLayoutWindow(0)
Der Kopierkonstruktor ermöglichst das Verwenden eines TSplitWindows in BIDS Container.
Öffentliche Variable
| Kopierkonstruktur |
int minWndSize
Die Variable minWndSize kontrolliert die minimale Größe eines Kindfensters. Das Setzen eines entsprechenden Werts verhindert, daß der Anwender das Fenster über die Größenlaufleiste kleiner als erwünscht einstellt. Die Voreinstellung lautet 5. Wird kein Wert eingesetzt, kann der Anwender ein Fenster so vergrößern, daß das zweite Kindfenster nicht mehr sichtbar ist.
Öffentliche Memberfunktionen
| Variable: minWndSize |
void Switch()
Switch wechselt die Teilungsreichtung von vertikal auf horizontal bzw. umgekehrt. Intern werden dazu die Funktionen LayoutVertical() bzw. LayoutHorizontal() aufgerufen und die Variable isVertical entsprechend gesetzt.
| Memberfunktion Switch |
void NextChild(int child = 0)
Wird NextChild mit dem Default-Parameter aufgerufen, wechselt der Eingabefokus auf das jeweils andere Kindfenster. Soll der Fokus unabhängig vom gegenwärtigen Zustand auf ein bestimmtes Fenster gesetzt werden, so ist NextChild mit den Parametern CHILD_LEFT bzw. CHILD_RIGHT aufzurufen. Intern verwendet die Funktion den API-Aufruf SetFocus() mit dem entsprechenden Fensterhandle.
| Memberfunktion NextChild |
TWindow* SetLeftChild(TWindow* client)
SetLeftChild setzt ein neues linkes Kindfenster. Dazu wird zunächst das bestehende linke Kindfenster nach einem Aufruf von CanClose() zerstört und anschließend durch das in client übergebene Fenster ersetzt. Die Funktion ruft Create() auf, um das neue Fenster zu erzeugen. Abschließend wird LayoutVertical() oder LayoutHorizontal() aufgerufen, um die Darstellung der Fenster vorzunehmen. Der Rückgabewert ist der Zeiger auf das neue Kindfenster oder 0, wenn die Funktion fehlschlägt.
| Memberfunktion SetLeftChild |
TWindow* SetRightChild(TWindow* client)
SetRightChild setzt ein neues rechtes Kindfenster. Dazu wird zunächst das bestehende rechte Kindfenster nach einem Aufruf von CanClose() zerstört und anschließend durch das in client übergebene Fenster ersetzt. Die Funktion ruft Create() auf, um das neue Fenster zu erzeugen. Abschließend wird LayoutVertical() oder LayoutHorizontal() aufgerufen, um die Darstellung der Fenster vorzunehmen. Der Rückgabewert ist der Zeiger auf das neue Kindfenster oder 0, wenn die Funktion fehlschlägt.
| Memberfunktion SetRightChild |
TWindow* GetLeftChild()
GetLeftChild liefert einen Zeiger auf das linke Kindfenster.
| Memberfunktion GetLeftChild |
TWindow* GetRightChild()
GetRightChild liefert einen Zeiger auf das rechte Kindfenster.
| Memberfunktion GetRightChild |
int GetLeftChildSize()
GetLeftChildSize liefert die Größe des linken Fensters als Prozentwert bezogen auf das Hauptfenster.
| Memberfunktion GetLeftSize |
bool IsVertical()
Mit IsVertical kann das aktuelle Fensterlayout ermittelt werden. Die Funktion liefert true, wenn die Kindfenster vertikal angeordnet sind, und false für eine horizontale Teilung.
| Memberfunktion IsVertical |
void EnableFixedSizing(bool enable = true)
EnableFixedSizing ermöglicht das nachträgliche Ändern des Flags für die Größenfixierung des linken Fensters. True fixiert die Größe, während false die Fixierung aufhebt.
| Memberfunktion EnableFixedSizing |
operator =
& operator ==
Die Zuweisungsoperatoren wurden implementiert, damit TSplitWindow als BIDS-Container verwendet werden kann.
Geschützte Memberfunktionen
| Zuweisungsoperatoren |
SetupWindow()
Die Memberfunktion SetupWindow des Objekts TSplitWindows ruft als erstes TLayoutWindow::SetupWindow() und anschließend abhängig von der Fensterorientierung LayoutVertical() bzw. LayoutHorizontal().
| Memberfunktion SetupWindow |
EvLButtonDown()
EvLButtonDown leitet den Ziehprozeß ein. Dazu wird die Variable dragging auf true gesetzt und der Mausbewegungsbereich mittels SetCapture() auf das Elternfenster der beiden Kindfenster beschränkt.
Als nächstes wird für den Zugriff auf das Ausgabefenster ein neuer TWindowDC erzeugt und der ROP2-Code für dc auf R2_NOT gesetzt. Dieser ROP2-Code erlaubt das einmalige Zeichnen der Größenlaufleiste und spätere Entfernen durch erneutes Zeichnen. Bestehende Grafik- und Text-Ausgaben bleiben jedoch in den darunterliegenden Fenstern erhalten.
Abschließend wird die Größe der Laufleiste anhand der Höhe des Client-Rechtecks bestimmt. Für das Zeichnen wird ein Stift mit der Breite eines breiten Rahmens gemäß GetSystemmetrics dem Fenster-DC zugewiesen und die aktuellen Koordinaten für spätere Zugriffe aus EvMouseMove() gespeichert.
| Memberfunktion EvLButtonDown |
EvMouseMove()
EvMouseMove löscht und zeichnet die Laufleiste neu über die Funktion DrawSizingBar(). Zusätzlich wird überprüft, ob die Maus aus dem Fenster herausgezogen wurde. In diesem Fall wechselt der Cursor zum Standard-Pfeil, um dem Anwender zu zeigen, daß die Maus das Fenster verlassen hat. Wandert die Maus zurück in das Layout-Fenster, wechselt der Cursor zurück auf das Zieh-Symbol. Ist dragging false, kehrt die Funktion sofort ohne jede Aktion zurück.
| Memberfunktion EvMouseMove |
DrawSizingBar()
Für das Zeichnen der Größenlaufleiste wird zunächst der Wert der variable oldPoint verwendet, um die bisherige Darstellung zu löschen. Zuvor wird jedoch der X-Wert des TPoint-Objekts gegen minWndSize verglichen. Ist der X-Wert kleiner oder gleich minWndSize, wird die Leiste an der Position minWndSize gelöscht. Anschließend wird die Leiste neu gezeichnet und neue Position nach oldPoint übenommen.
| Memberfunktion DrawSizingBar |
EvLButtonUp()
EvLButtonUp beendet den Ziehvorgang, indem zunächst die Variable dragging auf false gesetzt wird. Anschließend wird die Größenlaufleiste an der letzten Position durch Neuzeichnen gelöscht und das Maus-Capturing aufgehoben. Die Funktion ruft dann SetNewPositions() mit der aktuellen Position als Parameter auf, um die Fenstergrößen neu zu setzen. Zuletzt wird TWindowDC gelöscht und dc auf NULL gesetzt.
| Memberfunktion EvLButtonUp |
EvSetCursor()
EvSetCursor wird aus EvMouseMove heraus aufgerufen. Sie überwacht das Fenster, das unter dem Cursor liegt. Verläßt der Cursor das Layout-Fenster, wechselt die Cursorform zum Standardpfeil. Liegt der Mauscursor über einem Layout-Fenster, setzt die Funktion den Cursor auf die durch arrowType vorgegebene Form. Diese wird über die Funktionen LayoutHorizontal bzw. LayoutVertical in der Variablen arrowType abgelegt.
Private Variablen
| Memberfunktion EvSetCursor |
bool IsVertical
Die boolesche Variable IsVertical zeigt an, ob die Kindfenster das Elternfenster horizontal oder vertikal teilen, wobei der Wert true für eine vertikale Teilung steht.
| Variable IsVertical |
bool IsFixedSize
IsFixedSize zeigt an, ob das linke Fenster eine feste Größe (true) besitzt oder nicht.
| Variable IsFixedSize |
TWindow* childLeft
TWindow* childRight
childLeft und childRight speichern Zeiger auf die Fensterobjekte der beiden Kindfenster des Layout-Fensters.
| Variablen childLeft childRight |
TPoint oldPoint
oldPoint enthält während des Ziehvorgangs die Koordinaten der jeweils letzten Mausposition der Größenlaufleiste.
| Variable oldPoint |
TPen* sizingPen
sizingPen zeigt auf ein Stiftobjekt, das zum Zeichnen während der Größenänderung der Kindfenster verwendet wird.
| Variable sizingPen |
bool dragging
Die boolesche Variable dragging zeigt an, ob gerade ein Ziehvorgang über die Größenlaufleiste abläuft (true) oder nicht (false).
| Variable dragging |
bool offScreen
Verläßt die Maus während des Zihens das Layout-Fenster, wird die Variable offScreen auf true und bei Rückkehr in das Fenster wieder zurück auf false gesetzt.
| Variable offScreen |
int leftChildSize
In leftChildSize wird die Größe des linken Fensters als Prozentwert bezogen auf das Elternfenster gespeichert.
| Variable leftChildSize |
int clientWidth
int clientHeight
clientWidth und clientHeight geben die Höhe und Breite des Clientbereichs des Layoutfensters an. Diese Werte werden für die Größenberechnung der Größenlaufleiste verwendet.
| Variablen clientWidth clientHeight |
char* arrowType
arrowType enthält die während des Ziehens zu verwendende Cursorform. Der Wert der Variable ist, je nach aktuellem Fenster-Layout, entweder IDC_SIZEWE oder IDC_SIZENS.
| Variable arrowType |
TWindowDC* dc
In dc legt TSplitWindow einen Zeiger auf den für das Zeichnen während des Ziehvorgangs verwendeten dc für den schnelleren Zugriff ab.
Interna der Implementation
Für die Darstellung zweier kombinierter Fenster in einem Elternfenster verwendet die Fensterklasse TSplitWindow die Fähigkeiten und Eigenschaften der Klasse TLayoutWindow.
| Variable dc |
|
Zur Steuerung eines TLayoutWindow muß zunächst eine TLayoutMetrics-Struktur mit den passenden Werten des gewünschten Fensters gefüllt werden. Die Elemente X und Y der Struktur sind Instanzen der Klasse TEdgeConstraint, während Width und Height Instanzen der Klasse TEdgeOrWidthConstraint sind. Die Werte bezeichnen die linke obere Ecke des Fensters sowie dessen Breite und Höhe.
Nach Zuweisung dieser Werte kann SetChildLayoutMetrics mit dem erzeugten Fenster und der TLayoutMetrics-Struktur als Parameter aufgerufen werden.
| TLayoutWindow steuern |
|
Die Funktion LayoutVertical führt eine vertikale Teilung und Anordnung der Kindfenster durch. Ferner berücksichtigt diese Funktion, ob das linke Fenster in bezug auf seine Größe fixiert ist oder nicht.
| Vertikale Teilung |
|
In einem ersten Schritt wird eine Instanz der TLayoutMetrics-Struktur erzeugt, die nachfolgend mit lm bezeichnet wird. Diese Struktur wird für das linke bzw. in diesem Fall obere Fenster initialisiert. Die x- und y-Werte enthalten dazu entweder (0,0) oder die linke obere Ecke des Elternfensters. Durch Verwendung der Funktion Absolute() der TEdgeConstraint-Klasse wird sichergestellt, daß diese Werte absolut und nicht relativ interpretiert werden. Die Breite des Kindfensters ergibt sich als absoluter Wert aus der Größe des linken Fensters sowie der Breite des Clientbereichs des Elternfensters. Die unteren Fensterränder von Kind- und Elternfenster werden gleichgesetzt. Abschließend erfolgt der Aufruf von SetChildLayoutMetrics() mit lm und *childLeft als Parameter.
| Linkes Fenster |
TSplitWindow::LayoutVertical()
{
TLayoutMetrics lm;
childLeft->Attr.Style |= WS_CLIPSIBLINGS |
WS_BORDER;
lm.X.Absolute(lmLeft, 0);
lm.Y.Absolute(lmTop, 0);
if (isFixedSize) {
lm.SetMeasurementUnits(lmPixels);
long w = Parent->GetClientRect().Width();
lm.Width.Absolute(lmRight, (int)
(((long)leftChildSize
* w) /100));
}
else lm.Width.PercentOf(lmParent,
leftChildSize);
lm.Height.SameAs(lmParent, lmHeight);
SetChildLayoutMetrics(*childLeft, lm);
| SetChildLayout-Metrics() |
|
Im zweiten Schritt wird das Layout für das rechte Fenster festgelegt. Die Position des linken Rands ergibt sich anhand des rechten Rands des linken Fensters. Für die Berechnung der Breite des rechten Fensters muß zusätzlich berücksichtigt werden, daß zwei Rahmenlinien plaziert werden müssen. Die Breite dieser Linien sowie der Ziehlinie für Größenänderungen werden in der lokalen Variable gap gespeichert. Abschließend erfolgt für das rechte Kindfenster wiederum ein Aufruf von SetChildLayoutMetrics.
childRight->Attr.Style |= WS_CLIPSIBLINGS | WS_BORDER;
int gap = GetSystemMetrics(SM_CXFRAME) -
(GetSystemMetrics(SM_CYBORDER) *2);
lm.X.RightOf(childLeft, gap);
lm.Y.Absolute(lmTop, 0);
lm.Width.SameAs(lmParent, lmRight);
lm.Height.SameAs(lmParent, lmHeight);
SetChildLayoutMetrics(*childRight, lm);
| Rechtes Fenster |
|
Nachdem die Layouts für beide Kindfenster gesetzt wurden, kann die Verbindung der beiden Kindfenster über den Aufruf der Funktion Layout() des TLayoutWindow erfolgen.
Layout();
arrowType = (char*)IDC_SIZEWE;
}
Damit übernimmt dann TLayoutWindow die Kontrolle und sorgt dafür, daß die beiden Kindfenster jeweils korrekt plaziert und angezeigt werden, wenn sich die Größe des Elternfensters ändert.
| Layouts verbinden |
|
Die Funktion LayoutHorizontal führt die für die horizontale Teilung notwendigen Schritte analog zur Funktion LayoutVertical durch.
| Horizontale Teilung |
|
Die private Memberfunktion SetNewPositions setzt die LayoutMetrics zurück und berechnet die Positionen der Kindfenster analog zu der oben beschriebenen Vorgehensweise neu. Nach dem erneuten Besetzen der LayoutMetrics für die Kindfenster ruft die Funktion TLayoutWindow::Layout() auf, um das aktuelle Layout umzusetzen.
| Memberfunktion: SetNewPositions
|