Announcement

Collapse
No announcement yet.

Is this an ownerdrawn button?

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

  • Is this an ownerdrawn button?

    Hi All

    I was searching for an example of ownerdrawn button and I found this code by Steve Rossell and modified to fit
    my combobox program, Steve called it mouseoverbutton ? I wonder if it is actually an ownerdrawn button
    please pardon me as I'm only a beginner programmer.

    The main program is as below:
    Code:
    'Customized Button Combobox.bas
    
    ' Customized button with combobox -- that can use mouse hovering to display a different
    ' background color button using the MouseOverButton.inc by Steve Rossell
    ' https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/46476-ownerdraw-buttons?p=543985#post543985
    
    
    #DEBUG DISPLAY ON ' < especially useful while developing apps that use arrays !!
    #COMPILE EXE
    #INCLUDE "win32api.inc"
    #INCLUDE "MouseOverButton2.inc"
    
    #RESOURCE MANIFEST, 1, "XPTheme.xml"
    
    
    GLOBAL hDlg AS DWORD
    GLOBAL CountryArr() AS STRING
    
    %Idc_Cmb = 100
    %Idc_Lab = 108
    %Idc_BtnAdd = 110
    %ID_Lin = 112
    
    
    '=================================
    FUNCTION PBMAIN() AS LONG
    LOCAL hfb AS DWORD
    LOCAL LinThk AS LONG
    
    ' Initialize the customized button to work with mouse
    InitMouseOverButton
    
    
    FONT NEW "Fbold" ,12,1 TO hfb
    DIALOG NEW PIXELS, 0, "Please select a Country", _
    300, 300, 500, 300, %WS_THICKFRAME OR %WS_SYSMENU, 0 TO hDlg
    DIALOG SET COLOR hDlg, %RGB_MEDIUMBLUE , %RGB_AZURE
    
    ' draws a long and thick line ( at the Top of dialog ) to
    ' demarcate caption from dialog. It is long enough
    ' so that resizing the dialog would have no effect.
    ' LinThk is the line thickness
    LinThk = 4
    CONTROL ADD LINE, hDlg, %ID_Lin, "", 0, 1, 2000, LinThk,%SS_GRAYFRAME
    
    
    ' Create an customized button -- you cannot use Unicode here
    CONTROL ADD "MouseOverButton", hDlg, %Idc_BtnAdd, _
    "Add countries to combobox" , 30,18,201,23, _
    %WS_CHILD OR %WS_VISIBLE OR _
    %WS_TABSTOP, %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
    %WS_EX_RIGHTSCROLLBAR
    
    ' colors when mouse over = yellow
    ' otherwise = cornsilk
    CONTROL SEND hdlg, %Idc_BtnAdd, %WM_SETCOLORS, %RGB_LIGHTCYAN , %RGB_CORNSILK
    
    
    CONTROL ADD LABEL , hDlg, %Idc_Lab,"Country ", 30,90, 60, 20 , %SS_CENTER
    CONTROL SET COLOR hDlg, %Idc_Lab, %RGB_DARKBLUE , %RGB_AZURE
    CONTROL SET FONT hDlg,%Idc_Lab, hfb
    
    
    DIALOG SHOW MODAL hDlg CALL DlgProc
    FONT END hfb
    END FUNCTION
    
    
    
    
    
    
    '===============================================
    CALLBACK FUNCTION DlgProc() AS LONG
    LOCAL cbTxt AS STRING
    LOCAL cbItem AS LONG
    
    SELECT CASE AS LONG CBMSG
    CASE %WM_INITDIALOG
    BuildCarr
    ' Add ComboBox complete with array..
    CONTROL ADD COMBOBOX, CBHNDL, %Idc_Cmb, CountryArr() ,_
    120, 90, 175, 225, %CBS_DROPDOWN OR %WS_VSCROLL
    
    
    
    ' Not sure whether we need this block of code?
    CASE %WM_NCACTIVATE
    STATIC hWndSaveFocus AS DWORD
    IF ISFALSE CBWPARAM THEN
    ' Save control focus
    hWndSaveFocus = GetFocus()
    ELSEIF hWndSaveFocus THEN
    ' Restore control focus
    SetFocus(hWndSaveFocus)
    hWndSaveFocus = 0
    END IF
    
    
    CASE %WM_COMMAND
    
    SELECT CASE CB.CTL
    CASE %Idc_Cmb
    IF CB.CTLMSG = %CBN_SELENDOK THEN
    COMBOBOX GET TEXT CBHNDL, %Idc_Cmb TO cbTxt
    COMBOBOX GET SELECT CBHNDL, %Idc_Cmb TO cbItem
    ? " Selected Country : " + cbTxt,,"Item #" + STR$(cbItem)
    END IF
    
    CASE %Idc_BtnAdd
    ' add countries button was clicked
    BuildAddCarr
    
    END SELECT
    END SELECT
    
    END FUNCTION
    
    
    
    '================
    ' build the array for the combobox
    ' Note that Array Assign starts with LBound(Array())
    ' ie FIRST Element, not neccessarily 'element 0'
    SUB BuildCarr
    LOCAL jj AS LONG
    REDIM CountryArr(0 TO 11) ' Create array with 12 elements
    ARRAY ASSIGN CountryArr()="Cabo Verde", "Cambodia" , "Cameroon" , "Canada", "CAR" , _
    "Cayman Islands" , "Chad" , "Chile", "Colombia", "Comoros" , "Congo", "Costa Rica"
    END SUB
    
    
    
    '================
    ' Add more countries into the combobox
    ' Note that Array Assign starts with LBound(Array())
    ' ie FIRST Element, not neccessarily 'element 0'
    SUB BuildAddCarr
    ' retain the old countries name
    ' Change array to 22 elements
    REDIM PRESERVE CountryArr(0 TO 21)
    ' fill additional items
    ' NB DIM ..AT.. creates an 'absolute array'
    DIM AddOn(12 TO 21) AS STRING AT VARPTR(CountryArr(12))
    ARRAY ASSIGN AddOn()= "c13","c14","c15","c16","c17","c18","c19","c20","c21","c22"
    CONTROL KILL hDlg, %Idc_Cmb
    
    CONTROL ADD COMBOBOX, hDlg, %Idc_Cmb, CountryArr(), _
    120, 90, 175, 225, %CBS_DROPDOWN OR %WS_VSCROLL
    
    END SUB

    its include is as below:

    Code:
    'MouseOverButton2.inc
    'https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/46476-ownerdraw-buttons?p=543985#post543985
    ' This is a modified version Aug 3 2020
    ' Thanks to Steve Rossell
    
    '*************************************************************************************'
    '* MouseOverButton Custom Control Example *'
    '* *'
    '* Example of how to create a custom control and register it, so it can be used by *'
    '* windows and dialog boxes. *'
    '*************************************************************************************'
    
    
    ' You need to include "Win32API.inc" in the main program
    
    ' Custom message used to set the button colors
    ' WM_USER to WM_USER + 7FFF are available for custom messages
    %WM_SETCOLORS = %WM_USER + 1
    
    
    '*************************************************************************************'
    '* InitMouseOverButton *'
    '* *'
    '* Purpose: *'
    '* Register the MouseOverButton Window Class, which allows DDT and SDK to add this *'
    '* control to a Dialog or Window. *'
    '* *'
    '* Output: *'
    '* DWORD value indicating success for failure of registering the control. if the *'
    '* function succeeds, the return value is an atom that uniquely identifies the class *'
    '* being registered. If the function fails zero is returned. *'
    '*************************************************************************************'
    FUNCTION InitMouseOverButton AS DWORD
    LOCAL ClassName AS ASCIIZ * 32 ' Unique class name for the control
    LOCAL wc AS WNDCLASS ' Window attributes for the control
    
    ClassName = "MouseOverButton" ' Class name
    
    wc.Style = %CS_HREDRAW OR %CS_VREDRAW ' Redraw the entire window
    wc.lpfnWndPRoc = CODEPTR(MouseOverButtonProc) ' Message handeler function
    wc.hIcon = %NULL ' No icon for the control
    wc.hCursor = LoadCursor(%NULL, BYVAL %IDC_HAND) ' Use hand mouse cursor
    wc.hbrBackground = 0 ' Ignored, use WM_SETCOLORS
    wc.lpszMenuName = %NULL ' No menu needed for the control
    wc.lpszClassName = VARPTR(ClassName) ' Class name
    
    FUNCTION = RegisterClass(wc) ' Register the custom control
    END FUNCTION
    
    
    
    
    '*************************************************************************************'
    '* MouseOverButtonProc *'
    '* *'
    '* Purpose: *'
    '* Process messages sent to the custom control. *'
    '* *'
    '* Input: *'
    '* hWnd : Handle of the control *'
    '* wMsg : The message being sent to the control *'
    '* wParam: First message parameter *'
    '* lParam: Second message parameter *'
    '* *'
    '* Output *'
    '* A long interger value that is the result of the message processing and depends on *'
    '* the message.
    
    ' you cannot use Unicode here *'
    '*************************************************************************************'
    FUNCTION MouseOverButtonProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD,_
    BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
    STATIC btnState AS LONG ' 0 = Button up, 1 = Button down
    STATIC MouseOver AS LONG ' 0 = MouseOut, 1 = MouseOver
    STATIC ColorOver AS LONG ' MouseOver color
    STATIC COlorOut AS LONG ' MouseOut color
    LOCAL r AS RECT ' Size and positon of the control
    LOCAL szText AS ASCIIZ *100 ' Text used on the control
    LOCAL hdc AS DWORD ' The control DC
    LOCAL ps AS PAINTSTRUCT ' Painting Information
    LOCAL hbrush AS DWORD ' Colored brush used to paint
    LOCAL pt AS POINTAPI ' Mouse cursor location
    LOCAL BkClr AS LONG ' Background Color of the control
    LOCAL FrClr AS LONG ' ForeColor of the control
    
    ' Process messages
    SELECT CASE AS LONG wMsg
    
    CASE %WM_SETCOLORS ' Set the controls colors
    ColorOver = wParam ' Set MouseOver color
    ColorOut = lParam ' Set MouseOut color
    
    CASE %WM_PAINT ' Draw the control
    GetClientRect(hWnd, r) ' Size and location fo the control
    GetWindowText(hWnd, szText, SIZEOF(szText)) ' Get the text shown on the control
    
    
    IF MouseOver = 1 THEN
    ' the cursor is over the control?
    BkClr = ColorOver ' Use MouseOver color
    FrClr = %RGB_MAGENTA
    ELSE
    BkClr = ColorOut ' Use MouseOut color
    FrClr = %RGB_MEDIUMBLUE
    END IF
    
    hbrush = CreateSolidBrush(BkClr) ' Create a brush with the color
    SelectObject(hdc, hBrush) ' Select the brush
    
    hdc = BeginPaint(hwnd, ps) ' Prepare the control for painting
    FillRect hdc, r, hbrush ' Draw a solid rectangle
    
    IF btnState = 1 THEN
    ' When the button is clicked
    DrawEdge(hdc, r, %EDGE_SUNKEN, %BF_RECT) ' Draw a sunken edge
    ELSE
    DrawEdge(hdc, r, %EDGE_RAISED, %BF_RECT) ' Draw a raised edge
    END IF
    
    SetBkColor(hdc, BkClr) ' Set the text background color
    SetTextColor(hdc, FrClr) ' Set the text color
    
    ' Draw the text
    DrawText(hdc, szText, -1, r, %DT_CENTER OR %DT_VCENTER OR %DT_SINGLELINE)
    
    DeleteObject(hBrush) ' Delete the brush
    EndPaint(hwnd, ps) ' End painting
    
    
    CASE %WM_MOUSEMOVE
    ' The mouse moved over the control
    IF MouseOver = 0 THEN ' Was the mouse already over?
    SetCapture(hWnd) ' Capture the mouse
    MouseOver = 1 ' Mouse is over the control
    InvalidateRect(hwnd, BYVAL %NULL, %TRUE) ' Repaint the control
    ELSE
    GetWindowRect(hwnd, r) ' Size and location of the control
    GetCursorPos(pt) ' Location of the mouse cursor
    IF PtInRect( r, pt ) = %FALSE THEN ' Is cursor still over the control PtInRect(r, pt.x, pt.y )
    CALL ReleaseCapture() ' Stop capturing the mouse
    MOuseOver = 0 ' Mouse is not over the control
    InvalidateRect(hwnd, BYVAL %NULL, %TRUE) ' Repaint the control
    END IF
    END IF
    EXIT FUNCTION
    
    
    CASE %WM_LBUTTONUP
    ' Left mouse button is now up
    btnState = 0 ' Button is up
    CALL ReleaseCapture() ' Stop capturing the mouse
    MOuseOver = 0 ' Mouse is not over the control
    InvalidateRect(hwnd, BYVAL %NULL, %TRUE) ' Repaint the control
    
    ' Send a BN_CLICKED message to the controls parent window procedure
    SendMessage(GetParent(hwnd), %WM_COMMAND, MAKLNG(GetWindowLong(hwnd, %GWL_ID), %BN_CLICKED), hwnd)
    EXIT FUNCTION
    
    CASE %WM_LBUTTONDOWN: ' Left mouse button is down
    btnState = 1 ' Button is down
    InvalidateRect(hwnd, BYVAL %NULL, %TRUE) ' Redraw the button
    EXIT FUNCTION
    
    END SELECT
    
    ' Pass any messages we did not process onto Windows to handle
    FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
    END FUNCTION

  • #2
    How would we classify an ownerdrawn button ? what are its chief characteristics?
    The above program is sweet as it displays a very delightful view of a button and its real time interaction with the mouse.

    Comment


    • #3
      Custom controls can be created in several different ways:

      Ownerdraw - If a standard control has the "ownerdraw" style flag, the parent window receives a WM_DRAWITEM message and it is up to you to write the code to display the control the way you want when that message is received for for that control.. Windows handles all other notification as normal.

      Sub-class a standard control - When you sub-class a control, you write functions to dictate the way the control behaves when it receives certain messages. You replace the standard callback behaviour for those messages with your own code.

      From scratch - You create and register a new Class and code everything to do with it.your

      See https://docs.microsoft.com/en-us/win...controls-intro


      Your include file is the third variety - it is a new Class created from scratch.





      Comment


      • #4
        Thank you Sir Stuart

        I have a question about the below code block as to whether it is really needed or not, originally it was from the
        same main program written by Steve Rossell, see the link
        https://forum.powerbasic.com/forum/u...985#post543985



        As nothing in the program deals with non client portion ( concering % WM_NCACTIVATE ) of the dialog, I had this code block commented
        out. And that after this process, I found that this program still works the same?

        Looks like %WM_NCACTIVATE is of little use ?

        Code:
        ' Not sure whether we need this block of code?
        CASE %WM_NCACTIVATE
        STATIC hWndSaveFocus AS DWORD
        IF ISFALSE CBWPARAM THEN
        ' Save control focus
        hWndSaveFocus = GetFocus()
        ELSEIF hWndSaveFocus THEN
        ' Restore control focus
        SetFocus(hWndSaveFocus)
        hWndSaveFocus = 0
        END IF
        I do believe that this code block is redundant?

        Comment


        • #5

          This code block is active when your app's nonclient area needs to be changed to indicate an active or inactive state. eg when the user switches between windows.

          It uses a static variable to remember / restore keyboard focus to a control when the user leaves / returns to working with your app.

          Useful for apps that have several controls and is convienient for user to return to the same control. For example on a form with data entry text boxes when the user switches windows to refer to other resources before completing the form.
          Rgds, Dave

          Comment


          • #6
            Thank you Sir Biggs, I learn much from you. I would definitely need this code block as I will be dealing with
            multiple controls and switching between multiple windows dialogs

            Comment


            • #7
              See if you can find some code from Borje Hagsten called "RR Button" ... it really shows you how to create and manage ownerdraw buttons.

              I am positive I got it here so it should be around.

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

              Comment


              • #8
                About half way down the page.

                Comment


                • #9
                  Hm, from RRBUTTON.INC: ' Public Domain by Borje Hagsten, September 2001
                  19 years ago. Just looked at code and it even contains pallete creation for 256 color mode. Guess it's time to clean out some garbage there and update it. Could be a fun next project. I'll be back..

                  Comment

                  Working...
                  X