Announcement

Collapse
No announcement yet.

Updating toolbar button states

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Updating toolbar button states

    Does anyone know the best strategy for updating the enabled/disabled state of toolbar buttons?

    Say you have an application with edit controls and a toolbar with Copy, Cut, Paste and Undo buttons. The same commands appear on the Edit/Context menus. Updating the menu items is easy because you do it when processing %WM_INITMENU. You simple check for any text selection, any text in clipboard, check the undo buffer, and then enable/disable the menu items appropriately. The problem with updating the toolbar buttons is that their state must be updated immediately there are changes to the selection/clipboard/undo buffer. Are there a set of notification messages than can be intercepted, for instance?

    Thanks, Keith


    ------------------

  • #2
    WM_COPY and WM_PASTE ??


    ------------------
    hellobasic

    Comment


    • #3
      WM_DRAWCLIPBOARD

      ------------------

      Comment


      • #4
        Keith,

        The easiest way I've seen this done by seasoned C/C++
        programmers and I use it also, is to update the TB and anyother
        miscellaneous chores in the message loop. This is accomplished
        by looking at the message queue and if no messages are present
        for the thread to process, do idle processing now. The following
        code would be inside your message loop construct, of course.

        Code:
        if PeekMessage( msg, %NULL, 0, 0, %PM_NOREMOVE ) THEN
          if GetMessage( msg, %NULL, 0, 0 ) THEN
             Do whatever you're going to do here
        else
          DoIdleProcessing
          WaitMessage
        end if
        The DoIdleProcessing function is where you do your business. The
        TB will need to be enumerated. First find out the number of
        buttons by:

        nButtons = SendMessage( hWndToolBar, %TB_BUTTONCOUNT, 0, 0 )

        Now construct a for/next loop to get/set the button info. The
        following line will fill in the TB button structure:

        SendMessage hWndToolBar, %TB_GETBUTTON, i, btn where btn is the
        button structure and i is the for/next counter starting at 0.

        Now, send the TB button the state it should be in based on the
        conditions you just described above:

        SendMessage hWndToolBar, %TB_SETSTATE, btn.idCommand, %TBSTATE_ENABLED
        or set the last parameter to zero(0).

        Do this for each button on the TB.

        The WaitMessage function yields control to other threads when
        a thread has no other messages in it's message queue. The
        WaitMessage function suspends the thread and does not return
        until a new message is placed in the thread's message queue.

        I deliberately explained in this fashion so YOU could fill in
        the code missing and thus gain a better understanding of how
        Windows does it's thing.

        Cheers,
        Cecil



        ------------------

        Comment


        • #5
          Cecil

          What you describe sounds like it could be exactly what I was looking for. The alternative approach of explicitly intercepting every message that might alter the state of the text selection, clipboard or undo buffer seemed so messy. And what if another application places text on the clipboard - no it gets so messy that way.

          I will try your method when I get back to my development machine.
          Many thanks.
          Keith

          Ps. Please don't worry that I have to fill in the code. I'd already sorted out HOW to update the button states. It was the strategy of WHEN to do it that was bothering me.



          ------------------

          Comment


          • #6
            Cecil

            Just another thought, but can't the message loop be simplified by
            removing the message when Peeking, as follows.

            Code:
            DO
              IF PeekMessage (msg, %NULL, 0, 0, %PM_REMOVE) THEN
                IF msg.message = %WM_QUIT THEN EXIT LOOP
              
                Process message in normal way
              
              ELSE
                DoIdleProcessing
                CALL WaitMessage()
              
              END IF
            LOOP
            Cheers, Keith

            ------------------

            Comment


            • #7
              Keith,

              Well, yes, you could do it that way, but you still have
              to retrieve the message. Here's how I do the loop, expanded
              from the above construct:

              Code:
              DO
                if PeekMessage( msg, %NULL, 0, 0, %PM_NOREMOVE ) THEN
                  if GetMessage( msg, %NULL, 0, 0 ) THEN
                     Do whatever you're going to do here, ie process the
                       message.
                  else
                     EXIT DO
                  end if
                else
                  DoIdleProcessing
                  WaitMessage
                end if
              LOOP
              If GetMessage retrieves the %WM_QUIT message, it returns %NULL
              or zero (0), thus causing the DO/LOOP to exit out.

              Cheers,
              Cecil



              ------------------

              Comment


              • #8
                Cecil --

                > you still have to retrieve the message

                Keith's code does that, by using PeekMessage with %PM_REMOVE.

                -- Eric


                ------------------
                Perfect Sync Development Tools
                Perfect Sync Web Site
                Contact Us: mailto:[email protected][email protected]</A>
                "Not my circus, not my monkeys."

                Comment


                • #9
                  Eric,

                  I missed that he changed the %PM_NOREMOVE to %PM_REMOVE.
                  You're absolutely right.

                  Cheers,
                  Cecil

                  ------------------

                  Comment


                  • #10
                    The update, for those interested now or in the future.

                    Cecil's scheme of updating the toolbar button states from the message loop worked fine as follows.

                    Code:
                      DO
                        IF PeekMessage (msg, %NULL, 0, 0, %PM_REMOVE) THEN
                          IF msg.message = %WM_QUIT THEN EXIT LOOP
                            IF TranslateAccelerator(hWnd, hAccel, msg) THEN
                              'Skip
                            ELSE
                              CALL TranslateMessage (msg)
                              CALL DispatchMessage  (msg)
                            END IF
                        ELSE
                          CALL UpdateToolbar()
                          CALL WaitMessage()
                        END IF
                      LOOP
                    The UpdateToolbar routine, of course, sets the toolbar button states as appropriate for the active edit control's text selection and the statuses of the clipboard and undo buffers. That's not the whole story, though, because the enabled/disabled state of the WHOLE toolbar must visibly mirror that of the menu bar. The menu bar is automatically greyed whenever a dialog box is popped-up from within the application and whenever another application is activated but, sadly, the toolbar is not. I ended up processing the %WM_NCACTIVATE message in the main window procedure as follows

                    Code:
                        CASE %WM_NCACTIVATE
                          IF wParam THEN
                            CALL EnableToolbar(g_hWndToolbar)
                          ELSE
                            CALL DisableToolbar(g_hWndToolbar)
                          END IF
                          FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
                    The DisableToolbar routine disables all toolbar buttons and sets a global tb_disabled flag to %TRUE. The EnableToolbar routine simply resets tb_disabled back to %FALSE. The tb_disabled flag is a complication to fix the following snag.
                    When another application is activated, UpdateToolbarButtons gets called AFTER %WM_NCACTIVATE has been processed and so the individual states of the toolbar buttons get restored when they should all be disabled (BTW the same problem does not occur with dialogs). When tb_disabled is true, UpdateToolbarButtons simple skips.

                    Regards, Keith


                    ------------------

                    Comment


                    • #11
                      I was gamely following this thread until the following
                      That's not the whole story, though, because the enabled/disabled state of the
                      WHOLE toolbar must visibly mirror that of the menu bar.
                      The menu bar?
                      The menu bar is automatically greyed whenever a dialog box is popped-up from within
                      the application and whenever another application is activated but, sadly, the toolbar
                      is not.
                      Are you referring to the caption of the application window?

                      Maybe I am missing something here, but why do you need to disable the buttons
                      on the toolbar when the main application window loses the focus?

                      Anyway, WM_NCACTIVATE is not a very good place for your EnableToolbar() and
                      DisableToolbar() functions because in a multi-windowed app you will have a
                      real mess on your hands. WM_ACTIVATEAPP is probably a better deal.

                      ------------------
                      Dominic Mitchell

                      [This message has been edited by Dominic Mitchell (edited June 14, 2001).]
                      Dominic Mitchell
                      Phoenix Visual Designer
                      http://www.phnxthunder.com

                      Comment


                      • #12
                        Dominic

                        Thanks very much for your interest.

                        I'm referring to the main menu bar that sits just under the title bar of the main application window and has the usual (in many applications) File, Edit, View etc options. This gets greyed out when an application dialog is popped-up and when another application is activated.

                        I don't actually NEED to disable the toolbar buttons when this happens. It's simply a matter of aesthetics that I wish the toolbar buttons to appear greyed-out just like the menu bar.

                        I don't understand why WM_NCACTIVATE is not a very good place for enabling/disabling the toolbar. WM_ACTIVATEAPP, as you suggest, gets sent when focus changes to another application. I don't think it gets sent when an application dialog is popped-up so it can only be of any use for half of my problem (activating another application). WM_NCACTIVATE gets sent to a window when its non-client area needs to be changed to indicate an active or inactive state (indicated by the value of wParam) and seems to be exactly what I need. If there is something I don't grasp about multi-windowed applications when you say "you will have a real mess on your hands", please explain.

                        Many thanks
                        Keith


                        ------------------


                        [This message has been edited by Keith Waters (edited June 14, 2001).]

                        Comment


                        • #13
                          Dominic,

                          I think he's saying the menu bar itself gets greyed. I can't
                          think of why Windows would do this, however why would one
                          want to do this anyway? Must be missing something here.

                          Keith,

                          Are you manually disabling the menu bar?

                          In searching through a lot C/C++ code, the above message loop
                          that I posted is used quite consistantly. The PeekMessage
                          function can retrieve the WM_PAINT message if a WM_PAINT message
                          has a null update region. So, a word of caution would be in
                          order with the simplified version you have. MFC default
                          message pump also uses this scheme for idle processing.

                          Cheers,
                          Cecil


                          ------------------

                          Comment


                          • #14
                            Cecil, Dominic

                            Regarding the menu bar, lets start with some straight observations. At this very moment, I'm viewing this discussion thread in Netscape Communicator 4.73. I click "File" on the menu bar and then click "Open Page". The "Open Page" dialog appears and I see that the menu bar is now greyed. I note that the same thing happens with "File > Open" in Notepad, and the same thing happens in my application. I'm not programmatically greying the menu bar, unless I've done it unconsciously, it just happens automatically.

                            That's the observation part. Now, what I want, and I repeat it's purely an aesthetics thing, is for the toolbar buttons to be greyed at the same time as the menu bar is greyed. That's all. My present scheme, subject to the caution Cecil raises (which is appreciated), works fine for me, but if
                            Dominic can enlighten me on something he feels I do not understand I would greatly appreciate that.

                            Keith


                            ------------------

                            Comment


                            • #15
                              By multi-windowed app I mean an application with multiple top level
                              windows which excludes MDI. Given the following three windows in the
                              application described above

                              A - top level window with toolbar/monitors WM_NCACTIVATE
                              B - top level window
                              C - top level window

                              When the user switches from A to B the toolbar will be disabled and will
                              remain disabled until he/she switches back to A. Therefore, the toolbar
                              will be useless even though the application has not lost the focus. One
                              workaround for this is to monitor WM_NCACTIVATE in the window procedures
                              for A, B and C. However, this would lead to nasty flickering of the toolbar
                              as the user switches from window to window. A better solution would be to
                              monitor WM_ACTIVATE. If the activation flag is WA_INACTIVE then a check
                              should be done on lParam(the handle of the window being activated). If the
                              window being activated does not belong to the application then the toolbar
                              would be disabled.

                              You are right about WM_ACTIVATEAPP. For the reasons outlined above I prefer
                              WM_ACTIVATE over WM_NCACTIVATE. However, in an SDI app either WM_ACTIVATE or
                              WM_NCATIVATE should be ok.

                              What I don't get and Cecil pointed this out, is the method by which your menubar
                              is being greyed when your app loses the focus.

                              PS;
                              Tried your tests. The menubar is not greyed in any of those cases. When a dialog
                              appears the application window is disabled and it caption is redrawn using a brush
                              with the COLOR_INACTIVECAPTION system color.

                              [This message has been edited by Dominic Mitchell (edited June 14, 2001).]
                              Dominic Mitchell
                              Phoenix Visual Designer
                              http://www.phnxthunder.com

                              Comment


                              • #16
                                Keith,

                                I now fully understand what you are saying, HOWEVER this is
                                NOT normal Windows procedure. I have MS IE and my menu bar
                                does not grey as you say. In opening NotePad, same thing,
                                the menu bar shines like a new dime. I've never witnessed the
                                event that you describe on any program that I have. Seems to
                                be a BIG problemo with your OS or supporting dll's.

                                If it's possible to e-mail me your EXE file, I'll be glad
                                to run it and see what happens. I use NT4 sp6.

                                e-mail [email protected]

                                Cheers,
                                Cecil

                                ------------------

                                Comment


                                • #17
                                  Cecil

                                  I really appreciate you replying like this. I was beginning to doubt my powers of communication/logic/observation/etc. Plus, I've had quite a bit of wine with an old friend I've just met after some time. I will email the exe when I'm sober.

                                  Regards,
                                  Keith


                                  ------------------

                                  Comment


                                  • #18
                                    Graying the toolbar when an app loses focus is something that I quite like too, but few apps (programmers?) seem to be concerned with.

                                    If anyone uses Free Agent, then you'll see this effect there (that is just one that springs to mind when reading this thread).

                                    As has been noted, it is purely a matter of aesthetics.

                                    ------------------
                                    Lance
                                    PowerBASIC Support
                                    mailto:[email protected][email protected]</A>
                                    Lance
                                    mailto:[email protected]

                                    Comment


                                    • #19
                                      Keith,

                                      Automatic graying of the menu of a window when it loses focus seems to depend upon the Windows version (or some obscure Windows setting). On my Windows 98 PC menus grey out automatically. On two W95 PCs I've tried they don't. Therefore if you programatically gray the toolbar, on some machines the toolbar will be grayed, but not the menu.

                                      Also where do you stop? Should you grey out all the buttons on a dialog when it loses focus?

                                      Just a few thoughts

                                      Simon

                                      ------------------

                                      Comment


                                      • #20
                                        I can't say I've ever actually noticed a dependence on the O/S version in this regard, but I suspect that if that is true, the IE version installed may be the contributing factor.

                                        I hear what you say about buttons... with an app like Free Agent, there are no buttons in the window...

                                        At the end of the day, this is a case of "what the programmer wants the app to look like". Afterall, some folks like to "skin" their windows, others prefer the standard UI look. Some like a background image, others plain. Some like controls to be colored, some are repulsed.

                                        So, how about we wrap this topic up with a classic quote... "it's the artist, not the paint brush!"




                                        ------------------
                                        Lance
                                        PowerBASIC Support
                                        mailto:[email protected][email protected]</A>
                                        Lance
                                        mailto:[email protected]

                                        Comment

                                        Working...
                                        X