Assigning events to a VCL control created dynamically at runtime

二次信任 提交于 2019-12-25 18:06:10

问题


I'm trying to create a dynamic VCL control at runtime and assign an event handler to it.

I think I've tried everything to get this to work, but cannot (everything I try generates different errors).

If you could help fill in the question marks in the code below, it would be of great help!

Oh, in case you're wondering why it's in a namespace instead of a class, it's because this is actually a large library that I just kept adding to. When I change it to a class, you'd think it would be fine, but no, it generates a gazillion weird errors.

test.h

namespace TestSpace {
    TTimer *time;
    AnsiString file;
    void __fastcall MyFunc(AnsiString f);
    ?Declaration for OnTimer event?
}

test.cpp

void __fastcall TestSpace::MyFunc(AnsiString f) {
    TestSpace::file = f;
    TestSpace::time->OnTimer = ?;
    TestSpace::time->Enabled = true;
}

TestSpace::?(TObject* Sender) {
    TestSpace::time->Enabled = false;
    DeleteFile(TestSpace::file);
}

回答1:


A VCL event handler is expected to be a non-static member of a class. Your OnTimer handler is not a class member, it is a free-floating function instead (the namespace is not important).

The correct way to solve this issue is to create a class for your OnTimer event handler, and then instantiate that class alongside the TTimer, eg:

test.h

namespace TestSpace {
    class TimerEvents {
    public:
        void __fastcall TimerElapsed(TObject *Sender);
    };
    TTimer *time;
    TimerEvents time_events;
    AnsiString file;
    void __fastcall MyFunc(AnsiString f);
}

test.cpp

void __fastcall TestSpace::MyFunc(AnsiString f) {
    TestSpace::file = f;
    TestSpace::time->OnTimer = &(time_events.TimerElapsed);
    TestSpace::time->Enabled = true;
}

void __fastcall TestSpace::TimerEvents::TimerElapsed(TObject* Sender) {
    // 'this' is the TimerEvents object
    // 'Sender' is the TTimer object
    TestSpace::time->Enabled = false;
    DeleteFile(TestSpace::file);
}

That being said, there is actually an alternative way to use a free-floating function as a VCL event handler like you want, by using the System::TMethod struct:

test.h

namespace TestSpace {
    TTimer *time;
    AnsiString file;
    void __fastcall MyFunc(AnsiString f);
    // NOTE: must add an explicit void* parameter to receive
    // what is supposed to be a class 'this' pointer...
    void __fastcall TimerElapsed(void *This, TObject *Sender);
}

test.cpp

void __fastcall TestSpace::MyFunc(AnsiString f) {
    TestSpace::file = f;
    TMethod m;
    m.Data = ...; // whatever you want to pass to the 'This' parameter, even null...
    m.Code = &TestSpace::TimerElapsed;
    TestSpace::time->OnTimer = reinterpret_cast<TNotifyEvent&>(m);
    TestSpace::time->Enabled = true;
}

void __fastcall TestSpace::TimerElapsed(void *This, TObject* Sender) {
    // 'This' is whatever you assigned to TMethod::Data
    // 'Sender' is the TTimer object
    TestSpace::time->Enabled = false;
    DeleteFile(TestSpace::file);
}


来源:https://stackoverflow.com/questions/49040803/assigning-events-to-a-vcl-control-created-dynamically-at-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!