Discussion:
Performance Problem
(too old to reply)
bar
2007-09-13 11:45:49 UTC
Permalink
I am using BCB6 Ent.
I am creating 50 to 100 number of labels at runtime and placing all of them
in a panel.

header file
------------------------------------
private:
void __fastcall LabelMouseEnter(TObject *Sender);
void __fastcall LabelMouseLeave(TObject *Sender);
void __fastcall LabelClick(TObject *Sender);
------------------------------------
<snip>
for(int i=0; i<60; i++)
{
TLabel *Label = new TLabel(picTickerPanel);
Label->Parent = picTickerPanel;
Label->Tag = i;
Label->AutoSize = true;
Label->Transparent = true;
Label->Caption = NewsItem[i].Headline;
Label->Top = 0;
Label->Left = Left;
Left = Label->Width + 20; //-->Align the lables properly

//Assign the Event Handlers run time.
Label->OnMouseEnter = LabelMouseEnter;
Label->OnMouseLeave = LabelMouseLeave;
Label->OnClick = LabelClick;
}
-------------------------
void __fastcall TfrmMain::LabelMouseEnter(TObject *Sender)
{
TLabel *L = dynamic_cast<TLabel*>(Sender);
L->Font->Color = clRed;
}
-------------------------
void __fastcall TfrmMain::LabelMouseLeave(TObject *Sender)
{
TLabel *L = dynamic_cast<TLabel*>(Sender);
L->Font->Color = clBlack;
}
-------------------------
void __fastcall TfrmMain::LabelClick(TObject *Sender)
{
//some thing.
}
-------------------------

Then i am scrolling this panel in a timer at an interval 25 milli seconds
void __fastcall TfrmMain::Timer1Timer(TObject *Sender)
{
picTickerPanel->Left = picTickerPanel->Left + 1;
}

If the number of lable less than 10 then all the label events are
triggering.
But when more no events are triggering.
Thanks
SA
Remy Lebeau (TeamB)
2007-09-13 17:15:30 UTC
Permalink
Post by bar
Left = Label->Width + 20; //-->Align the lables properly
If you are trying to make the labels appear side-by-side, then you need to
use the '+=' operator instead:

Left += (Label->Width + 20);

Otherwise, use the TLabel's Left property instead:

Left = (Label->Left + Label->Width + 20);
Post by bar
TLabel *L = dynamic_cast<TLabel*>(Sender);
Use static_cast instead. You don't need the overhead of a dynamic lookup
since you already know the Sender will always be a TLabel.


Gambit
bar
2007-09-15 09:03:18 UTC
Permalink
Post by Remy Lebeau (TeamB)
If you are trying to make the labels appear side-by-side, then you need to
Left += (Label->Width + 20);
Left = (Label->Left + Label->Width + 20);
Post by bar
TLabel *L = dynamic_cast<TLabel*>(Sender);
Yes remy thanks.
Post by Remy Lebeau (TeamB)
Use static_cast instead. You don't need the overhead of a dynamic lookup
since you already know the Sender will always be a TLabel.
I searched deja i not unable to find the solution. I added
Application->ProcessMessages(); in the Timer_Timer event, no result, still i
am having the same problem.

And
Evenafter when the form is closed by Form->Close(), it continues to display
until any command button is pressed.on the form.

Regards
SA
Remy Lebeau (TeamB)
2007-09-16 03:09:11 UTC
Permalink
Post by bar
Evenafter when the form is closed by Form->Close(), it continues
to display until any command button is pressed.on the form.
Then you are likely doing something else in the form to block it with code
you have not shown yet. Please provide a complete project that reproduces
the problem with minimal code.


Gambit
bar
2007-09-16 09:01:42 UTC
Permalink
Hi Remy

//I am creating a appbar for my form.
//I have to read a xml file which has news headlines and URL paths for
images then i need to scroll these over form.
//So i selected a Panel as a container, this Panel requires a background
picture, so i took a ImageBox Control and made as alClient to the panel at
design time.
//Every present in the local hard drive, the XML file, and URL path for the
images.

//Header file
class TfrmMain : public TForm
{
private:
{
APPBARDATA abd;

_di_IXMLDocument XMLNews;
_di_IXMLNode Nrss;
int TotalNewsItems;

_di_IXMLDocument XMLImages;
_di_IXMLNode Arss;
int TotalImagesItems;

void __fastcall CMMouseEnter(TMessage &Message);
void __fastcall CMMouseLeave(TMessage &Message);
}
public:
{
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
VCL_MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TForm)
}
}
-----------------------------------------------
//cpp file

