delphi cxgrid 过滤列表增加右键

发布时间 2023-12-20 09:13:48作者: Tag

首先弹出来的下拉过滤列表也是一个form

思路,在不改源代码的情况:hook,捕捉  WM_SHOWWINDOW  消息,通过源码得知窗口类名 为”TcxGridFilterPopup“ 
再通过句柄转得到实例,同时在本单元type 一下新的 TcxGridFilterPopup, TcxGridPopupListBox 才能访问保护起来的方法跟属性

 CallWndProcHook:HHOOK;
 CurrentcxGridFilterPopup: TcxGridFilterPopup;
 pm_cxgrid_filter_choose:TPopupMenu;

initialization
initcxgrid_filter_Menus;
CallWndProcHook := SetWindowsHookEx(WH_CALLWNDPROC, @HookCallWndProc, 0, GetCurrentThreadID);



finalization
if CallWndProcHook > 0 then
UnHookWindowsHookEx(CallWndProcHook);
pm_cxgrid_filter_choose.Free;

 

type
TMycxGridFilterPopup = class(TcxGridFilterPopup)
end;


TMycxGridPopupListBox = class(TcxGridPopupListBox)
end;

 

function GetInstanceFromhWnd(const hWnd: Cardinal): TWinControl;
type
 PObjectInstance = ^TObjectInstance;
 TObjectInstance = packed record
   Code: Byte;            { 短跳转 $E8 }
   Offset: Integer;       { CalcJmpOffset(Instance, @Block^.Code); }
   Next: PObjectInstance; { MainWndProc 地址 }
   Self: Pointer;         { 控件对象地址 }
 end;
var
 wc: PObjectInstance;
begin
 Result := nil;
 wc     := Pointer(GetWindowLong(hWnd, GWL_WNDPROC));
 if wc <> nil then
 begin
   Result := wc.Self;
 end;
end;

function HookCallWndProc(code: Integer; wParam: wParam; lParam: lParam): LRESULT; stdcall;
var
cwp : PCwpStruct;
lpClassName: array [0..MAX_PATH] of Char;
tmpobjct:TWinControl;
begin
if code = HC_Action then
begin
cwp := PCwpStruct(lParam);
case cwp^.message of
WM_SHOWWINDOW:
begin
try
GetClassName(cwp.hwnd, lpClassName, MAX_PATH);
if lpClassName= 'TcxGridFilterPopup' then
begin
tmpobjct := GetInstanceFromhWnd(cwp.hwnd);
if (tmpobjct <> nil) then
begin
if TcxGridFilterPopup(tmpobjct).PopupMenu = nil then
TcxGridFilterPopup(tmpobjct).PopupMenu := pm_cxgrid_filter_choose;
CurrentcxGridFilterPopup := TcxGridFilterPopup(tmpobjct);
end;
end;
except
on e:exception do
Error_File(DataModule1.qry1.FieldByName('xm').AsString+ ' 添加过滤右键错误: '+ e.Message );
end;
end;
end;
end;
Result := CallNextHookEx(CallWndProcHook, code, wParam, lParam);
end;

procedure initcxgrid_filter_Menus;
var
 tmpItem: TMenuItem;
begin
 pm_cxgrid_filter_choose := TPopupMenu.Create(nil);
 tmpItem := TMenuItem.Create(pm_cxgrid_filter_choose);
 tmpItem.Caption := '全选';
 tmpItem.Tag := 1;
 tmpItem.OnClick := MyEventClass.SetcxGridFilterListChecked;
 pm_cxgrid_filter_choose.Items.Add(tmpItem);

 tmpItem := TMenuItem.Create(pm_cxgrid_filter_choose);
 tmpItem.Caption := '反选';
 tmpItem.Tag := 2;
 tmpItem.OnClick := MyEventClass.SetcxGridFilterListChecked;
 pm_cxgrid_filter_choose.Items.Add(tmpItem);
end;

procedure TMyEventClass.SetcxGridFilterListChecked(Sender:Tobject);
var
Item: TcxCustomGridTableItem;
i,Len:integer;
FValueList: TcxGridFilterValueList;
AActiveValueIndexes: TcxGridIndexes;
MycxGridPopupListBox: TMycxGridPopupListBox;
Choose:Boolean;
begin
if CurrentcxGridFilterPopup = nil then
Exit;
Choose := TMenuItem(Sender).Tag = 1;
Item := CurrentcxGridFilterPopup.Item;
MycxGridPopupListBox := TMycxGridPopupListBox(TMycxGridFilterPopup(CurrentcxGridFilterPopup).ListBox);
case Choose of
False:
begin
Item.Filtered := False;
//要同步状态不然下拉的列表不会刷新
for i := 0 to MycxGridPopupListBox.Count -1 do
begin
if MycxGridPopupListBox.HasCheck(i) then
MycxGridPopupListBox.Checked[i] := False;
end;
end;
True:
begin
try
FValueList := Item.GridView.ViewData.CreateFilterValueList;
//获取下拉内容
Item.DataBinding.GetFilterValues(FValueList, False,True,True);
Len := 0;
for I := 0 to FValueList.Count -1 do
begin
if not (FValueList[i].Kind in [fviAll, fviCustom]) then
begin
inc(Len);
SetLength(AActiveValueIndexes, Len);
AActiveValueIndexes[Len-1] := i;
MycxGridPopupListBox.Checked[i] := False;
MycxGridPopupListBox.DoAction(i);
end;
end;
finally
FValueList.Free;
end;
end;
end;
end;