Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dynamically creating frames at runtime.

89 views
Skip to first unread message

Jason Cipriani

unread,
Jun 30, 2008, 12:19:45 AM6/30/08
to
I have a frame that I've created, and a TScrollBox. At runtime, I want to
add multiple instances of this frame to the TScrollBox. What's the right way
to do this?

I've been trying stuff like this to no avail:

=====
TMyFrame *frame = new TMyFrame(scrollbox);
frame->Left = 0;
frame->Top = 0;
frame->Width = 100;
frame->Height = 100;
frame->Visible = true;
=====

But that doesn't work -- not only does it not show the frame, but when I try
to "delete frame", it causes an access violation somewhere in the
destructor:

=====
:0044F9F4 System::TObject::Free(Self=:01F49510) <--- HERE
:004023E1 Forms::TFrame::~TFrame(this=:025F06D0)
:0040233D TMyFrame::~TMyFrame(this=:025F06D0)

System::TObject::Free():
0044F9EC 85C0 test eax,eax
0044F9EE 7407 jz $0044f9f7
system.pas.8832:
0044F9F0 B201 mov dl,$01
0044F9F2 8B08 mov ecx,[eax]
0044F9F4 FF51FC call dword ptr [ecx-$04] <--- HERE
system.pas.8833:
0044F9F7 C3 ret
=====

What's the right way to create a new component, add it to some parent
container, and eventually destroy it?

Thanks,
Jason


Bruce Larrabee

unread,
Jun 30, 2008, 1:00:52 AM6/30/08
to

Hi Jason,

Well my frames are not in fact dynamically created
but I think my method will work that way too, if not
let me know...

This works great BTW such as it is...

This is the frame:

//-------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "CellFrameUnit.h"
//-------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TCellFrame *CellFrame;
//-------------------------------------------------------------
__fastcall TCellFrame::TCellFrame(TComponent* Owner)
: TFrame(Owner)
{
}
//-------------------------------------------------------------

__fastcall TCellFrame::~TCellFrame()
{
// Destructor...

}

//-------------------------------------------------------------

void __fastcall TCellFrame::CellValueEditKeyDown(TObject *Sender,
WORD &Key, TShiftState Shift)
{
if(Key == 13)
{
Key = 9;
}
}

//-------------------------------------------------------------

void __fastcall TCellFrame::CellValueEditKeyPress(TObject *Sender,
char &Key)
{
// pressed key in value edit...

if(Key == '\r')
{
Key = 10;

return;
}

if((Key < 49)||(Key > 57))
{
Key = 0;

CellValueEdit->Clear();
}

}

//-------------------------------------------------------------


void __fastcall TCellFrame::CellValueEditEnter(TObject *Sender)
{
// entered value edit...

if(cell_value_locked == false)
{
CellValueEdit->Clear();
}
}

//-------------------------------------------------------------


Here is an array of cell data structures (Notice the pointer to
TCellFrame contained in the structure):


//-------------------------------------------------------------
//
// 'cell_data' structure:
//
// elements:
//
// solved: is cell solved
//
// is_single: does cell contain a single candidate
//
// is_pair: does cell contain a pair of candidates
//
// is_triple: does cell contain three candidates
//
// is_quad: does cell contain a four candidates
//
//
// current_value: the current value for this cell
//
// current_value_backup: a backup copy of the cell's
// current value
//
// candidate_count: the count of this cell's current
// candidate values
//
// candidate_count_backup: a backup of the candidate count
//
// cell_box: which box this cell is located in
//
// cell_row: which row this cell is located in
//
// cell_column: which column this cell is located in
//
// temp_value:
//
// single_value: value of single value
//
// pair_value: an array containing the pair if cell
// contains a pair
//
// triple_value: an array containing the triple if cell
// contains a triple
//
// quad_value: an array containing the quad if cell
// contains a quad
//
//
// candidate_values: an array containing this cell's
// candidate values
//
// candidate_values_backup: a backup copy of this cell's
// candidate values
//
// cellframe: a pointer to this cell's 'frame'
// (it's interface)
//

