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