Announcement

Collapse
No announcement yet.

Superclassed Ownerdrawn Button

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

  • Superclassed Ownerdrawn Button

    What event in the SuperClass CallBack procedure can be used to draw it?

    I know how to use WM_DRAWITEM in a dialog callback. Do owernerdrawn buttons, even if superclassed, have to rely on the parent control's WM_DRAWITEM event?

    Bob Mechler

  • #2
    Don't use OwnerDraw style and just do it on WM_PAINT in superclass procedure.

    This is kind of the whole idea behind superclassing... "It's just like <something> except for (in this case, the WM_PAINT processing).

    No, I have no clue if using 'DDT' is going to interfere with this, but it will work just fine with SDK-style windows.
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]ems.com
    http://www.talsystems.com

    Comment


    • #3
      Thanks. And probably switch to a Superclassed Label instead of a button, right?

      Bob Mechler

      Comment


      • #4
        Depends on what you are trying to accomplish with that label.

        Not that you can do a hell of a lot with a label anyway, but hey, it's your label.
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Don't use OwnerDraw style and just do it on WM_PAINT in superclass procedure.

          This is kind of the whole idea behind superclassing... "It's just like <something> except for (in this case, the WM_PAINT processing).
          These statements, I am afraid, are not correct by any stretch of the imagination.

          Go ahead and try it for a normal(e.g. BS_PUSHBUTTON) button. I guarantee you are in for a shock.
          Dominic Mitchell
          Phoenix Visual Designer
          http://www.phnxthunder.com

          Comment


          • #6
            When superclassing a control (a new class based on an existing class, which is different than subclassing) you have to be careful in how you process the window procedure messages. You have to make sure you don't work against the original class and how it works.

            If you want to build a custom class using ownerdraw, it may be better to build your own custom class (not a superclass) which acts as a container. Then have the container control create the ownerdraw control as a child of itself. Then the container class can handle the ownerdraw messages from its ownerdrawn child control.

            So the child control can get messages sent to its container, you can have the container class forward messages to the child control. This way the container could support all the messages of the child.
            Chris Boss
            Computer Workshop
            Developer of "EZGUI"
            http://cwsof.com
            http://twitter.com/EZGUIProGuy

            Comment


            • #7
              The container class? Is there an example? I've never used one.

              I didn't have any luck using WM_PAINT in the SuperClass of the button or label. It either GPF'd or drew it partially.

              There are some really nice examples I've found of gradient buttons (which is what I really want). None of them are superclassed though.

              I want to superclass a gradient button in order to give it additional default functionality. One would be to call a function I'll call ValidateForm(param,param,....) which will have the same name in all programs just code that returns the id's of fields not yet matching that program's needs or that it's ready to save the record or do the processing. That way the SuperClassed button will look exactly the same and be reusable by just supplying the location and size.

              I'll look for some container class examples next.

              Bob Mechler

              Comment


              • #8
                ahead and try it for a normal(e.g. BS_PUSHBUTTON) button. I guarantee you are in for a shock.
                I did start playing with it.

                Shock? No.

                Chagrin at forgetting that when you try to "make your own button" control a lot of the info you need to make it act like a button is not readily available? Yes.

                While the focus rectangle handling is the same for BS_OWNERDRAW 'standard' buttons and "superclass-created" buttons, with the latter you have to keep track of the "pushed state" yourself, which necessitates processing the WM_LBUTTONUP notification, as well as WM_Keyup/keydown looking for <spacebar> and storing that current pushed state.. as well as send notifications to the parent for some of those actions.

                On the plus side, I think its only the pushed state is what you have to monitor, as you can always ask for the size and location (GetWindowRect) and the focused state (compare GetFocus() with this hwnd).

                Darned, I should have (but didn't) try BM_GETSTATE message. I wonder if that might not make life easier. I'll try that later today or maybe tomorrow and see if I can post a little baby demo.

                Ok, so the button is a bad example. Let's go back to the label, that's a lot cleaner.


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

                Comment


                • #9
                  Bob,

                  An even simpler method would be to simply write a subroutine which does the drawing for ownerdraw buttons which can be called in the Dialogs WM_DRAWITEM message. That message will only be sent for ownerdraw controls and not other controls.

                  ie.

                  Code:
                  CASE %WM_DRAWITEM
                      FUNCTION=MyButtonDrawRoutine(CBWPARAM, CBLPARAM)
                      EXIT FUNCTION
                  Do all your drawing in the routine you write.

                  To make it more powerful, have the routine read back the text from the button control (send WM_GETTEXT to the control).

                  You can parse out the text and embed macros to define the drawing process.

                  For example embed macros like this:

                  "My Buttons Text {{RED}}"

                  By embeding macros in double brackets, you can parse out any macros and leave only the text. This way you can then define the macros for each button, such as colors, font, etc. in the buttons text . This makes it easy to use PBForms to design the dialog. You simply write the buttons text plus macros in the designers text field for the controls.
                  Chris Boss
                  Computer Workshop
                  Developer of "EZGUI"
                  http://cwsof.com
                  http://twitter.com/EZGUIProGuy

                  Comment


                  • #10
                    I like it Chris.

                    I'll also need to add a test for buttons since WM_DRAWITEM handles ownerdrawing of several other controls.

                    IF @lDisPtr.CtlType = %ODT_BUTTON for the drawing routine since I also want to owerdraw the tab labels on my tab control.

                    Bob Mechler

                    Comment


                    • #11
                      Bob,

                      A very useful API function is:

                      GetClassName

                      You can test any window handle to see what window class it is. It is a great way to test in WM_DRAWITEM what class generated the message.
                      Chris Boss
                      Computer Workshop
                      Developer of "EZGUI"
                      http://cwsof.com
                      http://twitter.com/EZGUIProGuy

                      Comment


                      • #12
                        Code:
                        LOCAL pDI AS DRAWITEMSTRUCT PTR 
                        
                        .....
                            CASE %WM_DRAWITEM
                               pDI =  CBLPARAM
                              SELECT CASE @pDI.CtlId
                                   CASE %BUTTON_1 
                                       CALL ButtonOneProc
                        
                                    CASE %BUTTON_2 
                                       CALL ButtonTwoProc
                          
                                .....
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          This stuff has been discussed at length before, see for example
                          http://www.powerbasic.com/support/pb...custom+control

                          If the control is subclassed/superclassed, and if you don't want to use a container, you can
                          also use message reflection. That is, the WM_DRAWITEM message is sent from the parent window
                          procedure to the subclassed/superclassed procedure for the control.
                          Dominic Mitchell
                          Phoenix Visual Designer
                          http://www.phnxthunder.com

                          Comment


                          • #14
                            GetClassName

                            You can test any window handle to see what window class it is. It is a great way to test in WM_DRAWITEM what class generated the message.
                            But if he wants to know if it is a button, all he has to do is examine the value of the CtlType
                            member of the DRAWITEMSTRUCT struct. GetClassName fails if the control is superclassed, this
                            test does not.
                            Dominic Mitchell
                            Phoenix Visual Designer
                            http://www.phnxthunder.com

                            Comment


                            • #15
                              Owerdrawn tab control.
                              Code:
                              ODT_TAB = 101
                              Dominic Mitchell
                              Phoenix Visual Designer
                              http://www.phnxthunder.com

                              Comment


                              • #16
                                Originally posted by Dominic Mitchell View Post
                                This stuff has been discussed at length before, see for example
                                http://www.powerbasic.com/support/pb...custom+control
                                Great link, wish I had found it a year ago!

                                Originally posted by Dominic Mitchell View Post
                                If the control is subclassed/superclassed, and if you don't want to use a container, you can
                                also use message reflection. That is, the WM_DRAWITEM message is sent from the parent window procedure to the subclassed/superclassed procedure for the control.
                                I use a global array of window handles and original classnames so that control can be passed back to the original classproc when appropriate.

                                Comment


                                • #17
                                  I like the idea mentioned about reflecting (forwarding) the WM_DRAWITEM message to the controls window procedure (if superclassed).

                                  ie.

                                  %BM_MyDraw = %WM_USER + 400

                                  Then in response to the WM_DRAWITEM message do this:

                                  Code:
                                  CASE %WM_DRAWITEM
                                     LOCAL pDI AS DRAWITEMSTRUCT PTR 
                                     pDI =  CBLPARAM
                                     IF @pDI.CtlType = %ODT_BUTTON THEN
                                        FUNCTION=SendMessage(@pDI.hwnditem, %WM_DRAWITEM, CBWPARAM, CBLPARAM)
                                       EXIT FUNCTION
                                     END IF
                                  This way you can handle all the drawing in the superclassed controls window procedure which is handy if you put it in a DLL.
                                  Chris Boss
                                  Computer Workshop
                                  Developer of "EZGUI"
                                  http://cwsof.com
                                  http://twitter.com/EZGUIProGuy

                                  Comment


                                  • #18
                                    Before I saw your post I came up with this. It seems to work ok. Not sure I needed all the parameters but I did get gradient ownerdrawn buttons.

                                    Code:
                                    CASE %WM_DRAWITEM
                                    
                                            lDisPtr = CBLPARAM
                                            IF @lDisPtr.CtlType = %ODT_BUTTON THEN
                                              CALL PaintGRLabelBg(CBHNDL,CBCTL,CBWPARAM,CBLPARAM)    
                                              FUNCTION = %True                       
                                            END IF


                                    Code:
                                        SUB PaintGRLabelBg(pCBHNDL&,pCBCTL&,pCBWPARAM&,pCBLPARAM&,pSelected&)
                                           LOCAL lZStr  AS ASCIIZ * 64 
                                           LOCAL Str AS STRING
                                           LOCAL V_hFont&
                                           LOCAL V_hCtl&
                                           LOCAL V_rc AS Rect
                                           LOCAL V_hdc&
                                           CONTROL GET TEXT pCBHNDL&,pCBCTL& TO Str
                                           CONTROL HANDLE  pCBHNDL&,pCBCTL& TO V_hCtl&     ' get the handle to the control
                                           V_hdc& = GetDc(V_hCtl&)
                                          ' this paints the actual label body
                                           LOCAL Xin AS LONG
                                           LOCAL Yin AS LONG
                                           DIM vert(1) AS TRIVERTEX
                                           DIM gRect AS GRADIENT_RECT
                                           GetClientRect V_hCtl&, V_rc
                                           Xin = V_rc.nRight - V_rc.nLeft            ' don't want to go all the way to the right, or we'll paint over the border
                                           Yin = V_rc.nBottom - V_rc.nTop            ' don't want to go all the way to the bottom, or we'll paint over the border
                                           Temp& = PB_BACK&
                                           cRed&   = Temp& MOD 256
                                           cGreen& = (Temp& \ 256) MOD 256
                                           cBlue&  = ((Temp& \ 256) \ 256) MOD 256 
                                           'cRed& = 192
                                           'cGreen& = 192
                                           'cBlue& = 60
                                           vert(0).x      = 0                      ' start at pixel 2 so we don't paint over the border
                                           vert(0).y      = 0                     ' start at pixel 22 so that we don't paint over the tabs
                                           vert(0).Red    = SetColor(cRed&)
                                           vert(0).Green  = SetColor(cGreen&)
                                           vert(0).Blue   = SetColor(cBlue&)
                                           vert(0).Alpha  = &h0000
                                           vert(1).x      = Xin
                                           vert(1).y      = Yin
                                           vert(1).Red    = SetColor(cRed& - 60)
                                           vert(1).Green  = SetColor(cGreen& - 60)
                                           vert(1).Blue   = SetColor(cBlue& - 60)
                                           vert(1).Alpha  = &h0000
                                           gRect.UpperLeft  = 0
                                           gRect.LowerRight = 1
                                           RoundRect V_hdc&,V_rc.nLeft - 1,V_rc.nTop - 1,V_rc.nRight + 1,V_rc.nBottom + 1,4,4
                                           GradientFill V_hdc&, vert(0), 2, gRect, 1, %GRADIENT_FILL_RECT_v
                                           SelectObject V_hdc&,V_hFontCap&
                                           lZstr = Str                            ' copy the text to the nul terminated string
                                           SetBkMode V_hdc&, %Transparent             ' set the bg for transparent
                                           SetTextColor V_hdc&, %BLACK 'GetSysColor(%COLOR_BTNTEXT)   ' set the foreground color to black
                                           TextOut V_hdc&, V_rc.nLeft + 4 , V_rc.nTop + 3 , lZStr, LEN (lZStr)  'draw the text
                                        END SUB
                                    Bob Mechler

                                    Comment


                                    • #19
                                      Also thanks to Dominic for the excellent reference to the container control of the textbox and lookup button. The different approaches contributed for DDT and SDK warrant study.

                                      Bob Mechler

                                      Comment

                                      Working...
                                      X