2015-10-11 2 views
2

Le contenu de la colonne TListView devient incorrect après le changement du thème Windows. Je l'ai réduit au message CM_RECREATE, c'est alors que VCL recrée le handle de fenêtre de TListView en réponse au changement de thème du système. Voici quelques captures d'écran illustrant le problème.Les colonnes TListView commandent un bogue après le changement du thème Windows

de liste originale état

Initial list view state

La dernière colonne a été déplacé déplacé vers la première position. Tout va bien.

Col moved

Après thème Windows a été changé, les colonnes positions sont conservées, cependant, les contenus ne sont plus correctes.

Theme change

Actuellement, je surmonter le problème en recréant simplement les colonnes manuellement dans mon gestionnaire de CM_RECREATEWND personnalisé. Est-ce un bug? C'est une bonne solution pour recréer des colonnes ou existe-t-il un meilleur moyen? J'utilise Delphi10 mais le même comportement a été observé dans les versions précédentes.

+0

Est-ce un comportement auquel vous vous attendez ou ce comportement est-il documenté? Si ce n'est pas le cas, traitez-le comme un bug ou un comportement non documenté et signalez-le à emba pour le corriger ou le documenter –

+0

Votre solution de contournement semble bonne. Vous devriez soumettre un rapport de bogue. –

+0

@Sir Rufo, je suis sûr que c'est un bug. Personne (en particulier les utilisateurs) ne s'attend à de mauvais résultats de colonne après, par exemple, se connecter via Remote Desktop (il déclenche également le WM_SYSCOLORCHANGE et la fenêtre gère les loisirs). – djsoft

Répondre

2

Je vais poster ma solution de contournement au cas où quelqu'un aurait besoin d'une solution rapide pour ce bug. Il suffit d'inclure cette unité comme dernière unité utilisée dans la liste des utilisations d'un formulaire.

unit LVFix; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.Classes, System.UITypes, 
    Vcl.Controls, Vcl.ComCtrls; 

type 
    TListView = class(Vcl.ComCtrls.TListView) 
    strict private 
    type 
    TColumnRec = record 
     Alignment: TAlignment; 
     AutoSize: Boolean; 
     Caption: String; 
     ImageIndex: TImageIndex; 
     MaxWidth, MinWidth, Width: TWidth; 
     Tag: Integer; 
     ID: Integer; 
    end; 
    var 
     FSavedCols: TArray<TColumnRec>; 
     FSavedColOrder: TArray<Integer>; 
    private 
    procedure SaveColumnState; 
    procedure RestoreColumnState; 
    protected 
    procedure CMRecreate(var M: TMessage); message CM_RECREATEWND; 
    end; 

implementation 

uses 
    Winapi.CommCtrl; 

{ TListView } 

procedure TListView.CMRecreate(var M: TMessage); 
begin 
    SaveColumnState; 
    inherited; 
    RestoreColumnState; 
end; 

procedure TListView.RestoreColumnState; 
var 
    I: Integer; 
begin 
    Items.BeginUpdate; //lock to prevent unnecessary events firing 
    try 
    //recreate columns 
    Columns.Clear; 
    for I := 0 to High(FSavedCols) do 
    begin 
     with Columns.Add do 
     begin 
     Alignment := FSavedCols[I].Alignment; 
     AutoSize := FSavedCols[I].AutoSize; 
     Caption := FSavedCols[I].Caption; 
     ImageIndex := FSavedCols[I].ImageIndex; 
     MinWidth := FSavedCols[I].MinWidth; 
     MaxWidth := FSavedCols[I].MaxWidth; 
     Width := FSavedCols[I].Width; 
     Tag := FSavedCols[I].Tag; 
     end; 
    end; 
    //restore column order 
    if Length(FSavedColOrder) <> 0 then 
     ListView_SetColumnOrderArray(Handle, Columns.Count, PInteger(FSavedColOrder)); 
    finally 
    Items.EndUpdate; 
    end; 
end; 

procedure TListView.SaveColumnState; 
var 
    R: LongBool; 
    I: Integer; 
    J: Integer; 
    T: TColumnRec; 
begin 
    //save column order 
    SetLength(FSavedColOrder, Columns.Count); 
    R := ListView_GetColumnOrderArray(Handle, Columns.Count, PInteger(FSavedColOrder)); 
    if not R then 
    SetLength(FSavedColOrder, 0); 
    //save original columns in original order 
    SetLength(FSavedCols, Columns.Count); 
    for I := 0 to Columns.Count - 1 do 
    begin 
    FSavedCols[I].Alignment := Columns[I].Alignment; 
    FSavedCols[I].AutoSize := Columns[I].AutoSize; 
    FSavedCols[I].Caption := Columns[I].Caption; 
    FSavedCols[I].ImageIndex := Columns[I].ImageIndex; 
    FSavedCols[I].MinWidth := Columns[I].MinWidth; 
    FSavedCols[I].MaxWidth := Columns[I].MaxWidth; 
    FSavedCols[I].Width := Columns[I].Width; 
    FSavedCols[I].Tag := Columns[I].Tag; 
    FSavedCols[I].ID := Columns[I].ID; 
    end; 
    for I := 0 to High(FSavedCols) - 1 do 
    for J := I + 1 to High(FSavedCols) do 
     if FSavedCols[J].ID < FSavedCols[I].ID then 
     begin 
     T := FSavedCols[I]; 
     FSavedCols[I] := FSavedCols[J]; 
     FSavedCols[J] := T; 
     end; 
end; 

end.