【问题标题】:How to detect ODS_COMBOBOXEDIT in custom styled owner draw TComboBox如何在自定义样式的所有者绘制 TComboBox 中检测 ODS_COMBOBOXEDIT
【发布时间】:2019-09-25 08:40:32
【问题描述】:

使用 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,但这不一样:即使下拉,我希望静态部分的绘制方式与列表中的项目不同。

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

【问题讨论】:

    标签: delphi vcl-styles tcombobox


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2016-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      相关资源
      最近更新 更多