Jörg Siebrands
Die Website wurde mit de Standard-Version des Webeditors "WebAdditor" erstellt
Delphi (2) - PageControl-TabSheet mit Schließen-Button
Wenn man mehrere Seiten platzsparend in einem Fenster darstellen möchte bietet sich die PageControl-Komponente an. Hier wird dann einfach jede Seite durch ein eigenes Register dargestellt. Leider fehlt in Delphi aber eine visuelle Möglichkeit um einzelne Seiten zu schließen.

Eine Möglichkeit wäre neben dem Seitennamen, der in der Caption-Eigenschaft der TabSheets steht, zusätzlich noch ein Bild mit einem entsprechenden Symbol (z. B. ein rotes Kreuz) anzuzeigen. Dazu benötigt man eine ImageList-Komponente in der dann in diesem Fall für jede Seite ein Bild eingefügt wird - in diesem Fall wäre es allerdings immer das gleiche Bild. Man müßte dann beispielsweise im Ereignis 'OnMouseDown' des PageControls die Maus-Koordinaten auswerten bzw. die Koordinaten speichern und im 'OnChange'-Ereignis auswerten.
Allerdings wird das Bild auf der linken Seite angezeigt - üblich für das Schließen-Symbol ist aber eher die rechte Seite. Um das Kreuz zum Schließen der Seite rechts anzuzeigen könnte man den in der Eigenschaft 'Caption' stehenden Text in die Grafik integrieren. Das hat allerdings den Nachteil, dass man den Text nicht während der Laufzeit ändern kann - die Namen der einzelnen Seiten müßten bereits feststehen.


Hier soll eine andere Möglichkeit aufgezeigt werden. Für das Schließen der Register habe ich einfach einen SpeedButton erstellt. Statt eine Grafik einzubinden habe ich ein 'X' als Caption eingegeben und die Breite und Höhe auf 12 Pixel gesetzt. Man kann diese Werte natürlich nach Belieben auch anders einstellen. Bei den Seitennamen habe ich in der Eigenschaft 'Caption' bei den einzelnen TabSheets 4 Leerzeichen zusätzlich eingegeben um Platz für den SpeedButton zu schaffen. Außerdem wurde die Eigenschaft 'Visible' des Buttons auf 'false' gesetzt.

Für das Positionieren des Buttons habe ich eine eigene Prozedur geschrieben, da die Positionierung an verschiedenen Stellen im Programm benötigt wird. Um die richtige Position im PageControl zu ermitteln wird die Eigenschaft 'TabRect[index]' der PageControl-Komponente benötigt. Index steht für das betreffende Register - der Index des aktiven TabSheets steht in der Eigenschaft TabIndex des PageControls. TabRect[Index] ist vom Typ TRect und liefert die Position des Rechtecks für den Tab-Bereich (der Bereich wo der Seitenname steht).

Die Routine mit dem Namen 'SetCloseButton' wird dem Formular hinzugefügt. Wenn noch Seiten vorhanden sind wird der Button an die richtige Position platziert und sichtbar geschaltet. Sind keine Seiten vorhanden wird der Button unsichtbar geschaltet:

procedure TForm1.SetCloseButton;
begin
  if (PageControl1.PageCount > 0) then begin
    SpeedButton1.Top := PageControl1.TabRect(PageControl1.ActivePageIndex).Top+2;
    SpeedButton1.Left := PageControl1.TabRect(PageControl1.ActivePageIndex).Right-14;
    SpeedButton1.Visible := true;
  end else begin
    SpeedButton1.Visible := false;
  end;
end;

Mit einem Doppelclick auf den Button wird der Rumpf für den Quelltext der Ereignisbehandlungsroutine zum Schließen des aktiven Registers erstellt: Hier wird zunächst der Button unsichtbar geschaltet da sonst nach dem Löschen der Seite - zumindestens in Delphi 7 - ein zweiter Button erscheint. Anschließend wird die Seite freigegeben und die Routine 'SetCloseButton' aufgerufen um den Button auf dem Tab der nun sichtbaren Seite zu plazieren:

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  SpeedButton1.Visible := false;
  PageControl1.ActivePage.Free;
  SetCloseButton;
end;

Damit der Button beim Seitenwechsel auf dem richtigen Tab positioniert wird muss die Routine 'SetCloseButton' auch im Ereignis 'OnChange' des PageControls aufgerufen werden:

procedure TForm1.PageControl1Change(Sender: TObject);
begin
  SetCloseButton;
end;

Im 'OnCreate'-Ereignis des Formulars wird nun noch der SpeedButton dem PageControl zugewiesen und 'SetCloseButton' für das erste Positionieren des Buttons aufgerufen:

procedure TForm1.FormCreate(Sender: TObject);
begin
  SpeedButton1.Parent := PageControl1;
  SetCloseButton;
end;

Zum Testen habe ich noch einen Button zum Erstellen einer neuen Seite erstellt. Im 'OnClick'-Ereignis des Buttons wird ein TabSheet erzeugt, dem TabSheet ein Name zugewiesen und anschließend die neue Seite dem PageControl hinzugefügt. Der Name enthält dabei die Index-Position des Tabs. Zum Schluss wird noch 'SetCloseButton' aufgerufen, ansonsten wäre in diesem Fall der Button nicht zu sehen.

procedure TForm1.Button1Click(Sender: TObject);
var
  NewTabSheet: TTabSheet;
begin
  NewTabSheet := TTabSheet.Create(PageControl1);
  NewTabSheet.Caption := 'Seite ' + IntToStr(PageControl1.PageCount+1)+ '    ';
  NewTabSheet.PageControl := PageControl1;
  SetCloseButton;
end;

Damit immer alle Tabellenreiter angezeigt werden, auch wenn diese nicht alle nebeneinander passen, kann man "MultiLine" von PageControl1 noch auf "true" stellen.

Das Projekt wurde in Delphi 7 getestet die Methode wird aber auch in einem Delphi-XE2-Projekt von mir genutzt. Die Delphi7-Projektdateien können hier als ZIP-Datei heruntergeladen werden:

TabSheetClose.zip