Announcement

Collapse
No announcement yet.

Custom Controls/Sub Classing

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

  • mark smit
    Guest replied
    Thank you!


    I also have some code that subclasses an edit control to allow it
    to use the mouse wheel. This only works with numerical edit boxes
    but It does save on keyboard typing. Just click on the control and
    scroll the mouse wheel and watch the numbers roll up and down.

    If anybody is interested please let me know and I'll be happy to
    post the code here!



    ------------------
    Cheers

    Leave a comment:


  • Steve Hutchesson
    replied
    Compliments Mark,

    A nicely done piece of code, we need a custom control expert floating
    around here as a lot of people are interested in this type of code
    so keep up the good work.

    regards,

    [email protected]

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

    Leave a comment:


  • mark smit
    Guest replied
    Hey Jules!


    I just remembered these from the MSDN...

    Code:
    CopyRect rc2, rc
    OffsetRect rc2, 2, 2
    You could use CopyRect instead of calling GetClientRect two times
    and OffsetRect to offse the text RECT. I was using them before to
    do what you suggested but I got lazy when I redid the control (smile).


    There are a couple of reasons for going with a DLL for my controls.

    1. Very easy to update the controls without having to recompile all
    the source code.

    2. If I want to try a "new look" with my application all I have to
    do is change the DLL to one with diffrent button drawing code.

    3. Just becuase I wanted to learn about DLL's.

    I am really happy that I can finally give somthing back to this
    forum instead of always being the one to ask questions!




    ------------------
    Cheers

    Leave a comment:


  • Jules Marchildon
    replied
    Mark,

    Nice code example to which we can build on, Thank You! The fact you are using it
    for your own use 'vs' distributing the DLL, I personally feel that this
    would be better served if it was an include file. The code is small, why
    have an extra DLL. I have already cut and pasted it into my include
    file and made some modifications to it.

    To give the button a nicer effect when the button is depressed, offset the
    text by a couple of pixels.

    <edited, added some more effects to make it look like a real normal button>
    <from here you can modify color,font,add bitmap etc, good starting point >

    Code:
    '----------------------------------------------------------------------------
    'rem custom control handler
    '----------------------------------------------------------------------------
    function StrataButtonProc(byval hWnd as long, byval message as long, byval wParam as long, byval lParam as long) export as long
     
        local  szMessage as asciiz * 64
        local  ps        as PAINTSTRUCT
        local  rc        as RECT
        local  rc2       as RECT
        local  hdc       as long
        static fDown     as long
        static fGotFocus as long
        local  pt        as POINTAPI
     
        select case (message)
              
            case %WM_KILLFOCUS
     
                'remove focus band
                InvalidateRect hWnd, byval %NULL, %TRUE
                fGotFocus = 0
                function = 0
                exit function
     
            case %WM_MOUSEMOVE
                pt.x = LOWRD( lParam)
                pt.y = HIWRD( lParam)
     
                'is the mouse still inside our button while SetCapture
                if fDown = 1 Then
                     GetClientRect hWnd, rc
                     IF  PtInRect( rc, pt.x,pt.y ) = %FALSE THEN
                         ReleaseCapture
                         fDown = 0
                         InvalidateRect hWnd, byval %NULL, %TRUE
                     End IF
                end if
     
            case %WM_LBUTTONDOWN
                SetCapture hWnd
                fDown = 1
                fGotFocus = 1
                SetFocus hWnd
                InvalidateRect hWnd, byval %NULL, %TRUE
                function = 0
                exit function
     
            case %WM_LBUTTONUP
                ReleaseCapture
                fDown = 0
                InvalidateRect hWnd, byval %NULL, %TRUE
                SendMessage GetParent(hWnd), %WM_COMMAND, maklng(GetWindowLong(hWnd,%GWL_ID),%BN_CLICKED), hWnd
                function = 0
                exit function
     
            case %WM_ERASEBKGND
                 FUNCTION = 0
                 EXIT FUNCTION
     
            case %WM_PAINT
     
                hdc = BeginPaint(hWnd, ps)
     
                GetWindowText hWnd, szMessage, sizeof(szMessage)
                GetClientRect hWnd, rc
                GetClientRect hWnd, rc2
     
                SelectObject hdc, SendMessage(GetParent(hWnd),%WM_GETFONT,0,0)
     
                SetTextColor hdc, GetSysColor(%COLOR_BTNTEXT)
                SetBkColor hdc, GetSysColor(%COLOR_BTNFACE)
     
                FillRect hdc, rc, GetSysColorBrush(%COLOR_BTNFACE)
     
                if fDown = 1 Then
                    'button down
                    rc2.nLeft = rc.nLeft +2
                    rc2.nTop  = rc.nTop  +2
                    DrawText hdc, szMessage, len(szMessage), rc2, %DT_CENTER or %DT_SINGLELINE or %DT_VCENTER
                    DrawEdge hDC, rc, %EDGE_SUNKEN , %BF_RECT
     
                else
                    'button up
                    DrawText hdc, szMessage, len(szMessage), rc, %DT_CENTER or %DT_SINGLELINE or %DT_VCENTER
                    DrawEdge hDC, rc, %EDGE_RAISED  , %BF_RECT
                end if
     
                If fGotFocus = 1 Then
                    InflateRect rc,-4,-4
                    DrawFocusRect hDC,rc
                End IF
     
                EndPaint hWnd, ps
                 
                function = 0
                exit function
     
        end select
     
        'rem call default window procedure
        function = DefWindowProc(hWnd, message, wParam, lParam)
    end function
    And thanks again for the code!
    Best regards, Jules
    mailto:[email protected][email protected]</A>


    [This message has been edited by Jules Marchildon (edited November 24, 2000).]

    Leave a comment:


  • mark smit
    Guest replied
    thanks!


    *constructive* comments well taken! in our application, screen space
    is at a premium so i have to make new controls for every thing in
    order to reclame as much space as possible. for example, my button
    uses only a single line border verses the normal inner and outer lines.
    because this control is only going to be used for its original purpose
    i have kept the "styles" and "features" to a minimum. this is my first
    crack at custom controls and it seems to be going well. i really
    appreciate all the advice i've been given in these forums. i feel
    like i should be paying you all tuition fees!

    btw: did any of you see my contribution to the source code forum?

    "convert vs resource.h files" http://www.powerbasic.com/support/pb...ad.php?t=22838

    this utility converts the resource.h files generated by visualstudio
    into a powerbasic resource.inc file. i made it because i was sick
    of editing every time i made a change. now all i have to do is...

    rc [resource.rc]
    pbres [resource.res]
    makinc [resource.h]

    wish: maybe the nice powerbasic people will put this into there compiler?




    ------------------
    cheers

    Leave a comment:


  • Lance Edmonds
    replied
    Neat code! However, I have a couple of points for you to ponder... please think of these as *constructive* comments!

    1. I don't believe it is necessary to unregister the window class when a thread detaches, and likewise when a thread attaches. Window classes are process-local, not thread-local. Other than those issues, the rest of the code looks fairly thread safe (although I;ve not gone through it thoroughly). You should definitely test any custom control in a multi-threaded app before unleashing it upon the world...

    For the lurkers: While Windows automatically unregisters window classes on app termination, it is good that you have handled this in your code because DLL's that register window classes MUST unregister their window classes during process detach under Windows 2000/NT.

    2. Your custom control callback returns zero (by default) for several messages - this may or may not need to be addressed.

    3. Your control does not support disabled/grayed state.

    4. There is no handling for "external" code to query the state of the custom control (ie, query whether the control is Pressed, Normal or Disabled, etc).

    5. You could add support for %WM_SETREDRAW - handling this may be overkill, so YMMV.

    6. You could add support for double clicks and "pushlike" styles.

    7. There is no error checking in your code at all.

    8. You are selecting a font into the devioce context during %WM_PAINT but do not restore the original font handle.

    9. When painting the button, you could send a %WM_CTLCOLORBUTTON message to the parent window procedure - that way you could allow the user to customize the control's color scheme. Since standard buttons do not actually allow the color scheme to change, you'll add an "important" feature the overcomes the standard buttons' limitation.

    I hope that these ideas are of some help. Remember, I said they were *constructive* comments! If you can cater to all of these, you'll have a great custom button control!

    PS: did I mention support for BMP images? <cheeky grin!>



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

    Leave a comment:


  • mark smit
    Guest replied
    Hello All!

    I have already made my custom button control from scratch and here
    is the code for it. The big thing is that I wish I didn't have to
    select the font or setup the colors each time WM_PAINT rolls around

    Code:
    #compile dll
    #register none
    #include "win32api.inc"
    
    rem function declares
    declare function RegisterCustomControls(byval hInstance as long) as long
    declare function UnregisterCustomControls(byval hInstance as long) as long
    declare function InitStrataControls() as long
    
    
    rem main dll entry point
    function LibMain(byval hInstance as long, byval fwdReason as long, byval lpvReserved as long) export as long
        select case (fwdReason)
            case %DLL_PROCESS_ATTACH
                function = RegisterCustomControls(hInstance)
    
            case %DLL_PROCESS_DETACH
                function = UnregisterCustomControls(hInstance)
    
            case %DLL_THREAD_ATTACH
                function = RegisterCustomControls(hInstance)
    
            case %DLL_THREAD_DETACH
                function = UnregisterCustomControls(hInstance)
    
        end select
    end function
    
    function InitStrataControls() export as long
    end function
    
    
    rem register custom classes
    function RegisterCustomControls(byval hInstance as long) as long
        local szClassName as asciiz * 80
        local wcex as WNDCLASSEX
    
    
        rem setup class name
        szClassName = "StrataButton"
    
    
        rem setup class structure
        wcex.cbSize = sizeof(wcex)
        wcex.style = %CS_HREDRAW or %CS_VREDRAW or %CS_GLOBALCLASS or %CS_PARENTDC
        wcex.lpfnWndProc = codeptr(StrataButtonProc)
        wcex.cbClsExtra = 0
        wcex.cbWndExtra = 0
        wcex.hInstance = hInstance
        wcex.hIcon = %NULL
        wcex.hIconSm = %NULL
        wcex.hCursor = LoadCursor(%NULL, byval %IDC_ARROW)
        wcex.hbrBackground = %COLOR_APPWORKSPACE
        wcex.lpszClassName = varptr(szClassName)
        wcex.lpszMenuName = %NULL
    
    
        rem register control class
        function = RegisterClassEx(wcex)
    end function
    
    rem unregister custom classes
    function UnregisterCustomControls(byval hInstance as long) as long
        local szClassName as asciiz * 80
    
    
        rem setup class name
        szClassName = "StrataButton"
    
    
        rem unregister control classes
        function = UnregisterClass(szClassName, hInstance)
    end function
    
    
    rem custom control handler
    function StrataButtonProc(byval hWnd as long, byval message as long, byval wParam as long, byval lParam as long) export as long
        local szMessage as asciiz * 64
        local ps as PAINTSTRUCT
        local rc as RECT
        local hdc as long
    
    
        select case (message)
            case %WM_LBUTTONDOWN
                SetCapture hWnd
                SetWindowLong hWnd, %GWL_USERDATA, %TRUE
                InvalidateRect hWnd, byval %NULL, %TRUE
                exit function
    
    
            case %WM_LBUTTONUP
                ReleaseCapture
                SetWindowLong hWnd, %GWL_USERDATA, %FALSE
                InvalidateRect hWnd, byval %NULL, %TRUE
                SendMessage GetParent(hWnd), %WM_COMMAND, maklng(GetWindowLong(hWnd,%GWL_ID),%BN_CLICKED), hWnd
                exit function
    
    
            case %WM_PAINT
                hdc = BeginPaint(hWnd, ps)
                GetWindowText hWnd, szMessage, sizeof(szMessage)
                GetClientRect hWnd, rc
                SelectObject hdc, SendMessage(GetParent(hWnd),%WM_GETFONT,0,0)
                SetTextColor hdc, GetSysColor(%COLOR_BTNTEXT)
                SetBkColor hdc, GetSysColor(%COLOR_BTNFACE)
                FillRect hdc, rc, GetSysColorBrush(%COLOR_BTNFACE)
                DrawText hdc, szMessage, len(szMessage), rc, %DT_CENTER or %DT_SINGLELINE or %DT_VCENTER
    
                if GetWindowLong(hWnd,%GWL_USERDATA) then
                    DrawEdge hDC, rc, %BDR_SUNKENINNER, %BF_RECT
                else
                    DrawEdge hDC, rc, %BDR_RAISEDINNER, %BF_RECT
                end if
    
                EndPaint hWnd, ps
                exit function
    
        end select
    
    
        rem call default window procedure
        function = DefWindowProc(hWnd, message, wParam, lParam)
    end function

    Does anybody have any pointers for me on this code?

    ------------------
    Cheers

    Leave a comment:


  • Steve Hutchesson
    replied
    Mark,

    I can post you the code for subclassing a windows control but I have a toy
    on my web site that does it correctly so a download of about 12k will solve
    that one.
    http://www.pbq.com.au/home/hutch/pbdll50.htm

    The file is subclass.zip

    For a button replacement control, starting from scratch is a lot more
    profitable where modifying an existing control (superclassing) definitely
    has its limitations.

    CreateWindowEx() and a normal WndProc style message handling procedure
    give you the maximum control when designing custom controls. The main trick
    is to use the extra window memory to store settings for each control called
    from the app that uses it.

    You will need to get the swing of SetCapture() / ReleaseCapture() when
    handling button up & down states from any of the WM_(mouse) messages but
    it is reasonably straight forward stuff. You normally send a WM_COMMAND
    message back to the parent so it knows when the button has been pressed
    ands you can dial in more or less any variation you want to get the effect
    you like.

    You have a number of options when drawing the UP and DOWN states of the button,
    roll your own GDI line function to frame the window, BitBlt() bmp images
    for the 2 states, you can use either DrawText() or TextOut() to display text
    on the button face in any color or font you like.

    Once you get the swing of this stuff, you have got under the interface of
    windows and can do basically anything you like.

    Regards,

    [email protected]

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

    Leave a comment:


  • Dominic Mitchell
    replied
    Mark,
    Since you have Newcomer and Rector hop over to page 225.
    Unfortunately, when a control class is set to CS_PARENTDC
    the only thing it inherits from the parent class is the clipping
    region(client area). What a joke!
    This is actually very eay to test using what I like to call lazy
    controls(e.g. groupbox). Put the groupbox in a window then use a
    large bitmap or large font for its caption. Now select a small
    bitmap or font for it caption(do not redraw the entire window just
    the groupbox). You should now be left with a messed up window.

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

    Leave a comment:


  • mark smit
    Guest replied
    Hello Chris!


    I am making a button replacment control and I want the font to be
    the same as the dialogs. It states in the Win32 (Rector/Newcomer)
    book that each device context has a default font,brush,pen,etc...
    so if I use the same DC as the controls parent by specifing
    CS_PARENTDC then I should get the same font right? I have tried
    the above and it doesn't work.

    ------------------
    Cheers

    Leave a comment:


  • Chris Boss
    replied
    Mark;

    (1) I believe the custom controls do NOT use CS_OWNDC. They use the
    parent windows DC which means when you draw into the controls DC
    you need to restore the attributes of the DC when you are done.

    (2) You should use GetWindowLong to get the controls original
    window procedure (callback). If the control was already subclassed
    (ie. A tooltip control will subclass controls it is attached to)
    you will get the "current" window procedure address, not the original
    , but this is proper because if you used GetClassLong to get the
    "original" Window procedure, and used it in your subclass routine,
    you would "override" any other subclassing that may previously have
    implimented. By using GetWindowLong, you can subclass a control multiple
    times with no problem.

    (3) The original Dialog Editor (that comes with PB) does have
    special functions that must be defined in a custom control for
    the custom controls to be recognized by the Editor. I do not
    know if Visual Studio still supports those functions.

    For more info see the book :

    Windows Custom Controls
    By William Smith and Robert Ward
    Published by R&D Publications, Inc.
    USA

    The book is about 16 bit Windows, but the majority
    of info is still the same for 32 bit windows. There
    are just a few differences in 32 bit windows.

    I couldn't find any books for 32 bit windows about
    building custom controls that are not ActiveX, but
    simply DLLs.


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

    Leave a comment:


  • mark smit
    Guest started a topic Custom Controls/Sub Classing

    Custom Controls/Sub Classing

    Hello Everybody!


    I have a few questions about windows control classes and
    subclassing, so here's the questions.


    1. Can I assume that all windows controls (EDIT,BUTTON...) where
    created with the class style CS_OWNDC?

    2. When subclassing a control is it propper to get the original
    controls callback pointer from GetClassLong?

    3. Is there any way to get a custom control created with PBDLL
    to show up in VisualStudio? I have asked this before but I could
    figure out what the answer ment.


    ------------------
    Cheers
Working...
X