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

nsc4cvqm  于 2023-06-22  发布在  其他
关注(0)|答案(2)|浏览(115)

使用Delphi 10.3:
在所有者绘制的TComboBoxStyle=csOwnerDrawFixed中,我希望下拉列表中所有者绘制的项目与组合的静态部分不同。为了区分这两种情况,我在State参数中检查odComboBoxEdit,如下所述:
How to draw the static part of the combobox

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()组装一个TDrawItemStruct,它将 * 永远 * 不包含ODS_COMBOBOXEDIT,因此CN_DRAWITEM处理程序将永远不会设置odComboBoxEdit
我可以重写TComboBoxStyleHook,但我需要一种方法来检测该项是静态项还是列表中的项。
作为一种变通方法,我检查Combo.DroppedDown,但这并不相同:即使在下拉时,我也希望静态部分的绘制方式与列表中的项目不同。
所以问题是,我如何检测(在自定义绘制处理程序或样式挂钩中)自定义绘制的项是静态区域而不是列表中的项?

ne5o7dgx

ne5o7dgx1#

我可以通过为TComboBox添加一个无条件包含ODS_COMBOBOXEDIT的stylehook来让它工作。假设TComboBoxStyleHook.DrawItemonlyTComboBoxStyleHook.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;
q9rjltbz

q9rjltbz2#

似乎在编辑控件中,TCustomCombobox完成了
procedure CNDrawItem(var Message:();消息CN_DRAWITEM;
它从不调用WM_DRAWITEM,因此一种解决方案是重写该方法(CnDrawItem)。

相关问题