struct cell_data {

bool solved;

bool is_single;

bool is_pair;

bool is_triple;

bool is_quad;

int current_value;

int current_value_backup;

int candidate_count;

int candidate_count_backup;

int cell_box;

int cell_row;

int cell_column;

int temp_value;

int single_value;

int pair_value[2];

int triple_value[3];

int quad_value[4];

int candidate_values[CANDIDATECOUNT];

int candidate_values_backup[CANDIDATECOUNT];

TCellFrame *cellframe;
};

struct cell_data celldata[100];

//-------------------------------------------------------------

This function is called in a loop from the Form's constructor:


void __fastcall TSudokuForm::InitializeCellValue( TCellFrame *CellFrame,
int index)
{
celldata[index].cellframe = CellFrame;

if(loaded_reg_data == false)
{
if(CellFrame->CellValueEdit->Text.c_str()[0] == 0)
{
celldata[index].current_value = 0;

// change the cell value font color from
// fushia to blue when the user clicks
// the start button...

CellFrame->CellValueEdit->Font->Color = clBlue;
}
else
{
celldata[index].current_value =

CellFrame->CellValueEdit->Text.c_str()[0] - 48;

celldata[index].solved = true;
}
}
else
{
char dstr[16];

int data;

if(celldata[index].current_value != 0)
{
data =

celldata[index].current_value + 48;

dstr[0] = data;

dstr[1] = '\0';

AnsiString data_str = dstr;

CellFrame->CellValueEdit->Text = data_str;

celldata[index].solved = true;
}
}
}

//-------------------------------------------------------------


HTH,

Bruce

Jason Cipriani

unread,
Jun 30, 2008, 1:19:53 AM6/30/08
to
"Bruce Larrabee" <bru...@westbrookent.com> wrote in message
news:4868...@newsgroups.borland.com...

> Well my frames are not in fact dynamically created
> but I think my method will work that way too, if not
> let me know...
>
> This works great BTW such as it is...

Thanks for your reply. My application is structured similarily to yours,
except it's important that I create the frames dynamically. I can't have a
static limit on the number of frames that exist (by precreating a bunch of
them at designtime, for example). The user can create and destroy the
objects that have associated TFrames, and I must be able to dynamically
create and destroy the TFrames as well.

Jason


Remy Lebeau (TeamB)

unread,
Jun 30, 2008, 1:21:05 AM6/30/08
to

"Jason Cipriani" <jason.c...@nospam-gmail.com> wrote in message
news:48685ee0$1...@newsgroups.borland.com...

> I have a frame that I've created, and a TScrollBox. At runtime,
> I want to add multiple instances of this frame to the TScrollBox.
> What's the right way to do this?

Exactly as you showed, except for one missing piece - you did not set the
Parent property:

frame->Parent = scrollbox;

> when I try to "delete frame", it causes an access violation somewhere
> in the destructor

There is nothing wrong with the code you have shown, so the problem has to
be in code you did not show. For instance, where is 'scrollbox' defined and
allocated?


Gambit


Bruce Larrabee

unread,
Jun 30, 2008, 1:42:14 AM6/30/08
to

Hey Remy,

Got any advice with my problem above?

