Board index » cppbuilder » Stay on top problem

Stay on top problem


2004-05-15 06:47:57 AM
cppbuilder7
In my program I have a main form and 8 subforms, the main form is neven
shown, only the subforms.
The program is shown in the tray with a popupmenu to open the other
subforms, a few of the subforms
I would like to have always on top.
I set the formstyle to fsStayOnTop but that seems to have no effect
(tried setting this on all forms, even the main form that is hidden)
If I create a new application with only one form and set formstyle to
fsStayOnTop it works, but not when I have many forms, anyone
know what I can do about this?
/Jonas
 
 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
[...] anyone know what I can do about this?
Have you tried overriding the form's CreateParams?
void __fastcall TForm1::CreateParams(TCreateParams& Params)
{
// just a sample
TForm::CreateParams(Params);
Params.Style &= ~(WS_CAPTION | WS_SIZEBOX | WS_POPUP);
Params.Style |= WS_CHILD | WS_BORDER;
Params.ExStyle |= WS_EX_PALETTEWINDOW;
Params.WindowClass.style |= CS_SAVEBITS;
}
If you look in the win32.hlp under CreateWindow(Ex), you'll
see WS_EX_TOPMOST. If you read what it says about WS_EX_TOPMOST
you'll see that you can also use SetWindowPos to accomplish
what you're asking. Instead of using Show or what ever to
display the form:
SetWindowPos( Form1->Handle, HWND_TOPMOST, Form1->Left, Form1->Top, Form1->Width, Form1->Height, SWP_SHOWWINDOW );
~ JD
 

Re:Stay on top problem

Thanks, yes I have tried SetWindowPos but I couldnt get it to work with that
either, it's possible that
I had some parameter wrong. I will test more with what you suggested
tomorrow, need to sleep now.
/Jonas
"JD" < XXXX@XXXXX.COM >skrev i meddelandet
Quote

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
>[...] anyone know what I can do about this?

Have you tried overriding the form's CreateParams?

void __fastcall TForm1::CreateParams(TCreateParams& Params)
{
// just a sample
TForm::CreateParams(Params);
Params.Style &= ~(WS_CAPTION | WS_SIZEBOX | WS_POPUP);
Params.Style |= WS_CHILD | WS_BORDER;
Params.ExStyle |= WS_EX_PALETTEWINDOW;
Params.WindowClass.style |= CS_SAVEBITS;
}

If you look in the win32.hlp under CreateWindow(Ex), you'll
see WS_EX_TOPMOST. If you read what it says about WS_EX_TOPMOST
you'll see that you can also use SetWindowPos to accomplish
what you're asking. Instead of using Show or what ever to
display the form:

SetWindowPos( Form1->Handle, HWND_TOPMOST, Form1->Left, Form1->Top,
Form1->Width, Form1->Height, SWP_SHOWWINDOW );

~ JD

 

{smallsort}

Re:Stay on top problem

I think what my problem is that I can't get any subforms to be on top.
I tried now to create a new application with two forms and set them to
fsStayOnTop and only the main form
stays on top, just like in my other program.
/Jonas
"JD" < XXXX@XXXXX.COM >skrev i meddelandet
Quote

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
>[...] anyone know what I can do about this?

Have you tried overriding the form's CreateParams?

void __fastcall TForm1::CreateParams(TCreateParams& Params)
{
// just a sample
TForm::CreateParams(Params);
Params.Style &= ~(WS_CAPTION | WS_SIZEBOX | WS_POPUP);
Params.Style |= WS_CHILD | WS_BORDER;
Params.ExStyle |= WS_EX_PALETTEWINDOW;
Params.WindowClass.style |= CS_SAVEBITS;
}

If you look in the win32.hlp under CreateWindow(Ex), you'll
see WS_EX_TOPMOST. If you read what it says about WS_EX_TOPMOST
you'll see that you can also use SetWindowPos to accomplish
what you're asking. Instead of using Show or what ever to
display the form:

