Solved

Two CEdit controls updating each other: infinite loop

Posted on 2008-10-19
14
428 Views
Last Modified: 2013-11-20
I have on my dialog two text edit boxes. The idea is that when the contents of one is changed, the other changes and vice versa. I respond to the EN_CHANGE message (which I thought only fired in response to USER editing).

Needless to say, one EN_CHANGE invokes SetWindowText() in the other control, which causes another EN_CHANGE the other way, and so on ad infinitum.

I could just compare the "new" text with the existing text and do nothing if they are the same.

However, this won't work here because the text results from floating point numbers, so an exact textual match is not a good idea.

It is a simple dialog-based tool to convert kW to HP and vice versa. I don't want to have the user click any buttons to start the conversion; I just want the "other" box to update as the user types in "this" box.

How do I prevent this chain of EN_CHANGE messages ?
Is there a CEdit::SetWindowTextWithoutSendingAnUpdateMessage() call ?

Richard [in LU1]
0
Comment
Question by:muttley3141
  • 7
  • 6
14 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 22752463
If the focus is eg. in the first edit box then for the 'change' event in the second don't perform any processing.

if(GetFocus() == GetDlgItem(IDC_EDIT1))  return;

or similar code
0
 
LVL 55

Assisted Solution

by:Jaime Olivares
Jaime Olivares earned 40 total points
ID: 22752522
just create a couple of boolean members to avoid them to update
At first EN_CHANGE, set the boolean member to false and change the second control contents.
at second controls's EN_CHANGE event, first check the boolean variable to check if you are allowed to validate or not.
0
 
LVL 1

Author Comment

by:muttley3141
ID: 22758098
I'm currently doing what JO suggests, guarding things with simple boolean variables. This works, for now.

When the contents of CEdit #1 changes, the handler for that control (member of the containing CDialog-derived class) does this:

Sets ignchg = true;
Computes new text for CEdit #2
Calls SetWindowText() with that new text for CEdit #2
Sets ignchg = false;

Doing this will, of course, fire the handler for CEdit #2. That handler will see the ignchg set to true, and if it is, do nothing further, breaking the infinite cycle. If it is set to false, it will compute a new value for CEdit #1 in a symmetrical manner.

However, there is a problem with this: SetWindowText() resolves into SendMessage(WM_SETWINDOWTEXT..) or some such (or I presume it does).

What happens if the SendMessage() call puts the message into the queue of the CEdit #2, and returns before CEdit #2 has had time to pluck that message out of its queue, and act upon it ? By the time it gets around to acting on it, the return from SendMessage() may well cause the boolean to be set back to false.

I'm surprised this works at all at the moment.

My understanding is that a similar thing will happen if I use the "Do I have focus" test.
0
PRTG Network Monitor: Intuitive Network Monitoring

Network Monitoring is essential to ensure that computer systems and network devices are running. Use PRTG to monitor LANs, servers, websites, applications and devices, bandwidth, virtual environments, remote systems, IoT, and many more. PRTG is easy to set up & use.

 
LVL 44

Expert Comment

by:AndyAinscow
ID: 22758283
>>My understanding is that a similar thing will happen if I use the "Do I have focus" test.

Why - the focus is not being changed in the sending of messages.
0
 
LVL 1

Author Comment

by:muttley3141
ID: 22759035
AA>>My understanding is that a similar thing will happen if I use the "Do I have focus" test.

> Why - the focus is not being changed in the sending of messages.

The focus is indeed not being changed by the message, but the user could change the focus in between the message being sent and the message being received and acted upon. Such is the nature of sending messages: they are asynchronous.
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 22759418
Yes, but to change the focus requires other messages to be sent (AFTER the change message) surely.
0
 
LVL 1

Author Comment

by:muttley3141
ID: 22759666
>Yes, but to change the focus requires other messages to be sent (AFTER the change message) surely.

I don't know whether there are methods to change the focus other than sending messages.

If focus *is* changed by a message, then how can you tell that the focus-changing message will happen *AFTER* the SetWindowText() message. I don't know what other messages are floating about the system, who's sending them, who's receiving them, or in what order they get processed.

The sequence of actions you are proposing is.

1. Control A sends a SetWindowText() message to control B.
2. <lots of other messages get sent, maybe some to control B. These may be focus-changing messages, or other messages>
3. Control B now receives the message
4. < lots of other messages sent>
5. Control B eventually gets round to handling the message.
6. Control B decides to send a message to Control A
7. <lots of other messages sent>
8. Control A receives the message
9. <lots of other messages sent>
10. Control A now handles the message. It bases its decision as to whether or not to "handle" the message by determining whether it itself has focus.

By the time "10" happens, it may well have lost its original focus (which caused it to send the message at "1") due to all the other messages flying around.

