C++Builder TMouseWheelEvent 编译错误

C++Builder TMouseWheelEvent compiler error

无论我如何尝试使用它,我都无法动态创建 TScrollBox 并为其分配 OnMouseWheelEvent 处理程序。我收到以下编译器错误:

E2034 Cannot convert 'void (_fastcall * (_closure )(TObject *,TShiftState,int,TPoint &,bool &))(TObject *,TShiftState,int,TPoint &,bool &)' to 'TMouseWheelEvent'

我对 OnMouseWheelEvent 处理程序的声明是正确的(据我所知):

....
TScrollBox *sb = new TScrollBox(funnelCharts);
sb->Top = 5000;
sb->Parent = funnelCharts;
sb->Align = alClient;
sb->Height = funnelCharts->ClientHeight;
sb->OnMouseWheel = scrollEvent;
....

// --------------------------------------------------------------

void __fastcall TForm1::scrollEvent(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
{
    TScrollBox *scrollbox = dynamic_cast<TScrollBox*>(Sender);
    if (scrollbox)
    {
        for (int i = 1; i < Mouse->WheelScrollLines; i++)
        {
            if (WheelDelta > 0)
            {
                scrollbox->Perform(WM_VSCROLL, SB_LINEUP, 0);
            }
            else
            {
                scrollbox->Perform(WM_VSCROLL, SB_LINEDOWN, 0);
            }
        }
        scrollbox->Perform(WM_VSCROLL, SB_ENDSCROLL, 0);
        Handled = true;
    }
}

这是一个编译器错误,而不是链接器错误。

查看Controls.hppTMouseWheelEvent的实际声明。您的 scrollEvent() 方法与实际声明的不匹配,否则您不会收到错误。

根据您是为 32 位还是 64 位编译,TMouseWheelEvent(具体来说,其 MousePos 参数)的声明方式不同:

32 位:

typedef void __fastcall (__closure *TMouseWheelEvent)(System::TObject* Sender, System::Classes::TShiftState Shift, int WheelDelta, const System::Types::TPoint &MousePos, bool &Handled);

64 位:

typedef void __fastcall (__closure *TMouseWheelEvent)(System::TObject* Sender, System::Classes::TShiftState Shift, int WheelDelta, System::Types::TPoint MousePos, bool &Handled);

原因是 BCC32 和 BCC64 在传递 8 字节结构类型(如 TPoint)方面有所不同。这种差异记录在 Embarcadero 的 DocWiki 上:

Events with Structures or Sets of 5-8 Bytes Are Not Valid for BCC64

受此差异影响的其他事件类型包括 TGetSiteInfoEventTMouseWheelUpDownEventTContextPopupEvent

要解决此问题,您必须 #ifdef 您的代码如文档所述:

class TForm1 : public TForm
{
    ...
    #ifndef _WIN64
    void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled);
    #else
    void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, TPoint MousePos, bool &Handled);
    #endif
    ...
};

...

#ifndef _WIN64
void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
#else
void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, TPoint MousePos, bool &Handled)
#endif
{
    ...
}

或者,更简洁的方法:

class TForm1 : public TForm
{
    ...
    void __fastcall scrollEvent(
        TObject* Sender, TShiftState Shift, int WheelDelta,
        #ifndef _WIN64
        const TPoint &MousePos,
        #else
        TPoint MousePos,
        #endif
        bool &Handled);
    ...
};

...

void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta,
    #ifndef _WIN64
    const TPoint &MousePos,
    #else
    TPoint MousePos,
    #endif
    bool &Handled)
{
    ...
}

或者,更干净:

#ifndef _WIN64
#define SAFE_5TO8_PARAM(type, name) const type &name
#else
#define SAFE_5TO8_PARAM(type, name) type name
#endif

class TForm1 : public TForm
{
    ...
    void __fastcall scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, SAFE_5TO8_PARAM(TPoint, MousePos), bool &Handled);
    ...
};

...

void __fastcall TForm1::scrollEvent(TObject* Sender, TShiftState Shift, int WheelDelta, SAFE_5TO8_PARAM(TPoint, MousePos), bool &Handled)
{
    ...
}