1

Windowsデスクトップのアイコンを模倣するVCLコンポーネント、TGIconを作成しています.MouseEnterおよびMouseLeaveイベントをコンポーネントに追加することを決定するまで、正常に機能していました。私は次のガイドに従いました: Embarcadero Community

ここに私のコード(ヘッダー)があります:

class PACKAGE TGIcon : public TGraphicControl
{
    private:
        AnsiString FCaption;
        TPngImage *FIcon, *FDIcon;
        TFont *FFont;
        TNotifyEvent FOnMouseEnter;
        TNotifyEvent FOnMouseLeave;

        void __fastcall CMMouseEnter(TMessage &Message);
        void __fastcall CMMouseLeave(TMessage &Message);

        BEGIN_MESSAGE_MAP
            MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
            MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
        END_MESSAGE_MAP(TGIcon)

    protected:
        virtual void __fastcall Paint();
        void __fastcall SetCaption(AnsiString value);
        void __fastcall SetIcon(TPngImage *value);
        void __fastcall SetFont(TFont *value);

    public:
        __fastcall TGIcon(TComponent* Owner);
        __fastcall ~TGIcon();
        void __fastcall MakeGray(void);

    __published:
        __property AnsiString Caption = {read=FCaption, write=SetCaption, nodefault};
        __property TPngImage  *Icon   = {read=FIcon, write=SetIcon};
        __property TFont      *Font   = {read=FFont, write=SetFont};
        __property Parent;
        __property Enabled;
        __property OnClick;

        __property TNotifyEvent OnMouseEnter = {read=FOnMouseEnter, write=FOnMouseEnter};
        __property TNotifyEvent OnMouseLeave = {read=FOnMouseLeave, write=FOnMouseLeave};
};

コンポーネントをフォームに配置しようとすると、IDE (C++ Builder Starter) がデスクトップにクラッシュします。問題の原因が「BEGIN_MESSAGE_MAP...END_MESSAGE_MAP」の部分であることを突き止めました。その部分をコメントアウトすると、コンポーネントは正常に動作します。

以前は C++Builder XE5 (Professional) で同じコンポーネントが動作していましたが、それはもう使用していない会社が所有しているため、コンポーネントのバイナリがないため、ここに書き直す必要があります。 . 私が覚えている限り、私が行ったことは XE5 で書いたものとまったく同じです。これは機能しますが、これは IDE をクラッシュさせ、エラー メッセージもアクセス違反もなく、単純な CTD でした。

C++ Builder 10.1 (Berlin) Starter Edition でこれを機能させるために必要なことはありますか? これは C++Builder のバグですか、それとも Starter Edition では実行できず、「有料」版でしか実行できないのですか?? それとも、この方法はすでに時代遅れですか?もしそうなら、「近代化された」C++ Builder がどのようにそれを行うかを教えてください。

前もって感謝します。

4

1 に答える 1

4

あなたMESSAGE_MAPは間違って終了しています。マクロでは、コンポーネントが派生する基本クラスEND_MESSAGE_MAPを指定する必要があります( )。TGraphicControl

Aは、仮想メソッドMESSAGE_MAPをオーバーライドする単なる手の込んだ方法です。Dispatch()

  • BEGIN_MESSAGE_MAPオーバーライドされたメソッドを宣言して開き、switchステートメントを開きます
  • MESSAGE_HANDLER(VCL_MESSAGE_HANDLERプロジェクトが ATL を使用する場合は代わりに使用case)switch
  • END_MESSAGE_MAPDispatch()未処理のメッセージに対して指定されたクラスのメソッドを呼び出し、switchを閉じ、オーバーライドされたメソッドを閉じます。

からの宣言は次のsysmac.hとおりです。

#define BEGIN_MESSAGE_MAP   virtual void __fastcall Dispatch(void *Message) \
        {                                           \
          switch  (((PMessage)Message)->Msg)        \
          {

#define VCL_MESSAGE_HANDLER(msg,type,meth)          \
          case    msg:                              \
            meth(*((type *)Message));               \
            break;

// NOTE: ATL defines a MESSAGE_HANDLER macro which conflicts with VCL's macro. The
//       VCL macro has been renamed to VCL_MESSAGE_HANDLER. If you are not using ATL,
//       MESSAGE_HANDLER is defined as in previous versions of BCB.
//
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER  VCL_MESSAGE_HANDLER
#endif // ATL_COMPAT

#define END_MESSAGE_MAP(base)           default:    \
                        base::Dispatch(Message);    \
                        break;                      \
          }                                         \
        }

したがって、このコード:

BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
    MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGIcon) // <-- error!

プリプロセッサによって次のコードに変換されます。これがコンパイラに表示されます。

virtual void __fastcall Dispatch(void *Message)
{
    switch (((PMessage)Message)->Msg)
    {
        case CM_MOUSEENTER:
            CMMouseEnter(*((TMessage *)Message));
            break;

        case CM_MOUSELEAVE:
            CMMouseLeave(*((TMessage *)Message));
            break;

        default:
            TGIcon::Dispatch(Message); // <-- recursive loop!
            break;
    }
}

ご覧のとおり、 では基本クラス ( ) の代わりに独自のコンポーネント クラス ( ) を指定しているためTGIcon、コンポーネントが未処理のメッセージを受信すると無限再帰ループが作成されます。 再び呼んでいます。代わりに呼び出す必要があります (メソッドとメソッドも同様です):TGraphicControlEND_MESSAGE_MAPTGIcon::Dispatch()TGIcon::Dispatch()TGraphicControl::Dispatch()CMMouseEnter()CMMouseLeave()

BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
    MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TGraphicControl) // <-- fixed!
于 2017-08-30T02:48:59.743 に答える