【问题标题】:TListView columns order bug after windows theme changeWindows主题更改后TListView列顺序错误
【发布时间】:2015-10-11 11:11:07
【问题描述】:

windows 主题更改后,TListView 的列内容不正确。我已将其缩小到 CM_RECREATE 消息,即 VCL 重新创建 TListView 的窗口句柄以响应系统主题更改。下面是一些说明问题的屏幕截图。

原始列表视图状态

最后一列已移至第一位置。一切正常。

Windows 主题更改后,列位置保留,但内容不再正确

目前,我只需在自定义 CM_RECREATEWND 处理程序中手动重新创建列即可解决此问题。它是一个错误吗?重新创建列是一个很好的解决方案还是有更好的方法?

我使用的是 Delphi10,但在以前的版本中也观察到了相同的行为。

【问题讨论】:

  • 这是您期望的行为还是记录在案?如果不是,则将其视为错误或未记录的行为并将其报告给 emba 以修复或记录它
  • 您的解决方法听起来不错。您应该提交错误报告。
  • @Sir Rufo,我很确定这是一个错误。没有人(尤其是用户)期望在例如之后出现错误的列内容。通过远程桌面连接(它还会触发 WM_SYSCOLORCHANE 和窗口句柄重新创建)。
  • @David 可以。我发布了一个问题,以确保它确实是一个错误,而不是我错过了什么:)
  • 好吧,在我的一些错误报告中,我要求修复或记录该行为,只是为了确保它不会因“按设计工作”而关闭。他们可以选择错误是在代码中还是在文档中。但是在文档中描述一个奇怪的行为通常比修复需要更多的时间;o)

标签: delphi tlistview delphi-10-seattle


【解决方案1】:

如果有人需要快速修复此错误,我将发布我的解决方法。只需将此单元作为最后使用的单元包含在表单的使用列表中即可。

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.

【讨论】:

    猜你喜欢
    • 2011-12-06
    • 2022-08-14
    • 1970-01-01
    • 2013-07-14
    • 2010-12-26
    • 2019-04-11
    • 2018-10-30
    • 2012-11-05
    • 2016-06-17
    相关资源
    最近更新 更多