Board index » cppbuilder » How to assign event-handler to a contol created dynamically

How to assign event-handler to a contol created dynamically


2004-10-06 11:58:28 PM
cppbuilder54
Hi
Descriptions:
Other C programmer need wrapping function for create form and controls
on the form. Something like this:
fm = CreateForm(...) ; // it is no problem
bt = AddButton(fm, ..., ClickEvent);
The question is C programmer want add their own event handler to the
controls they created without IDE.
Since the wraping functions was written when I do not know how many controls
and if the controls tied with click or other event, So I could not included
any clousre function in the parrent form, Ofcause there are some ways to
solve the problem, My thought is to create a struct that records all the
controls and it's underlined c event-routines and then in the form use one
clouser function to locate the controls and call the c-routine inside the
object of that class, it is complicate. but I think there might be some easy
way to assign the C rountine to a clouser, Any one knows this? thanks
 
 

Re:How to assign event-handler to a contol created dynamically

I've just started looking at this area and the solution I've come up
with is to use a dummy class:
class TClipPrintSave_ListView_StandardFunctions
{
public:
TClipPrintSave_ListView_StandardFunctions()
{;}
void __fastcall CopyAllToClipBoard( System::TObject * Sender );
void __fastcall CopySelectedToClipBoard( System::TObject * Sender );
};
extern TClipPrintSave_ListView_StandardFunctions dummy;
Then elsewhere I can use:
TMenuItem * tmpMenu=new TMenuItem( ParentMenu );
tmpMenu->Caption=Action.Caption;
tmpMenu->OnClick=SelectedOnlyF ? &dummy.CopySelectedToClipBoard
: &dummy.CopyAllToClipBoardS;
Those functions will then be coded as if they were static functions. I
can follow the 'Sender' and 'Parent' pointers to determine what control
the menu belongs to and then work with that. In theory :)
I've only been working on this for the last couple of hours though so
there may be a pitfall lurking :)
FWIW the reason *I'm* doing this is I want a simple function that I can
use to set up a standard pop-up menu for all and every TListView in our
application. As this is a retrofit this seems the simplest solution.
Using a TFrame from the start would probably have been better but that
was several years ago and this is a new idea.
--
Andrue Cope [TeamB]
[Bicester, Uk]
info.borland.com/newsgroups/guide.html
 

Re:How to assign event-handler to a contol created dynamically

wgy wrote:
Quote
Descriptions:
Other C programmer need wrapping function for create form and controls
on the form. Something like this:
fm = CreateForm(...) ; // it is no problem
bt = AddButton(fm, ..., ClickEvent);
The question is C programmer want add their own event handler to the
controls they created without IDE.

... but I think there might be some easy
way to assign the C rountine to a clouser, Any one knows this? thanks
Try and experiment with:
void *CreateForm(void)
{
TForm *Form = new TForm ( (TComponent*)0 );
Form->Show();
return (void*)Form;
}
class TClicker
{
public:
TClicker(){}
void (*click)(void*);
void __fastcall clickfunction (TObject *Sender);
};
void __fastcall TClicker::clickfunction (TObject *Sender)
{
//ShowMessage ( "TClicker::clickfunction" );
click(0);
}
void *AddButton ( void *fm, char *caption, int left, void (*click)(void*) )
{
TButton *Button = new TButton ( fm );
Button->Caption = caption;
Button->Left = left;
Button->Parent = (TWinControl*)fm;
TClicker *Clicker = new TClicker;
// the pointer will go out of scope
// the instance will still exist
// you have to solve that problem
Clicker->click = click;
Button->OnClick = Clicker->clickfunction;
return (void*)Button;
}
void button1click (void*)
{
ShowMessage ( "This is button1" );
}
void button2click (void*)
{
ShowMessage ( "This is button2" );
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
void *CreateForm(void);
void *AddButton ( void *fm, char *caption, int left, void (*click)(void*) );
void *fm = CreateForm() ; // it is no problem
void *bt1 = AddButton ( fm, "Abcd", 20, button1click );
void *bt2 = AddButton ( fm, "Xywz", 100, button2click );
if ( bt1) {;}
if ( bt2) {;}
// you have to make and adapt functions yet for deleting instances
}
Hans.
 

{smallsort}

Re:How to assign event-handler to a contol created dynamically

