[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 734
  • Last Modified:

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

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
reggieperrin
Asked:
reggieperrin
  • 10
  • 5
  • 4
  • +1
3 Solutions
 
rajeev_devinCommented:
Where you have called SetDlgItemText (hDlgNotify, ID_TEXT, s);
In some event handler ?
0
 
AlexFMCommented:
Try this:

SetDlgItemText (hDlgNotify, ID_TEXT, s);
UpdateWindow(GetDlgItem(hDlgNotify, ID_TEXT));
0
 
reggieperrinAuthor Commented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
itsmeandnobodyelseCommented:
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
 
reggieperrinAuthor Commented:
I also tried:

UpdateWindow(hDlgNotify);


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

0
 
rajeev_devinCommented:
Can you post your code ?
0
 
reggieperrinAuthor Commented:
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
 
rajeev_devinCommented:
But where you are calling SetNotifyText.
It is not visible from the above code.
0
 
reggieperrinAuthor Commented:
It is the very first line of what I posted above:

SetNotifyText("Application loading: 10 percent");

0
 
rajeev_devinCommented:
>> 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
 
reggieperrinAuthor Commented:
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
 
reggieperrinAuthor Commented:
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
 
itsmeandnobodyelseCommented:
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
 
reggieperrinAuthor Commented:
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
 
itsmeandnobodyelseCommented:
>>>> 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
 
reggieperrinAuthor Commented:
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
 
itsmeandnobodyelseCommented:
>>>> 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
 
reggieperrinAuthor Commented:
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
 
itsmeandnobodyelseCommented:
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
 
reggieperrinAuthor Commented:
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

Prep for the ITIL® Foundation Certification Exam

December’s Course of the Month is now available! Enroll to learn ITIL® Foundation best practices for delivering IT services effectively and efficiently.

  • 10
  • 5
  • 4
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now