|
Hi PJ
Just Tried this,
No Avail.
The Problem appears to be in the Kernal, it appears to receive the Paint messages, but only actually paint the screen in it's own good time.
LateNightsInNewry
|
|
|
|
|
LateNightsInNewry wrote: The ShowWindow(SW_HIDE) causes the Entire App to disapear off the horizon
Of course it does. This is what you wanted, right? If you hide the main window then all the
children get hidden too.
DoSomethingVerryLengthy() is in OnInitDialog()?
If so, that won't work well...there's still a bunch of messages that need to be processed before
the window displays - a few WM_SIZEs, etc. then finally a WM_PAINT. If you want the window
comletely initialized and displayed BEFORE DoSomethingVerryLengthy() then maybe post a message to
yourself from OnInitDialog() and in response to that message then DoSomethingVerryLengthy().
No extra threads should be necessary here, a least for the UI - this isn't even real-time screen
updating - just simple window updates.
Putting DoSomethingVerryLengthy() on a separate thread is an option tough.
Remember that if DoSomethingVerryLengthy() is running on COtherDlg's UI thread then you need
to pump messages periodically if you expect the dialog to stay responsive.
Hope that made sense I'm still not caffeinated this morning!
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Mark Salsbery wrote: DoSomethingVerryLengthy() is in OnInitDialog()?
Mark Salsbery wrote: Of course it does. This is what you wanted, right? If you hide the main window then all the
children get hidden too.
Hi Mark,
Thanks, Also see my other reply.
That's the Nub of the problem, I am calling ShowWindow(SW_HIDE) from a Child Window, NOT the Main Window The Main Window was separately created on the heap, and just displays a bitmap to act as background.
What I want to keep displayed is the Background Bitmap Window, which appears to get clobbered for no good reason. The Question is, to stop it getting clobbered, or, to repaint it before any shenanigans in OnInitDialog();
DoSomethingVerryLengthy() is in OnInitDialog()?
It is fully acceptable and desirable that the Dialog being initialised is not displayed untill OnInitDialog() terminates. (have NO Usefull data to display untill DoSomethingVerryLengthy() completes).
I am NOT worried about displaying this one until much later, i.e. After DoSomethingVerryLengthy() has completed.
The Problem is the Disappearance of the Background window.
Thanks for your comments sofar, they have been helpfull.
regards,
LateNightsInNewry
|
|
|
|
|
Thanks to your extended description of what you have going on I think this post is outdated
(see my other reply minutes ago).
There's still a concern if DoSomethingVerryLengthy() doesn't do anything UI related. If that's
the case then there's definitely a problem having it in OnInitDialog(). Actually, until you
return from OnInitDialog() the UI isn't going to refresh.
Where does DoSomethingVerryLengthy() fit in to your latest detailed post (which window class)?
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Also...
The point I'm trying to make is that OnInitDialog is just called in response to one of the many
messages that get sent to a window during creation before the window is displayed. Trying to
do any UI updating in there won't work well Therefore, it works best to let the window be
entirely created and displayed before doing something else, especially something lengthy.
An alternative to posting yourself a message in OnInitDialog() is to start the
DoSomethingVerryLengthy() externally (via a method call) from the window that created the dialog.
I mean something like:
pOtherDlg = new COtherDlg(...);
pOtherDlg->Create(...);
//** Optional if pOtherDlg not created with WS_VISIBLE style **
pOtherDlg->ShowWindow(SW_SHOW);
pOtherDlg->UpdateWindow();
//** End Optional if pOtherDlg not created with WS_VISIBLE style **
pOtherDlg->DoSomethingVerryLengthy();
Come on, caffeine
Cheers!
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Hi Mark,
I've read your advice, and there are several points of which I want to take on board. However, I also think that a number of issues are not clear, mainly through me not explaining propperly, so here we go:-
The Application is based on a Dialog Based MFC Wizzard Application, with the following modifications:
By default,the MFC Wizzard initializes m_pMainWnd with &MyAppDlg in
CMyApp::InitInstance(). This Code was Changed as follows:
m_pMainWnd = new CBckGndWnd();
((CMainWnd*)m_pMainWnd)->DisplayBitMap("SalesCounter.bmp");
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED );
m_pMainWnd->UpdateWindow();
This Window is intended to stay on the screen until the App Dies. Multiple Apps open on the screen is something this app tries to avoid. All Apps in this suite are designed to run on Full Screen only. People using my stuff are sales operatives, no computer literacy is assumed, They are at All times shown a Clear and Well defined Full Screen Interface. One place where you may see such thing is on a Supermarket Check-out.
It is this CBckGndWnd Bitmap window that I want to remain displayed as background to the app at all times. This window's code appears to work, and displays the Full Screen Bitmap as advertised, most of the time.
By the way this window has NO other task, other than to show on the display.
After starting this BitmapWindow on the heap, InitInstance() does some more initialisation, and hits the function:
RunCounterProcess();
This 'RunCounterProcess' Function is an Endless Loop which Starts with displaying a Dialog Box, 'CStartTransactionDlg'.
This DialogBox has an Edit Control and various buttons, each to pick an Option. The Standard response would be to enter a Customer ID Number into the Edit Control,
Sofar Sogood, No Problems.
Now After Doing this, the Girl clicks the Button 'FindCustomer', and Control passes to the handler: 'CStartTransactionDlg::OnFindCustomer()'
OnFindCustomer() does some validation and initialisation, and calls in turn something like this:-
ShowWindow(SW_HIDE);// Hides CStartTransactionDlg
CCustomerAccountDlg Dlg(pCurrentCustomer,FLAG_SHOWACCOUNT|FLAG_ALLOWPAYMENT);
Dlg.DoModal();
ShowWindow(SW_SHOWNORMAL);// Show CStartTransactionDlg
Note That ON THIS OCCASION 'ShowWindow(SW_HIDE)' is called from 'CStartTransactionDlg', WHICH IS NOT THE MAIN WINDOW!!!, But Rather, This Dialog Box is displayed ON TOP OF the Main Window.(i.e. the Bitmap!)
The Problem is, that ShowWindow(SW_HIDE) does not only seem to affect the CStartTransactionDlg from where it was called,and which we intend to hide, but also hides momentarily an unintended window, the CBckGndWnd() m_pMainWnd. To Reiterate, the instance of CStartTransactionDlg, which we hide, is NOT the Application's main window, the instance of CBckGndWnd is!!
This is fine, and works well albeit with some anoying flashing, if the instance of CCustomerAccountDlg initialises quickly. If that is slow, the app, i.e. the background bitmap disappears off the screen for more or less the duration of CCustomerAccountDlg::InitDialog(). In other words, No messages can be processed by the Procedure for 'CBckGndWnd' whilst CCustomerAccountDlg is processing WM_INITDIALOG. This is not surprising, afterall there is only one thread.
I can Only see two ways of attack:-
-Stop ShowWindow(SW_HIDE) from interfering with the Background Window
-Force the Background Window to complete Re-paint, before we start the Next Dialog
So, to recap:
What I am realy looking for is something like:
MagicFuncToStopInterferenceWithBackground();
ShowWindow(SW_HIDE);// Hides CStartTransactionDlg
MagicCodeToRepaintCBckGndWndIfAboveFails();
// And Now, on a Full Background:-
CCustomerAccountDlg Dlg(pCurrentCustomer,FLAG_SHOWACCOUNT|FLAG_ALLOWPAYMENT);
Dlg.DoModal();
ShowWindow(SW_SHOWNORMAL);// Show CStartTransactionDlg
The sad point is that the above software was written some five years age. A new version is due for 2008, which fundamentally avoids the above pitfalls. It is also a problem which only became noticable some time ago, when the database had grown to such a size that search times have become non trivial. Needless to say, I am reluctant to start multythreading an app at the end of it's life cycle. At the same time, I want to do something to remove these glitches, if at all possible with reasonable efford. Beside that, I want to find out for the future what to do to avoid this sort of thing.
Sorry for the length of this, but I hope it explains what I want to achieve
Thanks,
LateNightsInNewry
|
|
|
|
|
LateNightsInNewry wrote: Sorry for the length of this, but I hope it explains what I want to achieve
Sorry you had to type all that
The key is to get all windows updated/refreshed before any lengthy process.
I'm going to assume your endless loop sits idle (using no CPU)...correct? That'll keep everything
else snappy.
You should just have to do something like this:
ShowWindow(SW_HIDE);// Hides CStartTransactionDlg
pMainWnd->UpdateWindow();
// And Now, on a Full Background:-
CCustomerAccountDlg Dlg(pCurrentCustomer,FLAG_SHOWACCOUNT|FLAG_ALLOWPAYMENT);
Dlg.DoModal();
pMainWnd->UpdateWindow(); // this one shouldn't be necessary, but WTH, it's cheap
ShowWindow(SW_SHOWNORMAL);// Show CStartTransactionDlg
Get the pMainWnd any way that's appropriate - passed in to class object instance, gobal variable,
method of ap class, etc.
The MagicFuncToStopInterferenceWithBackground() and MagicCodeToRepaintCBckGndWndIfAboveFails()
APIs won't be out until 2020 or so.
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Heh I'm trying to stay on this sub-thread...
Here's my code (adjusted from yours) from my first response:
ShowWindow(SW_HIDE);// Hides CStartTransactionDlg
pMainWnd->UpdateWindow();
// And Now, on a Full Background:-
CCustomerAccountDlg Dlg(pCurrentCustomer,FLAG_SHOWACCOUNT|FLAG_ALLOWPAYMENT);
Dlg.DoModal();
pMainWnd->UpdateWindow(); // this one shouldn't be necessary, but WTH, it's cheap
ShowWindow(SW_SHOWNORMAL);// Show CStartTransactionDlg
If that's not enough then maybe a message pump is necesasary (I do this in my real-time video
software because I want windows completely drawn before starting video....it's more pleasing to
the users)
void _PumpWaitingMessages()
{
MSG msg;
while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
{
if ( !AfxGetApp()->PumpMessage( ) )
{
::PostQuitMessage(0);
break;
}
}
}
...
CStartTransactionDlg::OnFindCustomer()
{
ShowWindow(SW_HIDE);
pMainWnd->UpdateWindow();
_PumpWaitingMessages();
CCustomerAccountDlg Dlg(pCurrentCustomer,FLAG_SHOWACCOUNT|FLAG_ALLOWPAYMENT);
Dlg.DoModal();
pMainWnd->UpdateWindow();
ShowWindow(SW_SHOWNORMAL);
}
*EDIT* Here's where the lengthy operation in OnInitDialog() comes in.
Normally, Dlg.DoModal(); will pump messages to refresh all the thread's windows.
If you do something lengthy in CCustomerAccountDlg::OnInitDialog(), though, then you have
interrupted the dialog's creation process and all those messages stuck in the queue don't
get processed - the dialog hasn't even entered the modal loop yet.
If this is the case, then I still recommend that within CCustomerAccountDlg, you post a user-
defined message to yourself (e.g. PostMessage(WM_STARTLENGTHYPROCESS)) from the end of
OnInitDialog() and in response to that message, start the lengthy process (instead of starting
the lengthy process from OnInitDialog()).
Mark
-- modified at 20:16 Tuesday 20th February, 2007
-- modified at 20:18 Tuesday 20th February, 2007
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Hi Mark,
Tried your Suggestion, and Actually had tried that already in similar form previously some months ago, (when that did not work, desperation started to set in) It does NOT work unfortunately. I cannot send you my code for licence reasons, at the same time, I do not think that you want to wade through some 148 MByte of Source code to find the problem.
Hence I propose to write a mini DemoApp in the next few days to demonstrate the problem I'll find out a way of getting it to you, or, maybe you suggest a way how to receive it
Thanks and Regards,
LateNightsInNewry
|
|
|
|
|
A mini demo app reproducing the problem would be great
I still think the UI thread is tied up preventing paints. If the background bitmap never repaints
then something is up elsewhere.
I'll definitely take a look at it though!
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Hi Mark,
Understand all that, but it seems to be an answer to the wrong question. I am NOT trying to paint a Dialog in the middle of creation. Rather,I want to keep an Entirely Unrelated Window on the heap which acts as visual background, painted on the screen at all times. Unfortunately it gets clobbered, I try to repaint before starting something lengthy, just does not happen.
Thanks for your much appreciated comments.
Regards,
LateNightsInNewry
|
|
|
|
|
LateNightsInNewry wrote: I am NOT trying to paint a Dialog in the middle of creation. Rather,I want to keep an Entirely Unrelated Window on the heap which acts as visual background, painted on the screen at all times. Unfortunately it gets clobbered, I try to repaint before starting something lengthy, just does not happen.
Right I'm following you
All the windows on a given UI thread use the same message loop so even tieing up a child window's
creation will effect underlying parent windows messages.
In OnInitDialog() you are in the middle of handling the WM_INITDIALOG message. Until you
return from that, all the WM_PAINT (and other) messages for all the windows on the thread are
stuck in the queue.
All messages involved in redrawing the clobbered background window need to be flushed and
dispatched before entering any new lengthy operation, unless that operation is going to
periodically pump the waiting messages (and again, OnInitDialog() is a bad place for that...the
window isn't fully created and displayed yet).
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
From the MFC Help Files:
Windows sends a WM_PAINT message whenever the CWnd update region is not empty and there are no other messages in the application queue for that window.
I Need the WM_PAINT Message to be sent Independent of the Message queue
LateNightsInNewry
|
|
|
|
|
BTW, from the UpdateWindow() docs:
"The function sends a WM_PAINT message directly to the window procedure of the specified window,
bypassing the application queue. If the update region is empty, no message is sent."
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Hi Mark,
Found that one too, secs after posting, but for some reason Windows does not appear to do the actual painting. See my response 3 mins ago. Suggest we return to that thread.
LateNightsInNewry
|
|
|
|
|
Hi all,
I need to create 4 MDI child windows at the start of the program for displaying 4 different pictures, please help.
regards
|
|
|
|
|
What (more specifically) is giving you trouble? When the windows are created? How the windows
are created? Are you using Doc/View architecture?
Mark
Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it.
|
|
|
|
|
Hi Mark,
I am using Doc/View, I am just not quite familiar about the usage of CWnd::Create(), not sure where/how to use it to make 4 child windows at same time.
regards,
|
|
|
|
|
CWnd::Create won't help here. Since you are using MDI then you need to create MDI child windows
(CMDIChild) which are derived from CFrameWnd.
There's lots of ways to do this...
For pure doc/view (You have a document class, view class, and a CMultiDocTemplate associating
these) you can use the doc template and the CDocTemplate::CreateNewFrame method to create an
MDIChildWnd from a loaded document.
If you don't want to use doc/view then you can use
a) CMDIFrameWnd::CreateNewChild()
b) CFrameWnd::LoadFrame()
c) create a CMDIChildWnd (or derived) object and use CMDIChildWnd::Create() to create the Windows
object for it.
Each of these methods require different known parameters so you can choose whichever method
suits your needs.
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
I checked many printing articles on CodeProject and CodeGuru
Need some help/guidance.
From my app (Environment - VC++ 6.0, MFC, Win98/2000/XP), I need to print single as well as batch of invoices and checks on dot-matrix printer
- print checks (multiple checks on single A4 page)
- print multiple invoices on one A4 or other custome size paper (e.g. 4 small-invoices on one A4 size papers)
Question is:
For dot-matrix printer, how to achieve printing such that if one invoice is printed in top 1/4 part of A4 paper, whole paper should not come out ? (User may cut printed portion of paper and aftter sometime may continue to print next invoice on same paper). (Similarly need to print one or more check)
Any sample or code snippet for such printing ?
I appreciate any help/guidance.
Anand_Arv
|
|
|
|
|
To use GDI to print then I imagine you'd need to change the paper size to a user-defined value
using the printer driver's configuration interface.
Mark
Great job, team. Head back to base for debriefing and cocktails.
|
|
|
|
|
Problem is...I need to print part of paper and then paper should not be ejected. How to achieve that ? (in an App developed with VC++/MFC and running on WinXP/Win98/Win2000)
Thanks a lot for helping.
Anand_Arv
|
|
|
|
|
I understand The problem is that to GDI, it's the paper size setting that causes the advance
to the next page when you call EndPage (or EndDoc) from your code.
If you set the paper size to 8.5 x 2.75 then it sould only advance 2.75.
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|
Mark Salsbery wrote: I understand The problem is that to GDI, it's the paper size setting that causes the advance
to the next page when you call EndPage (or EndDoc) from your code.
If you set the paper size to 8.5 x 2.75 then it sould only advance 2.75.
Thanks a lot for nice info.
Just curious to know...
Does this apply only to Dot Matrix Printer ?
i.e. For Laser/Inkjet printer, if I set paper size to 8.5 x 2.75 and use A4 paper, will it eject A4 paper fully or it will allow to continu printing on same paper ?
Anand
|
|
|
|
|
From my experience, a laser printer will eject the page at the end.
I'm no printing expert so I'm not sre how one can control it more precisely.
I know you could accumulate enough printing jobs to fill a sheet then do a page at a time.
Laser printers I've worked with didn't have a way to linefeed the paper and tear it off.
Maybe there's laser printers with continuous feed paper (rolls)?
I know dot matrix printers have escape codes to do it.
Mark
"Do you know what it's like to fall in the mud and get kicked... in the head... with an iron boot?
Of course you don't, no one does. It never happens. It's a dumb question... skip it."
|
|
|
|
|