Einzelnen Beitrag anzeigen

Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#9

AW: ListView Breite der letzten Spalte beim Resize der Form

  Alt 25. Okt 2023, 00:30
Erstmal ein Dankeschön fürs Mitdenken und Mitmachen an alle Beteiligten .

Inzwischen hab ich die Sache für mich zufriedenstellend gelöst. Ich stelle mal hier den Code mit etwas Erklärung ein, damit es auch anderen weiterhelfen kann.

Die Grundlage bilden die Ereignisse OnResize und OnCanResize des ListView. OnCanResize wird vor dem Resize eines Controls ausgelöst, OnResize danach. OnResize verwende ich schon von Beginn an, OnCanResize ist in TControl als protected property deklariert und daher nicht direkt zuweis- und nutzbar. Um dies zu umgehen, hab ich mir eine kleine Unit geschrieben:
Delphi-Quellcode:
unit VCLHacks;

interface

uses ComCtrls, Controls;

type
  TMyListView = class(TListView)
  end;

procedure ListView_SetOnCanResize(const AListView: TListView; const AOnCanResize: TCanResizeEvent);

implementation

procedure ListView_SetOnCanResize(const AListView: TListView; const AOnCanResize: TCanResizeEvent);
begin
    TMyListView(AListView).OnCanResize:= AOnCanResize;
end;

end.
Hinweis:
Die nachfolgenden Code-Auszüge sind fürs Forum vereinfachte und verkürzte Beispiele. Im eigentlichen Programm gibt viele in einer TList gespeicherte ListViews, die alle dieselben Eigenschaften und Events zugewiesen bekommen.

Beim Starten werden die Eigenschaften und Ereignisse zugewiesen:
Delphi-Quellcode:
procedure TfmMain.FormCreate(Sender: TObject);
begin
    FScrollBarSize:= Windows.GetSystemMetrics(SM_CXVSCROLL);
    if ListView1.Columns.Count > 0 then
        ListView1.Columns[ListView1.Columns.Count-1].AutoSize:= True;
end;

procedure TfmMain.FormShow(Sender: TObject);
begin
    SetListViewEvents(ListView1);
end;

procedure TfmMain.SetListViewEvents(const AListView: TListView);
begin
    if NOT Assigned(AListView) then Exit;
    AListView.OnResize:= ListViewResize;
    ListView_SetOnCanResize(AListView, ListViewCanResize);
end;
Die Behandlung der Ereignisse sieht so aus:
Delphi-Quellcode:
procedure TfmMain.ListViewCanResize(Sender: TObject; var NewWidth, NewHeight: Integer; var Resize: Boolean);
var
  Llv: TListView;
  Lcol: TListColumn;
  Ltotalcolwidth, i: integer;
begin
    if FListViewItemsUpdating then Exit;
    if NOT (Sender is TListView) then Exit;
    Llv:= TListView(Sender);

    Ltotalcolwidth:= 0;
    for i:= 0 to Pred(Llv.Columns.Count) do
        Inc(Ltotalcolwidth, ListView_GetColumnWidth(Llv.Handle, i));

    Lcol:= Llv.Columns[Llv.Columns.Count-1];
    Lcol.AutoSize:= ((Ltotalcolwidth - FScrollBarSize) <= Llv.ClientWidth);
end;
AutoSize der letzten Spalte wird ausgeschaltet, wenn die Summe der Breite aller Spalten größer ist als die sichtbare Breite des ListView (ClientWidth). AutoSize wird wieder aktiviert, wenn die Summe der Breite der Spalten maximal so groß ist wie ClientWidth zulässt. Dadurch wird die letzte Spalte nicht mehr schmaler, wenn andere Spalten vergrößert werden und anschließend das ListView in der Breite verändert wird.

Da die ListViews während der Programmlaufzeit mit immer wieder neuen Daten gefüllt werden können, erscheint ggf. ein vertikaler Scrollbalken, was einen horizontalen Scrollbalken aktiviert. Um das zu behandeln, mache ich mir das im OnShow zugewiesene OnResize-Ereignis zunutze:
Delphi-Quellcode:
procedure TfmMain.ListViewResize(Sender: TObject);
var
  Llv: TListView;
begin
    Llv:= nil;
    if Sender is TListView then
        Llv:= (Sender as TListView);
    if Assigned(Llv) then
        ListViewAdjustLastColumnWidth(Llv);
end;

procedure TfmMain.ListViewAdjustLastColumnWidth(const AListView: TListView);
var
  Ltotalcolwidth, Lcolwidth, i: integer;
  Lcol: TListColumn;
begin
    if NOT Assigned(AListView) then
        Exit;

    Ltotalcolwidth:= 0;
    for i:= 0 to Pred(AListView.Columns.Count) do
        Inc(Ltotalcolwidth, ListView_GetColumnWidth(AListView.Handle, i));

    Lcol:= AListView.Columns[AListView.Columns.Count-1];
    Lcolwidth:= ListView_GetColumnWidth(AListView.Handle, Lcol.Index);
    if ((Ltotalcolwidth - FScrollBarSize) = AListView.ClientWidth) then begin
        Lcolwidth:= Lcolwidth - FScrollBarSize;
        ListView_SetColumnWidth(AListView.Handle, Lcol.Index, Lcolwidth);
        Exit;
    end;
    // [...]
end;
Die letzte Spalte wird verkleinert, wenn die Summe aller Spaltenbreiten die ClientWidth des ListViews um eine Scrollbalken-Breite überschreitet. Dadurch verschwindet der horizontale Scrollbalken wieder.

Grüße
Dalai

Geändert von Dalai (25. Okt 2023 um 00:37 Uhr)
  Mit Zitat antworten Zitat