首页 > 解决方案 > 如何在自定义样式的所有者绘制 TComboBox 中检测 ODS_COMBOBOXEDIT

问题描述

使用德尔福 10.3:

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

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

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.pasTComboBoxStyleHook看来,原因在于以下组合:

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

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

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

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

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

标签: delphivcl-stylestcombobox

解决方案


通过为 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;

推荐阅读