Windows Delphi:ListView(vsReport)具有自定义字体颜色的单列标题?
在具有vsReport ViewStyle的ListView中,如何自定义任何单个列标题的字体颜色?例如(第二列标题为红色字体):Windows Delphi:ListView(vsReport)具有自定义字体颜色的单列标题?,windows,delphi,listview,delphi-xe2,columnheader,Windows,Delphi,Listview,Delphi Xe2,Columnheader,在具有vsReport ViewStyle的ListView中,如何自定义任何单个列标题的字体颜色?例如(第二列标题为红色字体): 您可以从listview获取本机标题控件,然后将列的特定项标记为所有者绘制。当标题项请求绘制时,只需更改文本颜色(如果不删除字符串标志)。绘图消息将被发送到标题的父级-listview,因此您需要在那里处理消息。有关所有者绘制的标题控件,请参见 示例代码: type TForm1 = class(TForm) ListView1: TListView;
您可以从listview获取本机标题控件,然后将列的特定项标记为所有者绘制。当标题项请求绘制时,只需更改文本颜色(如果不删除字符串标志)。绘图消息将被发送到标题的父级-listview,因此您需要在那里处理消息。有关所有者绘制的标题控件,请参见 示例代码:
type
TForm1 = class(TForm)
ListView1: TListView;
procedure FormCreate(Sender: TObject);
...
private
FLVHeader: HWND;
FSaveLVWndProc: TWndMethod;
procedure LVWndProc(var Msg: TMessage);
procedure SetHeaderItemStyle(Index: Integer);
end;
..
uses commctrl;
..
procedure TForm1.FormCreate(Sender: TObject);
begin
FLVHeader := ListView_GetHeader(ListView1.Handle);
SetHeaderItemStyle(1);
FSaveLVWndProc := ListView1.WindowProc;
ListView1.WindowProc := LVWndProc;
end;
procedure TForm1.SetHeaderItemStyle(Index: Integer);
var
HeaderItem: THDItem;
begin
HeaderItem.Mask := HDI_FORMAT or HDI_TEXT or HDI_LPARAM;
Header_GetItem(FLVHeader, 1, HeaderItem);
HeaderItem.Mask := HDI_FORMAT;
HeaderItem.fmt := HeaderItem.fmt or HDF_OWNERDRAW;
Header_SetItem(FLVHeader, 1, HeaderItem);
end;
procedure TForm1.LVWndProc(var Msg: TMessage);
begin
FSaveLVWndProc(Msg); // thanks to @Kobik (cause SO if called later then WM_NOTIFY case on some (all other then mine?) machines)
case Msg.Msg of
WM_DRAWITEM:
if (TWmDrawItem(Msg).DrawItemStruct.CtlType = ODT_HEADER) and
(TWmDrawItem(Msg).DrawItemStruct.hwndItem = FLVHeader) and
(TWmDrawItem(Msg).DrawItemStruct.itemID = 1) then
SetTextColor(TWmDrawItem(Msg).DrawItemStruct.hDC, ColorToRGB(clRed));
WM_NOTIFY:
if (TWMNotify(Msg).NMHdr.hwndFrom = FLVHeader) and
(TWMNotify(Msg).NMHdr.code = HDN_ITEMCHANGED) then
// also try 'HDN_ENDTRACK' if it doesn't work as expected
SetHeaderItemStyle(1);
WM_DESTROY: ListView1.WindowProc := FSaveLVWndProc;
end;
end;
我将在CDDS\u itemprespaint
呈现阶段处理标题通知代码,并使用CDRF\u NEWFONT
返回代码响应此通知消息。以下代码显示了如何扩展列表视图控件,使其具有用于指定标题项字体颜色的事件:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, CommCtrl, StdCtrls;
type
TGetHeaderItemFontColorEvent = procedure(Sender: TCustomListView;
ItemIndex: Integer; var FontColor: TColor) of object;
TListView = class(ComCtrls.TListView)
private
FHeaderHandle: HWND;
FOnGetHeaderItemFontColor: TGetHeaderItemFontColorEvent;
procedure WMNotify(var AMessage: TWMNotify); message WM_NOTIFY;
protected
procedure CreateWnd; override;
published
property OnGetHeaderItemFontColor: TGetHeaderItemFontColorEvent read
FOnGetHeaderItemFontColor write FOnGetHeaderItemFontColor;
end;
type
TForm1 = class(TForm)
ListView1: TListView;
procedure FormCreate(Sender: TObject);
private
procedure GetHeaderItemFontColor(Sender: TCustomListView;
ItemIndex: Integer; var FontColor: TColor);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TListView }
procedure TListView.CreateWnd;
begin
inherited;
FHeaderHandle := ListView_GetHeader(Handle);
end;
procedure TListView.WMNotify(var AMessage: TWMNotify);
var
FontColor: TColor;
NMCustomDraw: TNMCustomDraw;
begin
if (AMessage.NMHdr.hwndFrom = FHeaderHandle) and
(AMessage.NMHdr.code = NM_CUSTOMDRAW) then
begin
NMCustomDraw := PNMCustomDraw(TMessage(AMessage).LParam)^;
case NMCustomDraw.dwDrawStage of
CDDS_PREPAINT:
AMessage.Result := CDRF_NOTIFYITEMDRAW;
CDDS_ITEMPREPAINT:
begin
FontColor := Font.Color;
if Assigned(FOnGetHeaderItemFontColor) then
FOnGetHeaderItemFontColor(Self, NMCustomDraw.dwItemSpec, FontColor);
SetTextColor(NMCustomDraw.hdc, ColorToRGB(FontColor));
AMessage.Result := CDRF_NEWFONT;
end;
else
AMessage.Result := CDRF_DODEFAULT;
end;
end
else
inherited;
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
ListView1.OnGetHeaderItemFontColor := GetHeaderItemFontColor;
end;
procedure TForm1.GetHeaderItemFontColor(Sender: TCustomListView;
ItemIndex: Integer; var FontColor: TColor);
begin
case ItemIndex of
0: FontColor := clRed;
1: FontColor := clGreen;
2: FontColor := clBlue;
end;
end;
end.
整个项目你都可以。下面是上述示例的结果:
@SertacAkyuz:当我尝试调整任何列的大小时,我都会得到AV。@Andreas,谢谢你关于
NMCustomDraw.dwItemSpec
的观点@特拉玛——这让我很难受,事实证明,事实上,这是公平的。回答得好(+1)顺便说一句…@SertacAkyuz,这也是我的第一个想法(因为堆栈溢出)。这没有帮助。@kobik-这是操作系统的一个特性,也被VCL源验证过:在TCustomHeaderControl.CNNotify
中有一个案例分支:HDN\u ITEMCHANGEDA,HDN\u ITEMCHANGEDW:
。VCL也不能冒险使用HDN\u ITEMCHANGED
@TLama,可能是。我刚刚执行了您的EXE并报告了我所看到的:)@kobik,如果您将该列表视图剪切并粘贴到另一个项目,您也会看到同样的结果;-)您可以通过不喜欢的双缓冲
属性来解决此问题,也可以使用虚拟模式解决此问题。我打赌QC中有很多关于它的报告。我明天会在工作中尝试(那里有一个XP系统)。我认为它在那里会工作得很好。测试:在Windows 2000和Vista上工作,但在Windows XP上不工作。即使切换到Xp标准主题。找到解决方案:Condition1:=True;无效竖立(ListView1.FHeaderHandle,无,真)代码>