What's to stop the user pressing TAB to move the focus between the controls at any point between 2 and 9 ?

Far be it from me to contradict a Genius, but there's obviously something here that you know well and take for granted, but which is passing me by. I seem to be taking the nature of windows messaging to
be more unpredicitable than it is. Please tell me that I am wrong, quite wrong.

Richard [in SG1]
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 22759861
OK.
MFC is single threaded (well it is explicitly stated as NOT thread safe).
There is SendMessage which is synchronous and PostMessage which is assynchronous.  AFAIK the SetWindowText calls the SendMessage functions.
The message pump is on a per app basis, not a per control basis.
0
 
LVL 1

Author Comment

by:muttley3141
ID: 22760006
Ahah !

So are you saying that when part of my program calls SendMessage(), it is effectively simply calling the recipient's WindowProc, and is explicitly not "queuing" or "holding" anything ?

Are you saying that a call to SendMessage() returns when and only when its work is done ?

Assuming that SetWindowText() does call into SendMessage (as opposed to PostMessage), does this mean that the SetWindowText() has already done its work completely by the time it returns to the caller ?
(I realise, of course, that it could create a thread of its own if it really wanted to)

In other words, SendMessage() can't really fail in the way that PostMessage() can. Is my understanding correct ?

If I understand you correctly, then the naming of SendMessage() is very disingenuous: the word "send", to me, means "despatch something without any direct notification that it has reached its destination". Perhaps US usage of Post versus Send is significant; in UK English, they are effectively synonymous.

If so, then both your and JO's solutions are equally valid. JO's is what I am doing at the moment, but I will try your solution: it's less messy.

0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 22760143
Have a look at SendMessage and PostMesssage in help - they are very different in operation.  Important to understand that.


>>So are you saying that when part of my program calls SendMessage(), it is effectively simply calling the recipient's WindowProc,
Both edits are in the same app - so the same message pump feeds both WindowProc's
0
 
LVL 1

Author Comment

by:muttley3141
ID: 22760647
Yes, SendMessage() returns when the underlying job is finished, and PostMessage() puts the item into the queue if it can, and returns immediately.

My problem is with the definition of "underlying job".

The phrase "message pump" is a bit scary. I've heard it used before and I'm not quite sure what it's referring to. It conjures up images of long queues of messages "waiting".

Can you explain what a message pump is, please ? Is it just a Windows-ism for "message queue" or does it have a specific meaning ?

If MFC is single-threaded, I don't see how there can be a queue within the application.

I'm obviously assuming Windows/MFC is much more asynchronous than it is.

I will look up the specifics of SendMessage()
0
 
LVL 44

Accepted Solution

by:
AndyAinscow earned 160 total points
ID: 22760753
>>My problem is with the definition of "underlying job".
finish the *synchronous* processing involved in the message.


The message pump is the mechanism that windows uses to process messages in the queue.


>>If MFC is single-threaded, I don't see how there can be a queue within the application.

PostMessage(THIS);  PostMessage(THAT); PostMessage(THEOTHER);
Three messages are now waiting for the app to process them.  It can only process them once the app has CPU time to do so.

>>I'm obviously assuming Windows/MFC is much more asynchronous than it is.
Asynchronous is not the same as multithreaded (and it can behave asynchronously to the detriment of the programmer especially if one does not understand the difference between SendMessage and PostMessage - one sees number of questions here along the lines of 'what is wrong with this code segment....' ).




ps.  What I suggested I think should work but please attempt to break it - I would be interested to hear if you succeed.
0
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 22765184
Just a point for clarification.
You can use multiple threads with MFC apps.  Just do NOT pass any MFC objects between threads - you might be lucky and it functions in that particular release of MFC.  The 'correct' way to do it by passing window handles and using messages or other techniques to communicate between the threads.
0
 
LVL 1

Author Comment

by:muttley3141
ID: 22765872
Yes, I've done multi-threaded stuff on Windows before, but using Borland OWL. I'm not sure whether that is more/less thread-secure than MFC.

Is it safe, for example, if I have a "worker thread" which will take a long time, for that thread to e.g. update a CProgressBar in a dialog in the main thread ? I've always erred on the side of caution by sending a custom identifier as part of a WM_COMMAND message with the progress % in it, and having the "main" thread update said progress bar ?

I've seen Delphi programs which seem to talk directly to controls across threads, and it looks very scary.

I've never done it that way: I've always just "signaled" between threads using WM_COMMAND or whatever, and using getters/setters which I write myself and know to be thread-safe.
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Established in 1997, Technology Architects has become one of the most reputable technology solutions companies in the country. TA have been providing businesses with cost effective state-of-the-art solutions and unparalleled service that is designed…

825 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