SetWindowPos( Form1->Handle, HWND_TOPMOST, Form1->Left, Form1->Top,
Form1->Width, Form1->Height, SWP_SHOWWINDOW );

~ JD

 

Re:Stay on top problem

Interesting, found this on another forum
"It does work, if you use it on a secondary form (not the main form). The
VCL
removes the topmost style from secondary forms when the application looses
focus,
and restores it when the app gains focus again" - Peter Below (TeamB)
Can I do something to get around this?
"Jonas Andersson" < XXXX@XXXXX.COM >skrev i meddelandet
Quote
I think what my problem is that I can't get any subforms to be on top.
I tried now to create a new application with two forms and set them to
fsStayOnTop and only the main form
stays on top, just like in my other program.

/Jonas


"JD" < XXXX@XXXXX.COM >skrev i meddelandet
news:40a551d3$ XXXX@XXXXX.COM ...
>
>"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
>>[...] anyone know what I can do about this?
>
>Have you tried overriding the form's CreateParams?
>
>void __fastcall TForm1::CreateParams(TCreateParams& Params)
>{
>// just a sample
>TForm::CreateParams(Params);
>Params.Style &= ~(WS_CAPTION | WS_SIZEBOX | WS_POPUP);
>Params.Style |= WS_CHILD | WS_BORDER;
>Params.ExStyle |= WS_EX_PALETTEWINDOW;
>Params.WindowClass.style |= CS_SAVEBITS;
>}
>
>If you look in the win32.hlp under CreateWindow(Ex), you'll
>see WS_EX_TOPMOST. If you read what it says about WS_EX_TOPMOST
>you'll see that you can also use SetWindowPos to accomplish
>what you're asking. Instead of using Show or what ever to
>display the form:
>
>SetWindowPos( Form1->Handle, HWND_TOPMOST, Form1->Left, Form1->Top,
Form1->Width, Form1->Height, SWP_SHOWWINDOW );
>
>~ JD
>


 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
[...] Can I do something to get around this?
In my tests I got it to work by setting both the Main form's
and the secondary (child) form's FormStyle to fsStayOnTop,
dynamically allocating the secondary form and using CreateParams:
//-------------------------------------------------------------
void __fastcall TForm2::CreateParams(TCreateParams& Params)
{
TForm::CreateParams(Params);
Params.WndParent = ::GetDesktopWindow();
Params.Style |= WS_CHILD | WS_VISIBLE;
Params.ExStyle |= WS_EX_TOPMOST;
Params.WindowClass.style |= CS_SAVEBITS;
}
//-------------------------------------------------------------
In the project.cpp file, remove refrences to secondary forms:
//-------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//-------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//USEFORM("Unit2.cpp", Form2);
//-------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
// Application->CreateForm(__classid(TForm2), &Form2);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//-------------------------------------------------------------
In the Main form's header, declare a public pointer of secondary form's type:
//-------------------------------------------------------------
public:
TForm2* pForm2;
//-------------------------------------------------------------
In the main form's constructor, set the secondary form pointers to NULL:
//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
pForm2 = NULL;
}
//-------------------------------------------------------------
In the menu click that allocates the form:
//-------------------------------------------------------------
if( !pForm2 ) pForm2 = new TForm2( NULL );
if( pForm2 ) pForm2->SetFocus();
//-------------------------------------------------------------
To free allocated memory:
//-------------------------------------------------------------
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
Form1->pForm2 = NULL;
Action = caFree;
}
//-------------------------------------------------------------
If you don't care about multiple instances of the form then
you don't need all the form pointer stuff. You can also
prevent multiple instance without the pointers if you disable
the popup menu item in Form2's constructor and re-enable in
the OnClose event.
As a note: I couldn't get the 2nd form to update it's position
as it was being dragged until I released the mouse. You
probably can fix this by overriding the WndProc method and
refreshing the form when you receive a WM_MOVING message.
~ JD
 

Re:Stay on top problem

Thank you!
"JD" < XXXX@XXXXX.COM >skrev i meddelandet
Quote

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
>[...] Can I do something to get around this?

