Den Splitter nutzen


Um den Splitter nun verwenden zu können, müssen Sie kurz die Funktionsweise überdenken:

  1. Die linke Maustaste wird gedrückt und muss gedrückt gehalten werden.

  2. Bei gedrückt gehaltener Maustaste wird die Maus in die gewünschte Richtung verschoben, wobei die aktuelle Splitterposition meist durch eine Art Schatten kenntlich gemacht wird.

  3. Ist die neue Position erreicht, wird die Maustaste losgelassen, und die von der Änderung betroffenen Controls werden entsprechend angepasst.

Damit wäre der Weg eigentlich schon vorgegeben.

Zuerst reagieren Sie auf den Druck der linken Maustaste. Die entsprechende Nachricht heißt "WM_LBUTTONDOWN", und sie liefert die aktuellen Koordinaten im lParam zurück. Die Vorgehensweise unterscheidet sich für den vertikalen und horizontalen Splitter nur in Details, der Code ist so gesehen aber identisch. Darum hier die Erklärung für den vertikalen Splitter, der Tree-View und List-View trennt.
Wie gesagt, Sie benötigen zuerst einmal die aktuelle Position des Mauszeigers. Beim vertikalen Splitter ist dabei die X-Koordinate im niederwertigen word wichtig:

x := LOWORD(lp);

Wenn die Position des Mauszeigers innerhalb der Splitterposition liegt,

if(x >= vSplitPos) and (x <= vSplitPos + SPLITWIDTH) then
begin

dann setzen Sie den entsprechenden Cursor und sorgen mit "SetCapture" dafür, dass die Mausnachrichten nur an das eigene Fenster geleitet werden.

  SetCursor(LoadCursor(0,IDC_SIZEWE));
  SetCapture(wnd);

Diese Funktion wurde übrigens auch schon beim Drag&Drop des Tree-View angesprochen.

Der nächste Schritt ist der oben erwähnte "Schatten". Ich möchte es auch weiterhin so bezeichnen. Gemeint ist damit natürlich die Schraffur, die Sie mit der Maus verschieben, und die die dann neue Position des Splitters kennzeichnet. Für diesen Schatten habe ich die Funktion "DrawTrackSplit" von Eugen 1:1 übernommen

  DrawTrackSplit(wnd,vSplitPos,0,SPLITWIDTH,hSplitPos);

Außerdem ist wichtig, dass Sie die bool'sche Variable für den vertikalen Splitter setzen. Das ist das interne Signal, dass das Verschieben der Controls begonnen hat:

  fVTrackSplit := true;
end


Der nächste Schritt führt uns zurück zur "WM_MOUSEMOVE"-Nachricht, denn natürlich muss die Maus bewegt werden um dem Splitter eine neue Position zu geben. Im vorigen Kapitel wurde gezeigt, wie man diese Nachricht zur Kennzeichnung des Splitters nutzt. An der Stelle genügt eine Erweiterung für den vertikalen oder horizontalen Splitter, der sich nach dem Status der dazu gehörenden bool-Variablen richtet.

Wie ich bereits sagte, wird beim Druck auf die linke Maustaste ermittelt, ob die aktuellen Koordinaten der Maus zu einem der Splitter passen. Das obige Beispiel demonstrierte Ihnen das für den vertikalen Splitter. Also bleiben wir auch dabei und gehen davon aus, dass dieser Splitter benutzt werden soll.
In diesem Fall ist die Variable "fVTrackSplit" true, wovon wir die folgenden Codezeilen abhängig machen:

if(fVTrackSplit) then
begin

Zuerst stellen wir sicher, dass der Splitter nicht zu weit bewegt werden kann. Das bringt mich wieder auf die Konstanten, die ich eingangs deklariert habe. Wenn Sie also die Grenze des jeweiligen Splitters unterschreiten, bleibt der Schatten des Splitters auf der letztmöglichen Position stehen:

  if(x < MINVSPLIT) then x := MINVSPLIT
    else if(x > rc.Right - MINVSPLIT) then x := rc.Right - MINVSPLIT;

Eugen hat an dieser Stelle in seiner Demo einen recht witzigen Snap-Effekt, d.h. wenn Sie einen bestimmten Wert unterschreiten, springt der Splitter regelrecht an den jeweiligen Rand. Diesen Effekt können Sie sehen, wenn Sie in der Zeile

{.$DEFINE SNAPFX}

den Punkt entfernen und so den Compilerschalter aktivieren. Die technische Umsetzung dieses Effekts sollte eigentlich kein Problem sein: Sie prüfen lediglich ob ein bestimmter Schwellenwert erreicht bzw. unterschritten wurde und setzen die jeweilige Koordinate dann einfach auf den kleinsten möglichen Wert, etwa

  if(x < rc.Left + 50) then x := rc.Left + SPLITWIDTH
    else if(x > rc.Right - 50) then x := rc.Right - SPLITWIDTH;


Wenn Sie nun bemerken, dass die Position des Splitters (in dem Fall "vSplitPos") nicht mehr mit der jeweils ermittelten Koordinate übereinstimmt

  if(vSplitPos + 1 <> x) then
  begin

dann entfernen Sie zuerst den Schatten des Splitters an der aktuellen Position. Das lässt sich einfach dadurch erreichen, dass Sie die schon erwähnte Funktion "DrawTrackSplit" erneut aufrufen. Die beiden so erzeugten Grafiken (das steckt eigentlich dahinter) heben sich dadurch gegenseitig auf

    DrawTrackSplit(wnd,vSplitPos,0,SPLITWIDTH,hSplitPos);

Dann passen Sie die Position an und zeichnen den Schatten an der neuen Position

    inc(vSplitPos,x - vSplitPos - 1);
    DrawTrackSplit(wnd,vSplitPos,0,SPLITWIDTH,hSplitPos);
  end;
end


Der nächste Schritt: Sie haben die gewünschte Position erreicht und lassen die Maustaste wieder los. In dem Fall rufen wir einfach nur "ReleaseCapture", damit die Mausnachrichten wieder normal verarbeitet werden und nicht mehr auf unser Fenster beschränkt sind. Die dafür zu bearbeitende Nachricht heißt "WM_LBUTTONUP"

WM_LBUTTONUP:
  if fVTrackSplit or fHTrackSplit then
    ReleaseCapture;

Und das bringt uns direkt zum letzten Schritt: Wenn wir "ReleaseCapture" aufrufen, dann sendet das System die Nachricht "WM_CAPTURECHANGED", die wir uns zunutze machen. In unserem Beispiel ist nach wie vor der vertikale Splitter aktiv, erkennbar am Status true der Variablen "fVTrackSplit". Wenn dies der Fall ist, dann entfernen wir zunächst den Schatten des Splitters

if(fVTrackSplit) then
begin
  DrawTrackSplit(wnd,vSplitPos,0,SPLITWIDTH,hSplitPos);

und senden dann einfach "WM_SIZE" an unsere Anwendung. Dadurch lösen wir das Neuzeichnen bzw. das Neuanordnen der Controls aus, das anfangs bereits angesprochen wurde

  SendMessage(wnd,WM_SIZE,0,0);

Und natürlich muss die bool-Variable auch wieder zurückgesetzt werden, weil die Arbeit mit dem Splitter an der Stelle ja beendet ist

  fVTrackSplit:= false;
end;