将事件分配给在运行时动态创建的 VCL 控件

Assigning events to a VCL control created dynamically at runtime

我正在尝试在运行时创建动态 VCL 控件并为其分配事件处理程序。

我想我已经尝试了所有方法来让它工作,但不能(我尝试的所有方法都会产生不同的错误)。

如果您能帮忙填写下面代码中的问号,那就太好了!

哦,如果您想知道为什么它在 namespace 而不是 class 中,那是因为这实际上是一个我不断添加的大型库。当我将它更改为 class 时,您会认为它会很好,但不,它会产生大量奇怪的错误。

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);
}

VCL 事件处理程序预期 是class 的non-static 成员。您的 OnTimer 处理程序不是 class 成员,而是 free-floating 函数(命名空间并不重要)。

解决此问题的正确方法是为您的OnTimer事件处理程序创建一个class,然后实例化该class在 TTimer 旁边,例如:

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);
}

也就是说,实际上有一种 替代方法 可以像您想要的那样使用 free-floating 函数作为 VCL 事件处理程序,方法是使用 System::TMethod 结构:

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);
}