TMenuItem *mi = new TMenuItem(this);
mi->OnDrawItem = &miThemesDrawItem;错误结果:
bcc64 Error _TForm1.cpp(280):从不兼容类型‘__closure*’分配给‘Vcl::菜单::TMenuDrawItemEvent’(又名‘_TForm1.cpp ((__closure *))’(System:TObject *,Vcl:图形:TCanvas *,const System:类型::TRect &,bool) __attribute__((Fastcall) (__closure *)(系统:TObject *,Vcl:图形::TCanvas *,系统:类型:TRect &,bool)
函数声明是可以的,事实上,我可以在设计时将它分配给设计时可用的菜单项。
void __fastcall miThemesDrawItem(TObject *Sender, TCanvas *ACanvas, TRect &ARect, bool Selected);我找到了解决办法。我在设计时在分隔项N1上分配了这个处理程序,然后在运行时只执行mi->OnDrawItem = N1->OnDrawItem,因为OnDrawItem没有被调用菜单分隔符,但是我不喜欢这样!
我漏掉了什么,怎么分配这个处理程序?
发布于 2022-01-27 20:28:02
函数声明是可以的
事实上,事实并非如此。请非常密切地注意错误消息告诉您的内容:
分配给‘Vcl::菜单::TMenuDrawItemEvent’.从不相容类型.‘
那么,为什么miThemesDrawItem()不兼容呢?因为它的类型与TMenuDrawItemEvent所期望的不同!
让我们先看看TMenuDrawItemEvent。错误消息显示其类型为:
void ((__closure *))(System::TObject *, Vcl::Graphics::TCanvas *, const System::Types::TRect &, bool) __attribute__((fastcall))我们现在可以忽略__attribute__,因此类型是:
void (__closure *)(System::TObject *, Vcl::Graphics::TCanvas *, const System::Types::TRect &, bool)与TMenuDrawItemEvent在Vcl.Menus.hpp中的实际声明相匹配。
typedef void __fastcall (__closure *TMenuDrawItemEvent)(System::TObject* Sender, Vcl::Graphics::TCanvas* ACanvas, const System::Types::TRect &ARect, bool Selected);现在,让我们看看您的miThemesDrawItem()。错误消息显示其类型为:
void (__closure *)(System::TObject *, Vcl::Graphics::TCanvas *, System::Types::TRect &, bool)这与您的实际声明相符:
void __fastcall miThemesDrawItem(TObject *Sender, TCanvas *ACanvas, TRect &ARect, bool Selected);注意到声明类型的TMenuDrawItemEvent与声明类型的miThemesDrawItem()之间有什么区别吗?TRect参数在miThemesDrawItem()中不被声明为const!
您需要声明miThemesDrawItem(),使其具有与TMenuDrawItemEvent声明方式完全相同的签名,例如:
void __fastcall miThemesDrawItem(TObject* Sender, TCanvas* ACanvas, const TRect &ARect, bool Selected);,实际上我可以在设计时将它分配给设计时可用的菜单项。
这本身并不能保证miThemesDrawItem()与TMenuItem::OnDrawItem事件100%兼容。尽管当用户试图在设计时将事件处理程序的类型分配给事件时,IDE确实验证了事件处理程序的类型,但IDE在这一问题上有些宽容。在执行验证时,IDE依赖于RTTI,而RTTI是基于Delphi信息,而不是C++信息。Const-正确性在Delphi中的工作方式与在C++中略有不同。因此,有时IDE确实允许不兼容的处理程序通过,特别是为了向后兼容性(即,TMenuDrawItemEvent的TMenuDrawItemEvent参数并不总是const)。
在验证之后,IDE只是将事件处理程序的名称存储到DFM中,但是实际的函数直到运行时才分配给事件(因为在设计时不知道它的内存地址)。当DFM在运行时被流入时,当函数被分配给事件时,函数的类型将不再被验证,而是被盲目地视为- is。因此,即使在运行时,如果处理程序与事件不能100%兼容,也可能会出现微妙的问题。
另一方面,编译器要求函数的类型与指定给它的函数指针100%兼容。没有任何分歧的余地。因此,在本例中,参数上的const限定符的差异是一个大的不-不。这就是为什么编译器不允许将miThemesDrawItem()分配给代码中的TMenuItem::OnDrawItem事件,直到您修复miThemesDrawItem()的签名以与TMenuDrawItemEvent的类型完全匹配。
https://stackoverflow.com/questions/70884729
复制相似问题