//structure arrays to store the news and images data
struct udtNewsItem
{
String Headline,url,pubdate;
}*NewsItem;

struct udtAdvtItem
{
String url,AdvtLink;
int order;
}*AdvtItem;

__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
abd.cbSize = sizeof(abd);
abd.hWnd = frmMain->Handle;
abd.uCallbackMessage = WM_ABNOTIFY;

SHAppBarMessage(ABM_NEW, &abd);

abd.uEdge=ABE_TOP;

SetRect(&abd.rc,0,0,Screen->Width,Screen->Height);
SHAppBarMessage(ABM_QUERYPOS,&abd);

abd.rc.bottom=abd.rc.top+30;

SHAppBarMessage(ABM_SETPOS,&abd);

SetWindowPos(abd.hWnd,HWND_TOPMOST,abd.rc.left,abd.rc.top,
abd.rc.right-abd.rc.left,abd.rc.bottom-abd.rc.top,
SWP_NOMOVE | SWP_NOSIZE);

MoveWindow(abd.hWnd,abd.rc.left,abd.rc.top,
abd.rc.right-abd.rc.left,
abd.rc.bottom-abd.rc.top,TRUE);
frmMain->Width = Screen->Width;
}
----------------------------------------------------
void __fastcall TfrmMain::CMMouseEnter(TMessage &Message)
{
TForm::Dispatch(&Message);
frmMain->Height = 30;
}
//---------------------------------------------------------
void __fastcall TfrmMain::CMMouseLeave(TMessage &Message)
{
TForm::Dispatch(&Message);
frmMain->Height = 1;
}
---------------------------------------------------------
//Aligning the panel
Panel->Width = frmMain->Width-2;
Panel->Height = frmMain->Height-2;
Panel->Left = frmMain->Left+1;
Panel->Top = frmMain->Top+1;
----------------------------------------------------------
//Painting the panel(the image box)
TPicture *TilePicture = new TPicture();
TilePicture->LoadFromFile("c:\some.gif");
for(int y = 0; y < Panel->Height; y += TilePicture->Height)
{
for(int x = 0; x < Panel->Width; x +=
TilePicture->Width)
Image->Canvas->Draw(x, y,
TilePicture->Graphic);
}
----------------------------------------------------------
//reading the news xml file data into structure array.

XMLNews = LoadXMLDocument("c:\News.xml");
Nrss = XMLNews->DocumentElement->ChildNodes->GetNode(0);
TotalNewsItems = Nrss->ChildNodes->GetCount();

NewsItem = new udtNewsItem[TotalNewsItems];

for(int i=0; i<TotalNewsItems; i++)
{
NewsItem[i].Headline =
Nrss->ChildNodes->Nodes[WideString("title")]->Text;
NewsItem[i].url =
Nrss->ChildNodes->Nodes[WideString("link")]->Text;
NewsItem[i].pubdate =
Nrss->ChildNodes->Nodes[WideString("pubDate")]->Text;
}

//i am creating the labels as i shown in the previous in a loop and placing
them over panel side-by-side.

//read the images xml file for placing images over panel.
//I need to display .bmp, gif, .jpeg, and flash files, so i took
GIFImage.pas for showing .gif, .jpeg, .bmp and TShockwaveFlash Active X
control for flash images.

//Here are classes that i created in the header for detecting MouserEnter,
MouseLeave Events.

//-->begin of header
class TImageGIF : public TImage
{
private:
void __fastcall CMMouseEnter(TMessage &Message);
void __fastcall CMMouseLeave(TMessage &Message);

String GIFCursor;
public:
__fastcall TImageGIF(TComponent *Owner);

BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
VCL_MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
END_MESSAGE_MAP(TImage)
};

class TImageFLASH : public TShockwaveFlash
{
private:
void __fastcall CMMouseEnter(TMessage &Message);
void __fastcall CMMouseLeave(TMessage &Message);
void __fastcall CMMouseDown(TMessage &Message);

String FlashCursor;
public:
__fastcall TImageFLASH(TComponent *Owner);

BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(CM_MOUSEENTER, TMessage, CMMouseEnter)
VCL_MESSAGE_HANDLER(CM_MOUSELEAVE, TMessage, CMMouseLeave)
VCL_MESSAGE_HANDLER(WM_LBUTTONDOWN, TMessage, CMMouseDown)
END_MESSAGE_MAP(TShockwaveFlash)
};

