如何在自定义样式的所有者绘制 TComboBox 中检测ODS_COMBOBOXEDIT



使用 Delphi 10.3:

在带有Style=csOwnerDrawFixed的所有者绘制TComboBox中,我希望下拉列表中的所有者绘制的项目与组合的静态部分不同。为了区分这两种情况,我在State参数中检查odComboBoxEdit,如下所述:

如何绘制组合框的静态部分

procedure TStylePanel.TargetArrowComboDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
if (odComboBoxEdit in State) then
begin
// Paint static control
end
else
begin
// Paint item in dropped down list
end;
end;

只要没有激活的自定义 VCL 样式,这就可以很好地工作。但是,对于自定义样式,这不再可靠。检查Vcl.StdCtrls.pas中的来源以获取TComboBoxStyleHook,在我看来,原因在于这种组合:

procedure TComboBoxStyleHook.WMPaint(...)
procedure TComboBoxStyleHook.DrawItem(...)

当没有编辑句柄时(csOwnerDrawFixed就是这种情况(,DrawItem()组装一个永远不会包含ODS_COMBOBOXEDITTDrawItemStruct,因此CN_DRAWITEM处理程序永远不会设置odComboBoxEdit

我可以覆盖TComboBoxStyleHook,但我需要一种方法来检测该项目是静态项目还是列表中的项目。

作为一种解决方法,我检查Combo.DroppedDown,但这并不相同:即使下拉,我也希望静态部分的绘制方式与列表中的项目不同。

所以问题是,如何检测(在自定义绘制处理程序或样式钩子中(自定义绘制项是静态区域而不是列表中的项?

我能够通过为 TComboBox 添加一个无条件包含ODS_COMBOBOXEDIT的样式钩子来让它工作。假设TComboBoxStyleHook.DrawItem仅在需要自定义绘制静态项时由TComboBoxStyleHook.WMPaint调用,下拉列表中不在那里处理。似乎没有不必要的副作用。

type
TComboBoxStyleHookFix = class(TComboBoxStyleHook)
strict protected
procedure DrawItem(Canvas: TCanvas; Index: Integer; const R: TRect; Selected: Boolean); override;
end;
procedure TComboBoxStyleHookFix.DrawItem(Canvas: TCanvas; Index: Integer; const R: TRect; Selected: Boolean);
var
DIS: TDrawItemStruct;
begin
FillChar(DIS, SizeOf(DIS), 0);
DIS.CtlType := ODT_COMBOBOX;
DIS.CtlID := GetDlgCtrlID(Handle);
DIS.itemAction := ODA_DRAWENTIRE;
DIS.hDC := Canvas.Handle;
DIS.hwndItem := Handle;
DIS.rcItem := R;
DIS.itemID := Index;
DIS.itemData := SendMessage(ListHandle, LB_GETITEMDATA, 0, 0);
if (Control is TComboBox) and (TComboBox(Control).Style = csOwnerDrawFixed) then
DIS.itemState := ODS_COMBOBOXEDIT;
if Selected then
DIS.itemState := DIS.itemState or ODS_FOCUS or ODS_SELECTED;
SendMessage(Handle, WM_DRAWITEM, Handle, LPARAM(@DIS));
end;
procedure InitComboStyleHookFix();
begin
TCustomStyleEngine.RegisterStyleHook(TComboBox, TComboBoxStyleHookFix);
end;

似乎在编辑控件中,TCustomCombobox 完成了所有工作

过程 CNDrawItem(var Message: TWMDrawItem(; 消息CN_DRAWITEM;

它从不调用WM_DRAWITEM,因此一种解决方案是重写该方法(CnDrawItem(。

相关内容

  • 没有找到相关文章

最新更新