In my tests I got it to work by setting both the Main form's
and the secondary (child) form's FormStyle to fsStayOnTop,
dynamically allocating the secondary form and using CreateParams:
//-------------------------------------------------------------
void __fastcall TForm2::CreateParams(TCreateParams& Params)
{
TForm::CreateParams(Params);
Params.WndParent = ::GetDesktopWindow();
Params.Style |= WS_CHILD | WS_VISIBLE;
Params.ExStyle |= WS_EX_TOPMOST;
Params.WindowClass.style |= CS_SAVEBITS;
}
//-------------------------------------------------------------


In the project.cpp file, remove refrences to secondary forms:
//-------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//-------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//USEFORM("Unit2.cpp", Form2);
//-------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
// Application->CreateForm(__classid(TForm2), &Form2);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//-------------------------------------------------------------


In the Main form's header, declare a public pointer of secondary form's
type:
//-------------------------------------------------------------
public:
TForm2* pForm2;
//-------------------------------------------------------------


In the main form's constructor, set the secondary form pointers to NULL:
//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
pForm2 = NULL;
}
//-------------------------------------------------------------


In the menu click that allocates the form:
//-------------------------------------------------------------
if( !pForm2 ) pForm2 = new TForm2( NULL );
if( pForm2 ) pForm2->SetFocus();
//-------------------------------------------------------------


To free allocated memory:
//-------------------------------------------------------------
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
Form1->pForm2 = NULL;
Action = caFree;
}
//-------------------------------------------------------------

If you don't care about multiple instances of the form then
you don't need all the form pointer stuff. You can also
prevent multiple instance without the pointers if you disable
the popup menu item in Form2's constructor and re-enable in
the OnClose event.

As a note: I couldn't get the 2nd form to update it's position
as it was being dragged until I released the mouse. You
probably can fix this by overriding the WndProc method and
refreshing the form when you receive a WM_MOVING message.

~ JD

 

Re:Stay on top problem

I got it to work but I can't click any buttons or write in any edit boxes
that I have on that form. Is there some
message handling that I need to enable or something?
/Jonas
"JD" < XXXX@XXXXX.COM >skrev i meddelandet
Quote

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
>[...] Can I do something to get around this?

In my tests I got it to work by setting both the Main form's
and the secondary (child) form's FormStyle to fsStayOnTop,
dynamically allocating the secondary form and using CreateParams:
//-------------------------------------------------------------
void __fastcall TForm2::CreateParams(TCreateParams& Params)
{
TForm::CreateParams(Params);
Params.WndParent = ::GetDesktopWindow();
Params.Style |= WS_CHILD | WS_VISIBLE;
Params.ExStyle |= WS_EX_TOPMOST;
Params.WindowClass.style |= CS_SAVEBITS;
}
//-------------------------------------------------------------


In the project.cpp file, remove refrences to secondary forms:
//-------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//-------------------------------------------------------------
USEFORM("Unit1.cpp", Form1);
//USEFORM("Unit2.cpp", Form2);
//-------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
// Application->CreateForm(__classid(TForm2), &Form2);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (...)
{
try
{
throw Exception("");
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
}
return 0;
}
//-------------------------------------------------------------


In the Main form's header, declare a public pointer of secondary form's
type:
//-------------------------------------------------------------
public:
TForm2* pForm2;
//-------------------------------------------------------------


In the main form's constructor, set the secondary form pointers to NULL:
//-------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
pForm2 = NULL;
}
//-------------------------------------------------------------


In the menu click that allocates the form:
//-------------------------------------------------------------
if( !pForm2 ) pForm2 = new TForm2( NULL );
if( pForm2 ) pForm2->SetFocus();
//-------------------------------------------------------------


To free allocated memory:
//-------------------------------------------------------------
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
Form1->pForm2 = NULL;
Action = caFree;
}
//-------------------------------------------------------------

If you don't care about multiple instances of the form then
you don't need all the form pointer stuff. You can also
prevent multiple instance without the pointers if you disable
the popup menu item in Form2's constructor and re-enable in
the OnClose event.

