Solved

How can I use SetDlgItemText to send and display updates to a window when my app is not the desired focussed app?

Posted on 2006-07-18
20
619 Views
Last Modified: 2010-05-18
I currently successfully use
SetDlgItemText (hDlgNotify, ID_TEXT, s);
to updates a window called Notify that shows the user the percentage progress while loading my application.
(so I send "1%", "2%", "3%", etc to ID_TEXT).

However my problem is that if the user switches to another application while my application is loading, the above command no longer successfully works (so if for instance it was 3% loaded when they switched away from my application, then my dialog will wrongly continue to show 3% until my application finishes loading).

So how can I change the above code to successfully send and display the updated string to my dialog, yet not have to reset the focus to my application (since it would be annoying to the user if we tried to send the focus back to my application every percentage until my application finishes loading)?

0
Comment
Question by:reggieperrin
  • 10
  • 5
  • 4
  • +1
20 Comments
 
LVL 12

Assisted Solution

by:rajeev_devin
rajeev_devin earned 100 total points
ID: 17136420
Where you have called SetDlgItemText (hDlgNotify, ID_TEXT, s);
In some event handler ?
0
 
LVL 48

Assisted Solution

by:AlexFM
AlexFM earned 200 total points
ID: 17136432
Try this:

SetDlgItemText (hDlgNotify, ID_TEXT, s);
UpdateWindow(GetDlgItem(hDlgNotify, ID_TEXT));
0
 

Author Comment

by:reggieperrin
ID: 17136504
Rajeev, I call SetDlgItemText in a simple C function.

AlexFM, thank you for your suggestion: however, I tried it and it had no visible effect.

