首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在OnDrawItem中动态地为TMenuItem分配C++Builder

在OnDrawItem中动态地为TMenuItem分配C++Builder
EN

Stack Overflow用户
提问于 2022-01-27 19:38:52
回答 1查看 72关注 0票数 0
代码语言:javascript
复制
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)

函数声明是可以的,事实上,我可以在设计时将它分配给设计时可用的菜单项。

代码语言:javascript
复制
void __fastcall miThemesDrawItem(TObject *Sender, TCanvas *ACanvas, TRect &ARect, bool Selected);

我找到了解决办法。我在设计时在分隔项N1上分配了这个处理程序,然后在运行时只执行mi->OnDrawItem = N1->OnDrawItem,因为OnDrawItem没有被调用菜单分隔符,但是我不喜欢这样!

我漏掉了什么,怎么分配这个处理程序?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-27 20:28:02

函数声明是可以的

事实上,事实并非如此。请非常密切地注意错误消息告诉您的内容:

分配给‘Vcl::菜单::TMenuDrawItemEvent’.从不相容类型.‘

那么,为什么miThemesDrawItem()不兼容呢?因为它的类型与TMenuDrawItemEvent所期望的不同!

让我们先看看TMenuDrawItemEvent。错误消息显示其类型为:

代码语言:javascript
复制
void ((__closure *))(System::TObject *, Vcl::Graphics::TCanvas *, const System::Types::TRect &, bool) __attribute__((fastcall))

我们现在可以忽略__attribute__,因此类型是:

代码语言:javascript
复制
void (__closure *)(System::TObject *, Vcl::Graphics::TCanvas *, const System::Types::TRect &, bool)

TMenuDrawItemEventVcl.Menus.hpp中的实际声明相匹配。

代码语言:javascript
复制
typedef void __fastcall (__closure *TMenuDrawItemEvent)(System::TObject* Sender, Vcl::Graphics::TCanvas* ACanvas, const System::Types::TRect &ARect, bool Selected);

现在,让我们看看您的miThemesDrawItem()。错误消息显示其类型为:

代码语言:javascript
复制
void (__closure *)(System::TObject *, Vcl::Graphics::TCanvas *, System::Types::TRect &, bool)

这与您的实际声明相符:

代码语言:javascript
复制
void __fastcall miThemesDrawItem(TObject *Sender, TCanvas *ACanvas, TRect &ARect, bool Selected);

注意到声明类型的TMenuDrawItemEvent与声明类型的miThemesDrawItem()之间有什么区别吗?TRect参数在miThemesDrawItem()中不被声明为const

您需要声明miThemesDrawItem(),使其具有与TMenuDrawItemEvent声明方式完全相同的签名,例如:

代码语言:javascript
复制
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确实允许不兼容的处理程序通过,特别是为了向后兼容性(即,TMenuDrawItemEventTMenuDrawItemEvent参数并不总是const)。

在验证之后,IDE只是将事件处理程序的名称存储到DFM中,但是实际的函数直到运行时才分配给事件(因为在设计时不知道它的内存地址)。当DFM在运行时被流入时,当函数被分配给事件时,函数的类型将不再被验证,而是被盲目地视为- is。因此,即使在运行时,如果处理程序与事件不能100%兼容,也可能会出现微妙的问题。

另一方面,编译器要求函数的类型与指定给它的函数指针100%兼容。没有任何分歧的余地。因此,在本例中,参数上的const限定符的差异是一个大的不-不。这就是为什么编译器不允许将miThemesDrawItem()分配给代码中的TMenuItem::OnDrawItem事件,直到您修复miThemesDrawItem()的签名以与TMenuDrawItemEvent的类型完全匹配。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70884729

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档