//-->end of header

//All functions has expansions in cpp file.
void __fastcall TImageGIF::CMMouseEnter(TMessage &Message)
{
TImage::Dispatch(&Message);
Timer1->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TImageGIF::CMMouseLeave(TMessage &Message)
{
TImage::Dispatch(&Message);
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TImageFLASH::CMMouseEnter(TMessage &Message)
{
TShockwaveFlash::Dispatch(&Message);
Timer1->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TImageFLASH::CMMouseLeave(TMessage &Message)
{
TShockwaveFlash::Dispatch(&Message);
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TImageFLASH::CMMouseDown(TMessage &Message)
{
TShockwaveFlash::Dispatch(&Message);
I->Play();
}
//---------------------------------------------------------------------------

//Reading the Image XML file into structure array.
//same as i shown for news

//Creating controls at runtime : For .gif, .jpeg, .bmp, .jpg

TImageGIF *ImageGIF = new TImageGIF(Panel);
ImageGIF->Parent = picTickerPanel;
ImageGIF->AutoSize = true;
ImageGIF->Stretch = false;
ImageGIF->Top = Panel->Top + 1;
ImageGIF->Left = Left;
ImageGIF->Picture->LoadFromFile("c:\\some
path");
ImageGIF->Cursor = crHandPoint;
//assign events
ImageGIF->OnClick = ImageGIFClick;
ImageGIF->Visible = true;

//For .swf
TImageFLASH *ImageFLASH = new
TImageFLASH(Panel);
ImageFLASH->Parent = Panel;
ImageFLASH->Width = 300;
ImageFLASH->Height = 41;
ImageFLASH->Left = Left;
ImageFLASH->Top = Panel->Top;
ImageFLASH->Cursor = crHandPoint;
ImageFLASH->Visible = true;
ImageFLASH->Movie = "c:\\some path";

//I am sure about the alignment of lables and images everything fine.
//After i am starting a timer which scrolls this panel.at an interval of 25
milli seconds.
void __fastcall TfrmMain::Timer1Timer(TObject *Sender)
{
Panel->Left += 1;
}

While scrolling none of the events are triggering if the news and images
number is large and i don't have any problem when the number of news and
images are 10 - 15.

I tried to present the minimal code, I will appreciate for the any
suggestion,
Regards
SA
JD
2007-09-17 00:28:38 UTC
Permalink
"bar" <***@yahoo.co.in> wrote:
I haven't looked at this thread in detail but knowing that
you're using BCB6, I can tell you that CM_MOUSELEAVE is
unreliable. For more as to why, see here:

http://www.stevetrefethen.com/blog/IntroducingOnMouseEnterOnMouseLeaveEventsOnTControlInVCLForDelphi2006.aspx

As the article notes, the solution is to use the win32 API
TrackMouseEvent. For example:

class TfrmMain : public TForm
{
typedef TForm inherited;
private:
bool MouseIn; // gets initialized to zero (false)
void __fastcall DoOnMouseEnter();
MESSAGE void __fastcall WMMouseMove( TMessage &Message );
MESSAGE void __fastcall WMMouseLeave( TMessage &Message );
public:
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER( WM_MOUSEMOVE, TMessage, WMMouseMove )
VCL_MESSAGE_HANDLER( WM_MOUSELEAVE, TMessage, WMMouseLeave )
END_MESSAGE_MAP( inherited )
public:
};

//-------------------------------------------------------------
MESSAGE void __fastcall TfrmMain::WMMouseMove( TMessage &Message )
{
if( ! MouseIn ) DoOnMouseEnter();
inherited::Dispatch( &Message );
}
//-------------------------------------------------------------
MESSAGE void __fastcall TfrmMain::WMMouseLeave( TMessage &Message )
{
MouseIn = false;
// OnMouseLeave code goes here
inherited::Dispatch( &Message );
}
//-------------------------------------------------------------
void __fastcall TfrmMain::DoOnMouseEnter()
{
MouseIn = true;
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof( TRACKMOUSEEVENT );
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = Handle;
TrackMouseEvent( &tme );
// OnMouseEnter code goes here
}
//-------------------------------------------------------------

~ JD
bar
2007-09-18 08:11:55 UTC
Permalink
Hi JD, thanks for your inputs.

Evenafter i changed the code, i am having the same problem.
What i noticed is when i stop the Timer by clicking any button on the form,
then all the Label, Image events are occuring.

So have to stop the timer manually, i still didn't the proper solution.

Regards
SA
bar
2007-09-29 09:32:10 UTC
Permalink
Hi JD,
This code is working fine for the TForm.

I have a class created from TImage

class TImageGIF : public TImage
{

private:

bool MouseIn; // gets initialized to zero (false)
void __fastcall DoOnMouseEnter();
MESSAGE void __fastcall WMMouseMove( TMessage &Message );
MESSAGE void __fastcall WMMouseLeave( TMessage &Message );

public:

BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER( WM_MOUSEMOVE, TMessage, WMMouseMove )
VCL_MESSAGE_HANDLER( WM_MOUSELEAVE, TMessage, WMMouseLeave )
END_MESSAGE_MAP( TImage )

__fastcall TImageGIF(TComponent* Owner);
}

MESSAGE void __fastcall TImageGIF::WMMouseMove( TMessage &Message )
{

if( ! MouseIn ) DoOnMouseEnter();
inherited::Dispatch( &Message );
}
//-------------------------------------------------------------
MESSAGE void __fastcall TImageGIF::WMMouseLeave( TMessage &Message )
{
MouseIn = false;
Form1->Caption = "Left";
inherited::Dispatch( &Message );
}
//-------------------------------------------------------------

void __fastcall TImageGIF::DoOnMouseEnter()
{

MouseIn = true;
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof( TRACKMOUSEEVENT );
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = Handle; .
TrackMouseEvent( &tme );
// OnMouseEnter code goes here
Form1->Caption = "Entered";

}


I am getting a error
Undefine symbol Handle.

How can i give the handle of the TImage.
Even if i give Form1->Handle. Only MouseEnter is event is firing not Leave
event.

Thanks
SA

Remy Lebeau (TeamB)
2007-09-20 04:17:04 UTC
Permalink
Post by bar
abd.hWnd = frmMain->Handle;
That is a crash waiting to happen. The global frmMain pointer has not been
assigned yet while the constructor is still running. You should be using
the 'this' pointer instead (and you should be using it throughout the form's
code).

Also, you are not taking to account that the Handle may be recreated at
runtime after the constructor has exited. You should move your
SHAppBarMessage() calls to when form's HWND is actually allocated and
destroyed, such as in the CreateWnd() and DestroyWnd() methods.
Post by bar
SetWindowPos(abd.hWnd,HWND_TOPMOST,abd.rc.left,abd.rc.top,
abd.rc.right-abd.rc.left,abd.rc.bottom-abd.rc.top,
SWP_NOMOVE | SWP_NOSIZE);
Since you are telling the window not to move or resize, you should be
setting the x/y/cx/cy parameters to 0.
Post by bar
TilePicture->LoadFromFile("c:\some.gif");
<snip>
Post by bar
XMLNews = LoadXMLDocument("c:\News.xml");
You need to use double slashes.
Post by bar
ImageGIF->Top = Panel->Top + 1;
<snip>
Post by bar
ImageFLASH->Top = Panel->Top;
You are positioning the images in the wrong places. The Panel is the Parent
of the images, and the Top property is relative to the Parent, so you should
not be using the Panel's Top property like that.
Post by bar
Panel->Left += 1;
You can't use the '+=' operator with properties.
Post by bar
While scrolling none of the events are triggering if the news
and images number is large
It works fine for me when I tested it.
Post by bar
I tried to present the minimal code
But you did not post enough code to actually compile and test with.

In any case, I suggest to go to http://www.torry.net and download the
TAppBar class. I just tested it in BCB 6 and it works pretty well (after
correcting the code to give getter/setter methods to the published
properties, or else it won't compile in BCB).


Gambit
bar
2007-09-20 08:18:20 UTC
Permalink
Hi Remy
thanks for your time.
Post by Remy Lebeau (TeamB)
It works fine for me when I tested it.
can you please show me your cpp file in attachments to study it.
Best Regards
SA
bar
2007-09-23 06:41:19 UTC
Permalink
Hi Remy,
I modified the code that you suggested, no change in the performace.
I really appreciate if you show a minimal code that you did for scrolling.

Thanks
SA
Loading...