【问题标题】:Event Handler for Dynamically Created CheckBox动态创建的复选框的事件处理程序
【发布时间】:2019-01-29 06:39:16
【问题描述】:

我使用 Borland C++ Builder 5 编写了一个 C++ 程序。该程序动态创建了一个 TCheckBox 对象数组。我试图编写一个OnClick 事件处理程序来识别正在单击哪个复选框并基于此执行一些指令。我的事件处理程序基于该网站的类似帖子,但我似乎无法使其工作。

这是(缩写的)代码

// Header declaration
void __fastcall CBoxClick(TObject *Sender); 
// End Header

// CBoxClick function (the event handler)

void __fastcall CBoxClick(TObject *Sender){
    if (dynamic_cast<TCheckBox*>(Sender)!=NULL){
        //Do stuff
    }
    else{
        Form1 -> Debug -> Text = "Object is not a TCheckBox";         
    }
}

void ChkBoxInit(void){
    int i;                                            //Loop counter index
    TCheckBox* ChkBx[NCARDS];                         //Define array of type checkboxes
    for(i = 0; i < NCARDS; i++){                      //Initalize each checkbox
        ChkBx[i] = new TCheckBox(Form1);              //Create a new checkbox
        ChkBx[i] -> Parent = Form1;                   //Define parent of checkbox
        ChkBx[i] -> Tag = i;                          //Set value of Tag to index
        //  Other CheckBox parameters here such as Height, Width, Top, Left, Name are here
        //  Next, call event handler. I've tried the following 2 statements with the comment results
        ChkBx[i] -> OnClick = CBoxClick(ChkBx[i]);    //  Results in E2109: Not an allowed type
        ChkBx[i] -> OnClick = CBoxClick;              /* Alternate try - Results in E2034: Cannot convert
                                                        'void (_fastcall *)(TObject *)' to 
                                                        'void (_fastcall * (_closure )(TObject *))(TObject *)'  */
    }                                                 //End of for loop
}                                                     //End of function

