Why can’t you change the alignment of an edit control after it has been created?


Commenter Kevin Eshbach asks why you cannot programatically change the text centering style of an edit control after the control has been created.

The edit control is one of the original window manager controls, so it comes with a lot of history. First thing to note is that the WM_STYLECHANGED message did not exist until Windows 95. The edit control predates Windows 95 by over a decade, so the short answer is “It can’t respond to the change in styles because it doesn’t even know that you changed them!”

Back in the old days, the only time a control was informed of its styles was in the CREATESTRUCT passed as parameters to the WM_CREATE and WM_NCCREATE messages. Consequently, most controls back in those days cached their styles in member variables so that they wouldn’t have to call GetWindowLong(GWL_STYLE) all the time. This was back in the days of 4.77MHz CPUs, and a call to fetch the style of a window was quite a bit bigger and slower than just reading it out of your local data segment.

Even if you decided “Forget it, I won’t bother with a cache; I’ll just call GetWindowLong(GWL_STYLE) to read the style each time I need it”, you open yourself up to a new problem: What if the style changes? A change in the style means that the characters in the edit box need to have their positions recalculated and the text redrawn. This is obviously not something you want to do at every single message (redrawing at every message is probably not a great idea), so you still need to cache the old style so you can avoid recalculating stuff that hasn’t changed.

Even if you say, “Okay, fine, then instead of changing the style with SetWindowLong(GWL_STYLE), let’s say that if you want to change the style of an edit control, you have to use a new message, something like EM_CHANGESTYLE.” That way, the edit control knows when its styles have changed and doesn’t have to keep polling for them. When it gets this message, it updates the styles and recalculates all its internal state based on the new style.

Okay, sure it could’ve done this, but that’s code that has to be written and tested, for an extremely rare usage pattern. I mean, what is the scenario where somebody needs to change an edit control from left-aligned to right-aligned on the fly? You could count all the Windows 1.0 applications on your fingers and toes (note: exaggeration), and they just decided in the dialog template which way the text should be aligned. It was determined not just at creation time; it was determined at compile time.

If you want to change an edit control’s alignment on the fly, you can just destroy the old one and create a new one in its place with the same text.

