Announcement

Collapse
No announcement yet.

Subclassing a ComboBox

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

  • Subclassing a ComboBox

    While I was reviewing the Windows messages in a Subclassed ComboBox I noticed that the %WM_KEYUP message is not sent to the ListBox portion of the Combo control, but %WM_KEYUP is sent to the edit control as expected. One can use the Up, Down, Page Up, and Page Down keys to navigate the list when the drop down ListBox is exposed, so there is a Key Up condition and I would assume a %WM_KEYUP message as well.

    Just wondered why the apparent discrepancy?
    Later...

    JR

    "When governments fear the people there is liberty. When people fear the government there is tyranny." - Thomas Jefferson

  • #2
    Because it is Windows and discrepancies are the norm.
    Jeff Blakeney

    Comment


    • #3
      This window never get's the focus, it looks so but is not.
      hellobasic

      Comment


      • #4
        I'd guess it wants keyDOWN rather than keyUP because if you hold the key down and it starts to repeat, the control is supposed to move to the next item.

        I suppose you could try holding a key down... let me try it right here, I have an app handy...yes, if you hold the up/down arrow keys down, you start scrolling. (CBS_DROPDOWNLIST).


        MCM
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Edwin,

          This window never get's the focus, it looks so but is not.
          Yeah, after looking closer at the ComboBox control I kinda figured that. Still, it's that consistency thing you know.

          MCM

          Yes, I know when you hold an arrow key down the listbox scrolls. What I'm trying to do is to figure out what specific Windows messages are sent to the Edit and ListBox portion of the ComboBox control so I can fire specific procedures for specific messages. When those specific messages such as %WM_KEYUP and %WM_CHAR are not sent to the ListBox makes it a little more difficult to trap the proper Windows message at the proper time. It looks like I will have to track when the ListBox is dropped/closed from the Edit control, plus the specific key pressed, and proceed accordingly.
          Later...

          JR

          "When governments fear the people there is liberty. When people fear the government there is tyranny." - Thomas Jefferson

          Comment


          • #6
            of the ComboBox control so I can fire specific procedures for specific messages. When those specific messages such as %WM_KEYUP and %WM_CHAR are not sent
            Not to belabor the obvious but.... if a control does not send a notification you need for your application, maybe you should pick a different standard control or write your own control.

            In this case, the word "superclass" comes to mind....nay, it LEAPS to mind....
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              In this case, the word "superclass" comes to mind....nay, it LEAPS to mind....
              Yes, I thought about creating a superclass control too, if I only knew how to do it, but I don't, plus there aren't too many superclass examples available that go into the necessary depth for something like this. Hence my request for "superclass" examples in the "You Talk PowerBASIC Listens" forum.

              That said, so far the ComboBox is the only control I'm having difficulty with, the other standard controls are pretty straightforward and are relatively easy to work with by comparison.
              Later...

              JR

              "When governments fear the people there is liberty. When people fear the government there is tyranny." - Thomas Jefferson

              Comment


              • #8
                >plus there aren't too many superclass examples available

                Well, now it's not too many minus one.

                The basic idea is, "it acts like a <button here, but anything> except for <something>.

                This button superclass is just like a regular button, except it processes the <enter> key just like the spacebar key and effects an "I was clicked"

                Once the class is registered , you can use it anywhere you would use any of the 'standard' window classes, in either a ....
                Code:
                   hCtrl = CreateWindowEx  ( exstyle, [b]szclassname[/b] .....)
                ...call if you are SDK'ing, or in a ....
                Code:
                   CONTROL ADD  $CLASSNAME_TSIBUTTON .....
                .. statement if you are DDT'ing

                Code:
                ' -----------------------------------------------------'
                ' SET UP BUTTONS WHICH WILL "click me" on <ENTER> and
                ' advance-retreat in tab order on Tab/Shift Tab
                ' assumes: Buttons are NOT using the GLW_USER bytes
                ' -----------------------------------------------------'
                
                $CLASSNAME_TSIBUTTON  = "TSI_837API_buttonclass"    ' try this
                
                '$CLASSNAME_TSIBUTTON  = "TSI_Button_One_class"
                %PWM_BUTTON_ONE_INIT  = %WM_USER + 1&
                
                #IF 1
                FUNCTION UnRegisterTsiButtonClass ()  AS LONG
                
                 LOCAL szClass AS ASCIIZ * %MAX_PATH
                
                 szClass           = $CLASSNAME_TSIBUTTON
                 UnregisterCLass     szClass, GetModuleHandle (BYVAL %NULL) ' assumes class was registered by this application.
                
                END FUNCTION
                
                
                
                FUNCTION RegisterTsiButtonClass ()  AS LONG
                
                 LOCAL szClass AS ASCIIZ * %MAX_PATH
                
                 LOCAL WCE AS WndClassEx, iRet AS LONG, hInst AS LONG
                 LOCAL OldWndProc  AS DWORD
                 ' to create a dummy Window
                
                 hInst    = GetModuleHandle (BYVAL %NULL)    ' for this program only
                 szClass  = "button"      ' get the base class name
                
                
                 WCE.CbSize                    =   SIZEOF(WCE)                         ' must set first
                 iRet                          =   GetClassinfoEx (hInst, szClass, WCE)   ' get button class info into WCE
                 IF ISTRUE iRet  THEN    ' succesfully retrieved button class info
                
                      ' MSGBOX "Button class cbWndExtra in=" & FORMAT$ (WCE.cbWndExtra)
                      ' YES THIS WAS PROBABLY MY PROBLEM. THE BUTTON CLASS RETURNS '8' FOR THIS VALUE AND I WAS SETTING TO ZERO
                      OldWndPRoc               =   WCE.lpfnWndProc          ' we need this later...
                     ' change what's going to be different
                      szClass                  = $CLASSNAME_TSIBUTTON
                      WCE.lpszClassname        = VARPTR (szClass)
                      WCE.lpfnWndProc          = CODEPTR(WndProc_TSI_BUTTON_ONE_PROC)
                      WCE.hInstance            = hInst
                      ' we want the %CS_GLOBAL Class so DLLs attached to this program can use the class
                      ' 1.11.06 I do not need this, either in this application, leave it alone
                      'WCE.style                = (WCE.style OR %CS_GLOBALCLASS
                      ' 1.11.06 I wonder if this extra was in use and did not add that!
                      ' SDK:
                      '   The application can add to both the extra class bytes and the extra window bytes because it is registering a new class. The application must follow two rules when doing this: (1) the original extra bytes for both the class and the
                     '    window must not be touched by the superclass for the same reasons that an instance subclass or a global subclass should not touch these extra bytes; (2) if the application adds extra bytes to either the class or the window instance
                     '   for the application's own use, it must always reference these extra bytes relative to the number of extra bytes used by the original base class. Because the number of bytes used by the base class may be different from one version of
                      '  the base class to the next, the starting offset for the superclass's own extra bytes is also different from one version of the base class to the next.
                    ' --- BAD LINE IN Versions up to 1.2.2
                    '  WCE.cbWndExtra           = 0&
                      ' YES THIS WAS PROBABLY MY PROBLEM. THE BUTTON CLASS RETURNS '8' FOR THIS VALUE AND I WAS SETTING TO ZERO
                      ' I SHOULD HAVE LEFT IT ALONE!
                    ' -----
                
                
                      ' and register the new class
                      iRet   = RegisterClassEx (WCE)
                      IF ISTRUE iret THEN    ' registration succeeded
                              ' call the window procedure with 'special' message value
                              ' which means "we just registered the class and the new WndProc should
                              ' store the oldWndProc in its STATIC variable
                              CALL WndProc_TSI_BUTTON_ONE_PROC (%NULL, %PWM_BUTTON_ONE_INIT, %NULL, OldWndProc)
                      ELSE
                           MSGBOX "Could Not Register new class"
                      END IF
                  ELSE
                      MSGBOX "Could not get button class info"
                  END IF
                
                
                END FUNCTION
                
                FUNCTION WndProc_TSI_BUTTON_ONE_PROC (BYVAL hWnd AS LONG, BYVAL uMsg AS LONG, BYVAL wParam AS LONG, BYVAL lpAram AS LONG) AS LONG
                
                  STATIC OldWndProc AS LONG
                  LOCAL   CtrlId AS LONG, keyState AS LONG
                
                
                     SELECT CASE AS LONG uMsg
                
                          CASE  %PWM_BUTTON_ONE_INIT    ' artificial call
                              OldWndProc   = lparam
                              EXIT FUNCTION  ' DO NOT PASS TO OLD WNDPROC, BECAUSE THIS CALL IS ARTIFICIAL!!!
                
                
                          '%CASE %WM_CREATE
                           ' nothing in particular I need to do here
                           ' if I do not callWindowPRoc, the button remains drawn in "down" state.. try calling
                
                             ' convert <Enter> into click on this control, and Tab into focus changes and exit!
                          CASE  %WM_CHAR
                            IF wParam = %VK_RETURN OR %WM_CHAR = %VK_SPACE THEN  ' treat as a click...and post WM_COMMAND, BN_CLICKED to parent:
                                 ctrlId    = GetDlgCtrlId (hWnd)
                                 PostMessage GetParent(hWnd), %WM_COMMAND, MAKDWD(CtrlId,%BN_CLICKED), GetDlgItem(hWnd,Ctrlid)
                
                                 ' we still have to call the original window proc.. 6/25/05 or do I?
                                 ' I really shouldn't on space, because that will generate an additional click..
                                 ' 6.25.05 Exited function and will run a while to see what happends
                                 FUNCTION  = 0
                                 EXIT FUNCTION
                             ELSEIF wParam = %VK_TAB THEN
                                     ' < 0 assumes GetKeyState returns a LONG... should change to support DWORD DECLARES
                                       KeyState  = GetKeyState(%VK_SHIFT)
                                       SetFocus    GetNextDlgTabItem (GetParent(hWnd),  hWnd, BIT(keyState, 31))
                                      ' next works OK but suffers the LONG/DWORD problem
                                      'SetFocus GetNextDlgTabItem (GetParent(hWnd), hWnd, GetKeyState(%VK_SHIFT) < 0)
                                      FUNCTION = 0
                                     ' EXIT FUNCTION
                                     ' 6.25.05 Exit the function because the default proc does nothing with TAB anyway
                                     EXIT FUNCTION
                            END IF
                
                         ' CASE ELSE
                         ' nothing to do but allow the original WndPRoc to be called
                
                       END SELECT
                     ' if we get here, we just call the original Window procedure and let processing happen..
                      FUNCTION =  CallWindowProc (OldwndProc, hWnd, uMsg, wParam, lparam)
                
                
                
                END FUNCTION
                #ENDIF
                You're stuck with - or perhaps blessed with - my notes to myself re how I had this screwed up for the longest time because I did not respect the "extra bytes" in the base class.

                Hence my request for "superclass" examples in the "You Talk PowerBASIC Listens" forum.
                Just one man's opinion, but you will get much better examples from members than from the factory. And frankly you will get A) better examples than this and no doubt B) one or more folks pointing out all the mistakes I made in this example.


                MCM
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  And just as one more option....

                  I recently did an application where I wanted to subclass a combobox... or so I at first thought.

                  Turns out what I really wanted to do was subclass the EDIT control which is part of the two-part (edit and list) combobox control. You can use the CB_GETCOMBOBOXINFO message to get a handle to the edit control, which you can then subclass.

                  Maybe that's the approach you need here to "find" all the messages.... subclass BOTH the edit and list portions of the combobox control ?????
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    MCM,

                    Thanks for the example, will take a closer look at it when I have the time.

                    You're stuck with - or perhaps blessed with - my notes to myself re how I had this screwed up for the longest time because I did not respect the "extra bytes" in the base class.
                    You can't have too much code documentation I always say, besides comments serve to give a not so gentle reminder to yourself of what you did, but also the intent behind your code. Believe it or not I find your "notes" a valuable resource.

                    Just one man's opinion, but you will get much better examples from members than from the factory. And frankly you will get A) better examples than this and no doubt B) one or more folks pointing out all the mistakes I made in this example.
                    I don't disagree, but I think if you were to take inventory of the number of existing subclass vs. superclass examples available in the forums, POFFS, etc., you would find that subclass far out number superclass examples. At this point I will look at a superclass example wherever it comes from, beggars can't be choosers.

                    Turns out what I really wanted to do was subclass the EDIT control which is part of the two-part (edit and list) combobox control. You can use the CB_GETCOMBOBOXINFO message to get a handle to the edit control, which you can then subclass.

                    Maybe that's the approach you need here to "find" all the messages.... subclass BOTH the edit and list portions of the combobox control ?????
                    Yes, that is essentially what I did, but when I did so that's when I discovered the ListBox control did not support the %WM_KEYUP and %WM_CHAR messages despite the key up condition when navigating the list and the fact you can select a ListBox item with 'Enter', whereas the Edit control did support these messages. Consistency?

                    The key was to keep track when the ListBox was visible and when it was closed from the Edit control, easy enough with the %CBN_DROPDOWN and the %CBN_CLOSEUP notifications. If the ListBox was visible I assumed it had "input focus" and the key press intercepted in the Edit subclass was forwarded to the ListBox subclass procedure. This allowed me to use the Up/Down arrow navigation keys, and also allowed me to make a ListBox selection by pressing 'Enter'. I know my assumption is a trade off, but my ComboBox subclassing works well enough now and does pretty much what I want it to do.
                    Later...

                    JR

                    "When governments fear the people there is liberty. When people fear the government there is tyranny." - Thomas Jefferson

                    Comment


                    • #11
                      ....take inventory of the number of existing subclass vs. superclass examples available .... subclass far out number superclass
                      Accepting guesses? The same reason I created superclass above.

                      It's essentially the same coding of the procedure (the subclass proc and the superclass proc), but if you have 'many' of the same controls, it's easier to just create the superclass and use those controls than to individually subclass each 'button' or whatever control. (well, not really, it just seems that way).

                      Combine this with that we see lots more "demos" of , "What is the easiest way...?" versus "What is the best way...?" and you have a match made in... well, one of the nether worlds.

                      MCM
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment

                      Working...
                      X