In case this additional information helps (and the following is so whether I try AlexFM's trick or not):
Once the counter is wrongly visibly stuck on a number (since the user change focus to other application), even return the focus to my application by clicking on the counting window does not restart the visible counter (though when it does invisibly reach 100%, my program does launch as expected).
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 200 total points
ID: 17136543
You could set up a timer by

   SetTimer(hDlgNotify, (UINT)this, 1000, TimerProc);

Then your TimerProc was called any second where you can make the update:

voidCALLBACK TimerProc(
  HWND hwnd,     // handle of window for timer messages
  UINT uMsg,     // WM_TIMER message
  UINT idEvent,  // timer identifier
  DWORD dwTime   // current system time
)
{
      MyDialog* pDlg = (MyDialog*)idEvent;
      LPCSTR s = pDlg->GetText();        
      SetDlgItemText (hwnd, ID_TEXT, s);
}

If you are thru you should reset the timer by calling KillTimer;


Regards, Alex

 
0
 

Author Comment

by:reggieperrin
ID: 17136552
I also tried:

UpdateWindow(hDlgNotify);


... however that didn't make a change either.

0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 17136724
Can you post your code ?
0
 

Author Comment

by:reggieperrin
ID: 17140606
Certainly. Here you go:
===================================================================


SetNotifyText("Application loading: 10 percent");


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int SetNotifyText (char *s)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// function used to send text string to update what is appearing in Notify dialog
      {
      SetDlgItemText (hDlgNotify, ID_TEXT, s); //send the value to ID_TEXT for display
      //DB 20Jul2006: tried to add next line and then the next line so that dialog will update even if user focusses on other application, but it didn't help
      //UpdateWindow(GetDlgItem(hDlgNotify, ID_TEXT));
      //UpdateWindow(hDlgNotify);
      return OK;
    }

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DLGPROC NotifyDlgProc (HWND hDlg, UINT message, LONG wParam, LONG lParam)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
      {
      switch (message)
            {
            case WM_INITDIALOG:
                  SetWindowText (hDlg, NotifyCaption);
                  return DLG_FOCUSED;
            default:
                  return DLG_NOTPROCESSED; /* indicates not processed */
            }
      return DLG_PROCESSED;
      }

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
HWND OpenNotifyBox (char *s)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
      {
      NotifyCaption=s;

      if (hDlgNotify && IsWindow(hDlgNotify)) //if an instance of this window is already on screen
            return NULL;  
      else
            return (hDlgNotify = ModelessDialogBox ((LPSTR)"Notify", lpprocNotifyDlg));
      }


============================
And here is the code from the .rc file that defines the NOTIFY dialog box:
============================


NOTIFY DIALOG DISCARDABLE  100, 32, 139, 17
STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Notify"
FONT 10, "System"
BEGIN
    CTEXT           "",ID_TEXT,0,4,139,8
END
0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 17143339
But where you are calling SetNotifyText.
It is not visible from the above code.
0
 

Author Comment

by:reggieperrin
ID: 17143430
It is the very first line of what I posted above:

SetNotifyText("Application loading: 10 percent");

0
 
LVL 12

Expert Comment

by:rajeev_devin
ID: 17143509
>> It is the very first line of what I posted above:
But it is not an iterative call.
I just want to see the function (or, message handler) from where you are calling SetNotifyText(...).
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:reggieperrin
ID: 17143721
No, it is not an iterative call. I have many SetNotifyText commands manually distributed throughout the sequence of events that occur during the startup of my application, which present various phrases describing where we are at with the load.
The challenge here is not to help me get it to spin from 1 to 100.
The challenge is simply to get the Notify dialog to continue to display the phrases sent to it while my application does not have focus.
0
 

Author Comment

by:reggieperrin
ID: 17300895
With some experimentation, I discovered an additional fact that may help shed light on the problem: the failure to display extends not only to the text of the SetDlgItemText command... bitmap images included in the original paint of the window are invisible after switching from the other application.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 17301180
Did you try the timer solution I posted above?

You need to call the display functions as a reply to events that were created continuously while your prog is running. If you call the display functions only to events that occur while your prog has the focus you won't see anything while the prog is in the background.

Regards, Alex
0
 

Author Comment

by:reggieperrin
ID: 17301252
I did not try the timer solution you posted, because it appears to be a solution for me to provide the user a sense of % progress, and I simply want to send static phrases to my dialog. (Please tell me if I am misunderstanding).

My problem is that even when my program returns to being in the foreground, the dialog's contents are wrongly blank (i.e. both the bitmap and the text string which appeared within the dialog when it was launched wrongly no longer are visible...or sometimes the text string is still visible but only displaying the text it was last sent when my application was still in the foreground).
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 17301372
>>>> Please tell me if I am misunderstanding

Your prog runs a message pump. In order to draw bitmaps or text you need a WM_PAINT message issued by somewhat. This somewhat can be another event handling e. g. issued by a timer event. These timer events where generated when the pump is idle. In order to keep the pump running you need events that contiguously are generating messages. These doesn't need necessarily to be timer messages. You also could permanantly make your  display invalid by calling any of the Invalidate functions after each display. That would generate a new WM_PAINT message and so on ... However, a timer that generates an event say all seconds does consume much less resources and system overall performance than a permanent refresh of your screens.

Regards, Alex
0
 

Author Comment

by:reggieperrin
ID: 17348268
Thank you, however I am grappling with understanding what you are saying.
Am I correct that what you are saying is that the only way I can send messages to this dialog in a manner that will avoid the dialog's contents undesireably becoming blank after switching to and returning from another application is to set up a routine which is resending messages to that dialog every second or so?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 17395426
>>>> what you are saying is that the only way I can send messages to this dialog

No, I didn't say that it is the only way. But, I said that you need to keep your windows application running the message loop to get your screen(s) refreshed. If for example you were listening to a socket where you got messages and could actualize your screens by that it is no problem. The same applies if your prog was doing somewhat the whole time such as reading from an external device or copying data or ... In any case it is no problem to refresh (paint) the screens. But if you don't get any events - just wait for the user to activate your application you would need to generate events yourself - e. g. by a timer.

Regards, Alex
0
 

Author Comment

by:reggieperrin
ID: 17395912
Hi, Alex. Thank you for taking the time to explain this: unfortunately, I'm still foggy on what you mean, due to my lack and knowlege and experience. Is it possible that that we could text chat about this or something like that so I could get to the place where I understand what you are talking about? Thank you in advance for sticking with me on this: I do think I am close to "getting it".
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 17402398
The main issue is that any Windows program is reacting and not acting. That means it reacts on Windows Messages like WM_PAINT, WM_KEYDOWN, and others.

Some of these - like WM_KEYDOWN - were caused by user event. Your prog only reacts on them - or better gets the appropriate message - if it is activated, means one of your windows has the focus. To handle messages any windows program runs a so-called message pump. That is an infinite loop like

   while (PeekMessage(...))
   {
       TranslateMessage(...);
       DispatchMessage(...);
   }

The DispatchMessage is responsible to call the appropriate handler function.

In order to refresh the screens you need to get a WM_PAINT message, normally caused by a SendMessage(WM_PAINT, ...) or PostMessage(WM_PAINT, ...) called by the operation system if some of the screen output was invalid. However, if your prog is in the background and the foreground prog doesn't invalidate (change) some or one  of the open windows your prog doesn't get a WM_PAINT message, hence the screens were not refreshed.

Your call to SetDlgItemText normally should refresh the screens. Maybe you set the clipping options in your dialog resource so that the invalidation doesn't work. You could try to correct this by explicitly invalidating your dialog window. Call CWnd::Invalidate if using MFC or InvalidateRect(hwndDlg, ...) if using WINAPI only.

Regards, Alex


0
 

Author Comment

by:reggieperrin
ID: 17453301
Well, I kind of solved it by destroying and recreating the window every so often. However this solution, and the solution regarding InvalidateRect suggested above, do have the shortcoming of undesirably returning focus to my application potentially earlier than the user desires.
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now