delphi 64位中的标记属性被错误地用于存储对象引用

ia2d9nvy  于 2023-04-29  发布在  其他
关注(0)|答案(1)|浏览(95)

我正在将32位代码转换为64位代码,其中大量使用了.Tag属性。
其中许多只是用于存储整数值,然后像MyInteger := Component.Tag这样的赋值,尽管形式上是错误的(可能导致范围检查错误),但仍将继续工作。由于这些赋值没有编译器提示/警告,我决定不使用它们。这是我们自己的代码,它首先将整数放入标记中。..
但在其他地方,指向对象的指针被放置在.Tag属性中,例如。例如:

procedure IntervalWeergaveSubMenuToevoegen( AParentMenu : TMenuItem; ACaption : String; AInterval : TcxPivotGridGroupInterval; AField : TcxDBPivotGridField );
var lSubMenuItem : TMenuItem;
begin
  lSubMenuItem := TMenuItem.Create(Self);
  lSubMenuItem.Caption := ACaption;
  lSubMenuItem.ImageIndex := Integer(AInterval);  // (Mis-)use ImageIndex property to store interval
  lSubMenuItem.Tag := Integer(AField);            // (Mis-)use Tag property to store reference to field  THIS ONE!
  lSubMenuItem.GroupIndex := 99;               
  lSubMenuItem.RadioItem := True;
  lSubMenuItem.Checked := (AField.GroupInterval=AInterval);
  lSubMenuItem.OnClick := PopupSubMenuWeergaveClick;
  AParentMenu.Add(lSubMenuItem);
end;

然后PopupSubMenuWeergaveClick接收TMenuItem作为Sender,将.Tag转换回TcxDBPivotGridField

procedure TDialoogDynRapport.PopupSubMenuWeergaveClick(Sender: TObject);
begin
  inherited;
  ExcelPivotGrid.BeginUpdate;
  try                                  // TcxDBPivotGridField reference was put in MenuItem.Tag
    TcxDBPivotGridField(TMenuItem(Sender).Tag).GroupInterval := TcxPivotGridGroupInterval( TMenuItem(Sender).ImageIndex );
  finally
    ExcelPivotGrid.EndUpdate;
  end;
end;

不是很好,我知道。
我看到两条出路:

  • 例程IntervalWeergaveSubMenuToevoegen包含在TDialoogDynRapport方法中,因此我可以给予TDialoogDynRapport一个额外的私有结构来存储TMenuItemTcxDBPivotGridField之间的关联。类似于this
  • 只需将Integer(AField)赋值更改为另一个强制转换。毕竟.Tag现在是8字节,TcxDBPivotGridField的地址也是8字节。

有什么建议吗?
Delphi 11.3,没有多线程,应该可以在Win32中工作。

llew8vvj

llew8vvj1#

您实际上根本不需要“tag”属性。
有一种更好的方法将tMenuitemMap到一个或多个对象。您可以简单地使用tDictionary(=快速查找引擎),它使用tMenuitem作为键。
这里有一个快速而肮脏的例子:

Uses system.generics.collections, ..... ;

var fieldlookup: tDictionary <tMenuitem, TcxDBPivotGridField>;
    intervalLookup: tDictionary <tMenuitem, TcxPivotGridGroupInterval>;

Procedure initialization;
begin
 fieldlookup:=tDictionary <tMenuitem, TcxDBPivotGridField>.Create;
 intervallookup:=tDictionary <tMenuitem, TcxPivotGridGroupInterval>.Create;
end;

Procedure IntervalWeergaveSubMenuToevoegen( 
      AParentMenu : TMenuItem; 
      ACaption : String; 
      AInterval : TcxPivotGridGroupInterval; 
      AField : TcxDBPivotGridField);
var lSubMenuItem : TMenuItem;
begin
     lSubMenuItem := TMenuItem.Create(Self);
     fieldlookup.add(lSubMenuItem, AField);
     intervallookup.add(lSubMenuItem, AInterval);         
     lSubMenuItem.Caption := ACaption; 
     lSubMenuItem.GroupIndex := 99;               
     lSubMenuItem.RadioItem := True;
     lSubMenuItem.Checked := (AField.GroupInterval=AInterval);
     lSubMenuItem.OnClick := PopupSubMenuWeergaveClick;
     AParentMenu.Add(lSubMenuItem);              
end;



procedure TDialoogDynRapport.PopupSubMenuWeergaveClick(
          Sender: TObject);
Var Field:TcxDBPivotGridField; Interval:TcxPivotGridGroupInterval;
begin
  if (fieldlookup.TryGetValue(sender as tmenuitem, Field) and 
  intervallookup.Trygetvalue(sender as tmenuitem, Interval)) then
  begin
   {Field and interval are now known. Insert rest of event handler code here}
  end;
end;

相关问题