【问题讨论】:

    标签: c++ c++builder c++builder-5 tcheckbox


    【解决方案1】:

    CBoxClick() 不是您的 Form 类的成员。

    在您的 cpp 文件中,编译器将其视为独立函数。这就是 OnClick 事件分配失败时错误消息所抱怨的内容(非静态类方法具有 __closure 属性,非成员没有)。

    确保CBoxClick()inside你的Form类的头文件中声明:

    class TForm1 : public TForm
    {
        ...
    public:
        ...
        void __fastcall CBoxClick(TObject *Sender); // <-- add this
        ...
    };
    

    然后在你的 cpp 文件中更改这一行:

    void __fastcall CBoxClick(TObject *Sender){
    

    改为:

    void __fastcall TForm1::CBoxClick(TObject *Sender){
    

    然后从此更改OnClick 事件的分配:

    ChkBx[i]->OnClick = CBoxClick;
    

    为此(因为ChkBoxInit() 本身似乎也不是 Form 类的成员):

    ChkBx[i]->OnClick = Form1->CBoxClick;
    

    您尝试的第一个语法 (OnClick = CBoxClick(ChkBx[i]);) 完全是错误的,因为您实际上是在调用 CBoxClick(),然后尝试将其void 返回值分配给OnClick,这显然行不通。您需要将CBoxClick()地址 分配给OnClick,这仅适用于非静态类方法,不适用于独立函数(嗯,它可以完成,但它需要不同的涉及使用TMethod 结构的类型转换黑客的代码)。

    另外,您不应该使用dynamic_cast。既然您知道Sender 将始终是TCheckBox,请改用static_cast

    void __fastcall TForm1::CBoxClick(TObject *Sender){
        TCheckBox *cb = static_cast<TCheckBox*>(Sender);
        //Do stuff with cb...
    }
    

    更新:现在,话虽如此,更好的选择是完全摆脱 ChkBoxInit() 并在 Form 自己的构造函数中进行数组初始化:

    class TForm1 : public TForm
    {
        ...
    private:
        ...
        void __fastcall CBoxClick(TObject *Sender); // <-- moved here
        ...
    public:
        __fastcall TForm1(TComponent *Owner); // <-- constructor
        ...
    };
    

    __fastcall TForm1::TForm1(TComponent *Owner)
        : TForm(Owner)
    {
        TCheckBox* ChkBx[NCARDS];                         //Define array of type checkboxes
        for(int i = 0; i < NCARDS; i++){                  //Initalize each checkbox
            ChkBx[i] = new TCheckBox(this);               //Create a new checkbox
            ChkBx[i] -> Parent = this;                    //Define parent of checkbox
            ChkBx[i] -> Tag = i;                          //Set value of Tag to index
            //  Other CheckBox parameters here such as Height, Width, Top, Left, Name are here
            //  Next, setup event handler
            ChkBx[i]->OnClick = CBoxClick;
        }                                                 //End of for loop
    }        
    
    void __fastcall TForm1::CBoxClick(TObject *Sender)
    {
        TCheckBox *cb = static_cast<TCheckBox*>(Sender);
        // Do stuff with cb...
    }
    

    【讨论】:

    • 感谢您的帮助。我按照您的指示修改了代码。我还修改了标头以添加 TForm1 范围,但它没有编译,并给出错误消息 E2316: 'CBoxClick' is not a member of 'TForm1' 如何使 CBoxClick 成为 TForm1 的成员?
    • 不要在头文件中添加TForm1::CBoxClick 实际上需要表单的class 声明中。查看我的答案的更新。
    • 到目前为止我一直没有成功,所以我回到你原来的建议,因为我注意到我没有正确实施它。下面是来自头文件的代码、事件处理程序代码和一个简化的测试例程,它只创建一个复选框,而不是一个复选框数组。它仍然不起作用,给出 E2034 的构建错误 Cannot convert 'void (_fastcall TForm1::*)(TObject *)' to 'void (_fastcall * (_closure )(TObject *))(TObject *)' 在行它将 OnClick 事件分配给 CBoxClick。
    • @Doug 我在回答中提供的代码工作正常,因此您不能正确地将其应用到您的代码中。请编辑您的问题以显示您的最新代码
    • 抱歉,我尝试这样做,但遇到了编辑器问题,它在我完成之前提交了我的评论。无论如何,与此同时,我找到了一个类似的解决方案,我成功地尝试过。对代码的更改是将 OnClick 事件分配给 CBoxClick 事件处理程序,如下所示: ChkBx[i] -> OnClick = Form1 -> CBoxClick; //将OnClick事件分配给事件处理程序(CBoxClick)
    【解决方案2】:

    Remy - 我仍然无法使用编辑器。这是基于您的第一个响应的工作代码,只需稍作改动。感谢您的帮助。

    `// .h 文件----------------

    class TForm1 : public TForm
    {
    __published:    // IDE-managed Components
            TButton *Deal;
            TButton *Reset;
            TButton *Help;
            TButton *Quit;
            TEdit *Debug;
            void __fastcall QuitClick(TObject *Sender);
            void __fastcall ResetClick(TObject *Sender);
    private:    // User declarations
    public:     // User declarations
      __fastcall TForm1(TComponent* Owner);
      void __fastcall CBoxClick(TObject *Sender);  //CheckBox Event Handler prototype
    };
    

    // .cpp 文件----------------

      void ChkBoxInit(void){
        int i;                                         //Loop counter index
        TCheckBox* ChkBx[NCARDS];                      //Define array of type checkbox
        for(i = 0; i < NCARDS; i++){                   //Initalize each checkbox
          ChkBx[i] = new TCheckBox(Form1);             //Create a new checkbox
          ChkBx[i] -> Parent = Form1;                  //Define parent of checkbox
    
    // ..... Various parameters of ChkBx[i] go here (height, Width, Top, Left, etc.)
    
          ChkBx[i] -> Tag = i;                         //Use index value as tag
    `     ChkBx[i] -> OnClick = Form1 -> CBoxClick;    //Assign OnClick event to CBoxClick
        }                                              //End of for loop
      }                                                //End of function
    
    
    //  Event Handler ------------------
    
     void __fastcall TForm1::CBoxClick(TObject *Sender){
       if (static_cast<TCheckBox*>(Sender)!=NULL){
         Form1 -> Debug -> Text =  (static_cast<TCheckBox*>(Sender) -> Name);
       }
       else{
         Form1 -> Debug -> Text = "Object is not a TCheckBox";
       }
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-22
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多