('Can't get mouse messages from my MDI child windows')

Is this a silly question?

Thanks,

Bruce

Jason Cipriani

unread,
Jun 30, 2008, 2:06:17 AM6/30/08
to
"Remy Lebeau (TeamB)" <no....@no.spam.com> wrote in message
news:48686cfe$1...@newsgroups.borland.com...

>
> "Jason Cipriani" <jason.c...@nospam-gmail.com> wrote in message
> news:48685ee0$1...@newsgroups.borland.com...
>
>> I have a frame that I've created, and a TScrollBox. At runtime,
>> I want to add multiple instances of this frame to the TScrollBox.
>> What's the right way to do this?
>
> Exactly as you showed, except for one missing piece - you did not set the
> Parent property:
>
> frame->Parent = scrollbox;

I tried that too and I still can't see the frame. There must be something
else wrong, I'm sure it's related to why it's crashing on delete, then.

>> when I try to "delete frame", it causes an access violation somewhere
>> in the destructor
>
> There is nothing wrong with the code you have shown, so the problem has to
> be in code you did not show. For instance, where is 'scrollbox' defined
> and allocated?

It's just a TScrollBox I dropped onto the form in the designer...

I started a new fresh project from scratch and everything worked perfectly
(p.s. you also have to set the Name property to something unique or it says
a component with that name already exists and weird things start to happen).

I played around with everything a little more and I finally got it working,
but I don't understand why the solution works. Maybe you have some insight.
I've uploaded a project to b.p.attachments with the subject "TFrame AV". The
project is a TScrollBox, a frame, and a button to add and remove frames.

Here, the TFrames are stored in a structure TTheForm::TheThing. TheThing's
constructor creates the frame, and its destructor destroys the frame.

When you run the application everything should work fine. Take a look at
TheForm.h. There is a #define USE_POINTERS at the top. When that is set to
1, TMyFrom maintains a list<TheThing *> to keep track of the current
structures. Now set it to 0. This causes TMyForm to use a list<TheThing>
instead. Now run the application. Note that adding new frames does not
behave correctly, and removing frames causes an AV. What is the problem
here? TheThing stores a TFrame*, but having a list<TheThing> is somehow
causing problems where a list<TheThing*> is not.

This doesn't make sense to me because I'm still creating VCL components
appropriately with new/delete, I'm not copying them, whether I use TheThing
or TheThing* should not be having any effect on this, but it is.

In addition to doing what you said with the Parent, the fix I had to use in
my application was to store pointers to the structures I'm using to keep
track of these things, instead of just storing the structures in a list.

Thanks,
Jason


Clayton Arends

unread,
Jun 30, 2008, 5:19:45 PM6/30/08
to
The problem is that std::list works by copy constructing its members all of
the time. Your "TheThing" will delete the contained frame the first time an
object is destroyed (even if a previous copy-constructor was used). The
immediate solution is to add a reference counting mechanism to "TheThing".
When the reference count reaches 0 delete 'frame'.

HTH,
Clayton

Jason Cipriani

unread,
Jul 1, 2008, 5:22:16 AM7/1/08
to
"Clayton Arends" <nospam_cla...@hotmail.com> wrote in message
news:48694e03$1...@newsgroups.borland.com...

No, "TheThing" contains a TFrame*, not a TFrame. The std::list does not
perform deep copies like that. It uses the copy constructor of the item it
contains. The default copy constructor of "TheThing" is the usual
member-wise default -- it should not be doing a deep copy of the TFrame*
member, it should simply be assigning pointers.

Jason


Clayton Arends

unread,
Jul 1, 2008, 5:09:21 PM7/1/08
to
"Jason Cipriani" <jason.c...@nospam-gmail.com> wrote in message
news:4869f742$1...@newsgroups.borland.com...

> No, "TheThing" contains a TFrame*, not a TFrame.

I didn't say that it did.

> The default copy constructor of "TheThing" is the usual member-wise
> default

Yes.

> it should not be doing a deep copy of the TFrame* member,

It's not.

> it should simply be assigning pointers.

It is. But the problem isn't with construction or copy-construction. The
problem is when the temporary object is destructed. Your "TheThing"
destructor destroys your frame pointer.

If you don't believe me, put a ShowMessage() in the destructor of TMyFrame.

Clayton

Jason Cipriani

unread,
Jul 1, 2008, 7:11:26 PM7/1/08
to
"Clayton Arends" <nospam_cla...@hotmail.com> wrote in message
news:486a9d00$1...@newsgroups.borland.com...

> Your "TheThing" destructor destroys your frame pointer.

Oh dear...

It was a late night but the fact that I made that mistake not once, but
twice, and then triple-checked and didn't catch it, means I should probably
go audit -all- the code I wrote that night. That doesn't make me all that
warm and fuzzy.

Thanks for pointing that out...

Jason


Clayton Arends

unread,
Jul 3, 2008, 1:38:54 PM7/3/08
to
"Jason Cipriani" <jason.c...@nospam-gmail.com> wrote in message
news:486877d8$1...@newsgroups.borland.com...

> (p.s. you also have to set the Name property to something unique or it
> says a component with that name already exists and weird things start
> to happen).

I meant to mention this in my previous post but forgot. If you set the name
to a blank string then that serves the same purpose. This technique can be
used with any VCL component.

Clayton

Jason Cipriani

unread,
Jul 5, 2008, 4:07:57 AM7/5/08
to
"Clayton Arends" <nospam_cla...@hotmail.com> wrote in message
news:486d0eb0$1...@newsgroups.borland.com...

That's handy, I've just been generating names from memory addresses. Thanks
for the tip.

Jason


0 new messages