Solved

Two CEdit controls updating each other: infinite loop

Posted on 2008-10-19
14
408 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
>>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
Comment Utility
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
Comment Utility
Yes, but to change the focus requires other messages to be sent (AFTER the change message) surely.
0
 
LVL 1

Author Comment

by:muttley3141
Comment Utility
>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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>>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
Comment Utility
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
Comment Utility
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

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
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.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

772 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

10 Experts available now in Live!

Get 1:1 Help Now