Comments (25)
  1. Matej Horvat says:

    "You could count all the Windows 1.0 applications on your fingers and toes (note: exaggeration)"

    Besides the accessories Windows 1.x came bundled with, Aldus PageMaker, and some obscure shareware utilities, how many software did REALLY exist for Windows 1.x?

  2. Vilx- says:

    Fun fact: it’s possible to count to 1048576 by using just your fingers and toes…

  3. Gwyn says:

    Vilx: you can count to way more than that, if you do not count in binary

  4. jon says:

    This caught me out recently. I was writing a dialog rendering wrapper to prevent flickering when the dialog is resized, and found that comboboxes set the ES_NOHIDESEL style on their edit control. All well and dandy but it means that if you use WM_PRINTCLIENT to print a combobox into a memory DC it will do so with the text in it highlighted, even if the control doesn’t actually have focus.

    Clearing the ES_NOHIDESEL style for the WM_PRINTCLIENT didn’t work because, as I’ve now learned, the edit control doesn’t update on style change. The only solution I found was to manually clear the selection range via CB_SETEDITSEL and restore it after rendering.

  5. Anonymous says:

    Vilx: I only get 4 bits on my right foot and 3 on my left.  Also, you’ll find 01010 quite hard to express with your hands.

  6. Simon Cooke says:

    Waitaminute… digging way back into memory here (and I may be wrong), but doesn’t calling SetWindowPos with SWP_FRAMECHANGED cause a recreate and re-apply of the styles?

  7. peterchen says:

    Vilx – what bit states do you have in mind? pink, blue, broken, smashed?

  8. Cheong says:

    Also, you’ll find 01010 quite hard to express with your hands.

    Will it be hard? You may want to check this out.

    http://en.wikipedia.org/wiki/Finger_binary

    Actually, I’d find it much harder to count with my toes… Especially if binary count is used… :P

  9. Miles Archer says:

    Did anyone read the headline and think of changing a edit control to Chaotic Evil?

  10. JM says:

    @Miles: No, but now that you’ve mentioned it I can’t help thinking about a Message of Opposite Alignment. If such a thing existed Raymond could have simply replied "the window manager doesn’t pass cursed messages — PC hardware is difficult enough to get along with without such complications".

  11. SuperKoko says:

    > The edit control predates Windows 95 by over a decade

    I don’t buy the legacy argument.

    Microsoft continues controls development way after they were first introduced.

    e.g. The multi-line edit control now supports the mouse wheel.

    > Okay, sure it could’ve done this, but that’s code that has to be written and tested, for an extremely rare usage pattern.

    That is the real reason.

    [The legacy argument is to answer the question “Why didn’t the edit control support the feature from conception?” Because adding features later is much more expensive than designing them in. -Raymond]
  12. Ens says:

    @Cheong:

    He’s already referring to finger binary.  Try to express binary 01010 on one hand using finger binary.  It’s hard.  Physically difficult.

    As other commenters have mentioned, finger binary is also not even close to a maximal representation of hand counting.  And it makes me have to perform a retranslation step (binary to decimal) at the end of the count which is usually more difficult than counting without my hands.

    On the rare occasion that I do count or store a number with my hands I use American Sign Language http://www.dummies.com/how-to/content/counting-on-numbers-in-sign-language.html, except that I don’t do the funny business from 11-19, just handling it the same way as 21-29, 31-39, etc.  Slightly less efficient than finger binary, but it also serves as an example of some of the ways you can create even more hand states than just finger raised/finger lowered.

    Which adds nothing constructive to Raymond’s post.  Just wanted to nitpick, and I found somebody that wasn’t Raymond.

  13. Anonymous says:

    Ens: if you’re already working in hex, just use your fingers, palm upwards.  The thumb can be used for carry if necessary.

  14. PinkDuck says:

    This reminds me that the date/time applet’s edit/time-picker control in XP SP3 on my work PC shows the time left-aligned, even though all my regional settings are for English UK.

    I do have complex script, right-to-left and East Asian language supplementary support installed though. I do at home too, except there the time is right-aligned as usual.

  15. Michael G says:

    Try to express binary 01010 on one hand using finger binary.  It’s hard.  Physically difficult.

    Do you find it difficult to press the "J" and "L" keys at the same time?  (Or, if you want to try your other hand, the "S" and "F" keys).

    ‘Cause that’s the motion you use to count binary on fingers: pressing the table = 1, raised = 0.

  16. Worf says:

    I’m not physically special, but I don’t see the difficulty in 01010, even inverted 10101. It’s not a smooth action, but my thumb, middle, and pinky curl just fine. Just have to be a bit careful…

  17. Kevin Eshbach says:

    Thanks for answering the question Raymond.  I’ve had bugs to fix in the past where people where changing the text alignment style via SetWindowLong and then wondering why things started to act wacky and when I told them you cannot this style after the edit control is created they just stared at me like a mental patient.

  18. ulric says:

    I’d still test it before assuming it doesn’t support it.  When you call SetWindowLong to change styles, as a rule you have to call SetWindowPos with SWP_FRAMECHANGED, as mentioned above. If you don’t will it not work well with for anything.  

  19. Kevin Eshbach says:

    ulric,

    Looking at the documentation for the SetWindowPos at http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx I see nothing saying that the SWP_FRAMECHANGED flag will cause the control to be destroyed and re-created as Raymond stated is the correct way to change an edit control’s text alignment on the fly.

    [Huh? I see no such text on the page you link to. SWP_FRAMECHANGED does not “destroy and recreate content” – how could it? (How would SWP_FRAMECHANGED know how to recreate the contents of a grid control?) -Raymond]
  20. ulric says:

    Keven Eshbash:  what SetWindowPos does is end up cause a WM_NCCALCSIZE, and well-behaved controls watch for that message to re-calculate their layouts according to their styles.  A window has no other way to know the styles have been changed through SetWindowLong.

    (this comments on the question as much as the EM_CHANGESTYLE paragraph)

    You’ll find that information in the documentation for SetWindowLong, in the remark section, but if you use MFC CWnd::ModifyStyles it calls SetWindowPos internally for you.

  21. GregM says:

    [Huh? I see no such text on the page you link to. SWP_FRAMECHANGED does not “destroy and recreate content” – how could it? (How would SWP_FRAMECHANGED know how to recreate the contents of a grid control?) -Raymond]

    That’s exactly what Kevin just said.  Since the only way to change the style is to destroy and recreate the control, and SWP_FRAMECHANGED doesn’t destroy and recreate the control, SWP_FRAMECHANGED won’t change the style.

    [Ah, I misread the original comment. Thanks for setting me straight. -Raymond]
  22. Ulric says:

    Following the “Don’t be lazy” doctrine.. :P

    I’ve written a test application,

    and as I predicted, you can indeed change the alignement of an edit control at runtime.  It works, therefore this blog entry is wrong.

    ————————————–

    I wrote an MFC dialog with two buttons to modify the style of the edit control. here are the message handlers:

    void CTestEditDlg::OnBnClickedButton1()

    {

    m_TestEdit.ModifyStyle( ES_RIGHT, ES_LEFT );

    m_TestEdit.Invalidate();

    }

    void CTestEditDlg::OnBnClickedButton2()

    {

    m_TestEdit.ModifyStyle( ES_LEFT, ES_RIGHT );

    m_TestEdit.Invalidate();

    }

    MFC’s ModifyStyle does SetWindowLong and SetWindowPos( SWP_FRAMCHANGED)

    [Now uninstall LPK and try again. -Raymond]
  23. Ulric says:

    [Now uninstall LPK and try again. -Raymond]

    what’s the "LPK"?

  24. apz says:

    The first unfamiliar computer acronym :-( What is LPK?

  25. Kevin Eshbach says:

    All I know is I can’t find anything in the official Microsoft documentation where it states you can dynamically change the alignment style on the fly so in my opinion that means if it works it’s an undocumented feature that could disappear in future versions of Windows.  I personally prefer to stay away from undocumented features but to each his own.

Comments are closed.