Thanks Andrue and Hans
I also did by this way.
I limit the controls created by c programmer only can have click event (most
of the situations are okey with this limitation), and the solution is a new
pascal unit( I use Delphi unit as higher priority if delphi can fulfill the
task,
cause BCC can always use Delphi unit and also get faster complilation speed)
which less than 150 lines code, by this way, all the standard controls can
be created programablly in a C-Style function call.
type
TClickEvent = procedure (Sender : TObject); // define the c-style event
function, not a clousure at all
TClickRec = packed record // records all the controls on the form
created by c user
m_Control : TControl;
m_ClickPorct : TClickEvent;
end;
TDForm = class (TForm) // c- user only can create
this kind of form
procedure OnCtrlClick(Sender :TObject); // the clousure, will call c
user's event handler
private
m_ClickRecs : Array of TClickRec;
...
end;
TControlClass = class of TControl;
// following are c functions that create user interface dynamically
function DCreateForm(...) :TDForm;
function DAddCtrl(fm : TDForm; pa : TWinControl; x, y, w, h :Integer; ct :
TContrlClass;
mode:TAddMode, scap :AnsiString = ''; evt : TClickEvent=nil):TControl;
...
implementation
// The core function that add controls into a form
function DAddCtrl(fm : TDForm; pa : TWinControl; x, y, w, h :Integer; ct :
TContrlClass; mode:TAddModeSet, scap :AnsiString = ''; evt :
TClickEvent=nil):TControl;
var
ctl : TControl;
nc : Integer;
begin
ctl := ct.Create(fm);
ctl.Parent := pa;
SetBounds(x,y,w,h);
nc := Length(fm.m_ClickEventRecs)
SetLength(fm.m_ClickRecs, nc+ 1);
fm.m_ClickRecs[nc].m_Control := crl;
if daCap in mode then
TLabel(ctl).Caption := scap;
if (daClickEvt in mode) and evt <>nil then begin
TLabel(ctl).Onlick = fm.OnCtrlClick;
fm.m_ClickRecs[nc].m_ClickProc := evt;
end;
if daText in mode then
TEdit(ctl).Text := scap;
...
end;
// the clousure that call c-style event routine
procedure TDForm.OnClick(Sender : TObject);
var
i, ni;
begin
ni := -1;
for i:=0 to length(m_ClickRecs) -1 do
if (Sender as TControl) = m_ClickRecs[i].m_Control then begin
ni:= i; break;
end;
if (ni>=0) and (@m_ClickRecs[ni].m_ClickProc <>nil) then
m_ClickRecs[ni].m_ClickProc(Sender);
end;
This Pascal unit only has about 150 lines, After I integrated it into BCC
project, the compiled header file generated by BCC already has 96 lines. So
I have to
use pacal to descript the idea, ( If use BCC, it will be much more code
typing).
The another good thing of using c-style GUI functions is that user do not
need use IDE create
user interface for some simple I/O forms. It reduces number of files in a
project, and since there is no .dfm and all other resouce files tied to the
project,
application will be smaller.
 

Re:How to assign event-handler to a contol created dynamically

Great,
I never tried that the owner of Form and controls can be null( kind of fake
ownner). So the user will take care of freeing the memory.
"Hans Galema" < XXXX@XXXXX.COM >wrote in message
Quote
wgy wrote:

>Descriptions:
>Other C programmer need wrapping function for create form and
controls
>on the form. Something like this:
>fm = CreateForm(...) ; // it is no problem
>bt = AddButton(fm, ..., ClickEvent);
>The question is C programmer want add their own event handler to the
>controls they created without IDE.
>
>... but I think there might be some easy
>way to assign the C rountine to a clouser, Any one knows this? thanks

Try and experiment with:


void *CreateForm(void)
{
TForm *Form = new TForm ( (TComponent*)0 ); /* ********** nice
(wgy) ******/

Form->Show();

return (void*)Form;
}

class TClicker
{
public:
TClicker(){}
void (*click)(void*);
void __fastcall clickfunction (TObject *Sender);
};

void __fastcall TClicker::clickfunction (TObject *Sender)
{
//ShowMessage ( "TClicker::clickfunction" );
click(0);
}

void *AddButton ( void *fm, char *caption, int left, void
(*click)(void*) )
{
TButton *Button = new TButton ( fm );

Button->Caption = caption;

Button->Left = left;

Button->Parent = (TWinControl*)fm;

TClicker *Clicker = new TClicker;
// the pointer will go out of scope
// the instance will still exist
// you have to solve that problem
/* ********
Yes sir! I can do this, no problem ! :) wgy
**********/
Quote
Clicker->click = click;

Button->OnClick = Clicker->clickfunction;

return (void*)Button;
}

void button1click (void*)
{
ShowMessage ( "This is button1" );
}

void button2click (void*)
{
ShowMessage ( "This is button2" );
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
void *CreateForm(void);
void *AddButton ( void *fm, char *caption, int left, void
(*click)(void*) );


void *fm = CreateForm() ; // it is no problem

void *bt1 = AddButton ( fm, "Abcd", 20, button1click );
void *bt2 = AddButton ( fm, "Xywz", 100, button2click );

if ( bt1) {;}
if ( bt2) {;}

// you have to make and adapt functions yet for deleting instances
}

Hans.