As a note: I couldn't get the 2nd form to update it's position
as it was being dragged until I released the mouse. You
probably can fix this by overriding the WndProc method and
refreshing the form when you receive a WM_MOVING message.

~ JD

 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
I got it to work but I can't click any buttons or write in any edit boxes
that I have on that form. Is there some
message handling that I need to enable or something?
Dunno - didn't take it that far. Let me check ...
~ JD
BTW: You should be t{*word*220} your posts.
 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
I got it to work but I can't click any buttons or write in
any edit boxes that I have on that form.
Using WS_CHILD in the Params.Style was the guilty {*word*81} so I
just removed the entire line which included WS_VISIBLE which
also means that you need to do a bit more when allocating the
form:
//-------------------------------------------------------------
void __fastcall TForm2::CreateParams(TCreateParams& Params)
{
TForm::CreateParams(Params);
Params.WndParent = ::GetDesktopWindow();
Params.ExStyle |= WS_EX_TOPMOST;
Params.WindowClass.style |= CS_SAVEBITS;
}
//-------------------------------------------------------------
Quote
>In the menu click that allocates the form:
//-------------------------------------------------------------
if( !pForm2 ) pForm2 = new TForm2( NULL );
if( pForm2 )
{
pForm->Visible = true;
pForm2->SetFocus();
}
//-------------------------------------------------------------
~ JD
 

Re:Stay on top problem

It's working like I want it to, your help is most appreciated, just
wondering one thing though
I didnt use the TForm2 pointer like you did with creating it as a public
member in TForm1,
I used the TForm2 pointer that is already declared at the top of Unit2.cpp,
the same as is used in
Application->CreateForm(...) (that's no longer used)
It's working good but just wanted to know this is ok, you don't see a
problem with this?
/Jonas
 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
[...] you don't see a problem with this?
My only objective was to create a method that prevented
multiple instances AND was exception safe.
If your code does this (and you're still using caFree) ...
a rose by another name ....
~ JD
 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
[...] you don't see a problem with this?
Just a note: Typically one retains a pointer to an object so
that one can, at the appropriate time, delete it. As long as
the OnClose uses caFree the form will be properly destroyed
regardless of whether you retained a pointer to it or not.
So .... once it's been allocated and receives focus, you don't
need a pointer to it at all. Therefore you can use a local
variable that get's popped of the stack as soon as the user
creates it:
void __fastcall TMain::MenuForm2Click(TObject* Sender)
{
TForm2* pForm = new TForm2( NULL );
pForm->Show();
}
~ JD
 

Re:Stay on top problem

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
Quote
I'm not sure if I did it right but in the Form1 OnCreate
You should not be using the OnCreate event:
www.bcbdev.com/articles/suggest.htm
use the constructor instead. However, allocating the form there
(in the constructor or OnCreate for that matter) means that the
form instance is always allocated which means that you have a
potential memory leak unless you add a destructor to the main
form where you delete form2.
Quote
[...] I put the form2 = new Form2(NULL);
That doesn't look right. You're missing a 'T'
form2 = new TForm2( NULL );
Quote
and in form1 OnClose I have form2->Free();
Do not call Free directly. Use delete instead and that should
be moved to the destructor instead.
You're making it more complicated than you need to trying to
simplify my example. You need to go back in this thread and
look at how I showed allocating the form and using caFree in
the OnClose event to delete it.
~ JD
 

Re:Stay on top problem

I'm not sure if I did it right but in the Form1 OnCreate I put the form2 =
new Form2(NULL);
and in form1 OnClose I have form2->Free();
/Jonas
"JD" < XXXX@XXXXX.COM >skrev i meddelandet
Quote

"Jonas Andersson" < XXXX@XXXXX.COM >wrote:
>[...] you don't see a problem with this?

Just a note: Typically one retains a pointer to an object so
that one can, at the appropriate time, delete it. As long as
the OnClose uses caFree the form will be properly destroyed
regardless of whether you retained a pointer to it or not.