Announcement

Collapse
No announcement yet.

Superclass New Control

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

  • Superclass New Control

    I'm new to windows programming but have been programming in basic
    for a lot of years. I have searched the forums and I believe I
    understand subclassing and superclassing concepts.

    I'm looking for the easiest way to implement a custom control for
    a "lookup" control that contains a text box and an ellipsis button.
    The idea is the user can directly input the text into the text box
    or press the ellipsis button which should send a message back to
    the callback function. This message would cause another model dialog
    to be open listing another table of data to select from.

    I know you can superclass the edit box, but can you also add a
    standard button to the control? If so, how might you distinguish
    the message from edit box verses the button, maybe the rect the
    mouse occured over? I don't think you can add multiple standard
    controls to a single superclassed control. If not, would I have
    to implement all the edit and button functionality myself.

    I would appreciate any information you could point me toward.

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

  • #2
    You can create a compound control from existing controls by either
    1. bundling them in a container
    -or-
    2. pick one control from the set and embed the remaining controls in it.

    To embed the button in the edit control you would
    1. Create the edit control with the WS_CLIPCHILDREN style so that it does not draw over
    the button.
    2. (a) Use the SetParent function to make the edit control the parent of the button or
    (b) pass the handle of the edit control to the CreateWindowEx function when creating
    the button.
    3. Set the right margin of the edit control to the width of the button so that the caret
    does not get lost under the button.
    4. Subclass or superclass the edit control so that you can pass the button's BN_CLICKED
    notification to the parent of the edit control.

    Well, this approach is quick and easy but not reuseable.

    Putting the controls in a container is the most flexible method and is reuseable. This is
    the method you would use to make a full blown custom control.
    The code below uses an include file for the custom control but you can put this stuff in
    a dll and sell it as follows:
    [CODE]
    In LibMain do the this

    SELECT CASE fwdReason
    CASE %DLL_PROCESS_ATTACH
    RegisterLookUpClass32

    CASE %DLL_PROCESS_DETACH
    UnregisterLookUpClass32
    END SELECT

    FUNCTION = %TRUE
    [CODE]
    This sample consists of two parts, the custom control code and the code to test it.
    For an example of a custom control built from the ground up see Borje's EDM32 control.

    ==========================
    Code to test custom contol
    ==========================
    Code:
    #DIM ALL
    #REGISTER NONE
    #COMPILE EXE
    #OPTION VERSION4
             
    #INCLUDE "WIN32API.INC"
    #INCLUDE "LOOKUP.INC"
           
    '=========================== [ Control Identifiers ] ===========================
            
    ' Form2
    %IDD_FORM2                                  = 1000
    %IDC_FORM2_LOOKUP1                          = 1001
    %IDC_FORM2_TEXTBTN1                         = 1002
             
    '====================== [ Global Variable Declarations ] =======================
           
    GLOBAL  ghInstance    AS DWORD    ' handle of the application instance
                
    '-------------------------------------------------------------------------------
    '
    ' PROCEDURE: WinMain
    ' PURPOSE:   Program entry point, calls initialization function, processes
    '            message loop.
    '
    '-------------------------------------------------------------------------------
              
    FUNCTION WinMain _
      ( _
      BYVAL hInstance     AS LONG, _        ' handle of current instance
      BYVAL hPrevInstance AS LONG, _        ' handle of previous instance(not used in Win32)
            pszCmdLine    AS ASCIIZ PTR, _  ' address of command line
      BYVAL nCmdShow      AS LONG _         ' show state of window
      ) AS LONG
                       
      LOCAL szClassName   AS ASCIIZ * %MAX_PATH   ' class name
      LOCAL twcx          AS WNDCLASSEX           ' class information
      LOCAL tmsg          AS tagMsg               ' message information
      LOCAL hWnd          AS DWORD                ' handle of main window
                  
      ' Save the handle of the application instance
      ghInstance = hInstance
                       
      ' Register the Form2 window
      szClassName        = "Form2_Class"
      twcx.cbSize        = SIZEOF(twcx)                               ' size of WNDCLASSEX structure
      twcx.style         = %CS_DBLCLKS                                ' class styles
      twcx.lpfnWndProc   = CODEPTR(Form2_WndProc)                     ' address of window procedure used by class
      twcx.cbClsExtra    = 0                                          ' extra class bytes
      twcx.cbWndExtra    = 0                                          ' extra window bytes
      twcx.hInstance     = ghInstance                                 ' instance of the EXE/DLL that is registering the window
      twcx.hIcon         = LoadIcon(%NULL, BYVAL %IDI_APPLICATION)    ' handle of class icon
      twcx.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)        ' handle of class cursor
      twcx.hbrBackground = %COLOR_BTNFACE + 1                         ' brush used to fill background of window's client area
      twcx.lpszMenuName  = %NULL                                      ' resource identifier of the class menu
      twcx.lpszClassName = VARPTR(szClassName)                        ' class name
      twcx.hIconSm       = LoadIcon(%NULL, BYVAL %IDI_APPLICATION)    ' handle of small icon shown in caption/system Taskbar
      IF ISFALSE RegisterClassEx(twcx) THEN
        FUNCTION = %FALSE
        EXIT FUNCTION
      END IF
               
      ' Register custom control
      RegisterLookUpClass32
                
      ' Create the Form2 window
      hWnd = CreateWindowEx(%WS_EX_WINDOWEDGE, _                                          ' extended styles
                            "Form2_Class", _                                              ' class name
                            "Testing", _                                                  ' caption
                            %WS_OVERLAPPEDWINDOW OR %WS_VISIBLE, _                        ' window styles
                            70, 94, _                                                     ' left, top
                            360, 178, _                                                   ' width, height
                            %NULL, %NULL, _                                               ' handle of owner, menu handle
                            ghInstance, BYVAL %NULL)                                      ' handle of instance, creation parameters
      ' If window could not be created, return "failure"
      IF ISFALSE hWnd THEN
        FUNCTION = %FALSE
        EXIT FUNCTION
      END IF
                
      ' Make the window visible; update its client area
      ShowWindow hWnd, %SW_SHOW
      UpdateWindow hWnd
              
      ' Main message loop of program.
      ' Acquire and dispatch messages until a WM_QUIT message is received.
      WHILE ISTRUE GetMessage(tmsg, BYVAL %NULL, 0, 0)
        IF ISFALSE IsDialogMessage(hWnd, tmsg) THEN
          TranslateMessage tmsg
          DispatchMessage tmsg
        END IF
      WEND
             
      FUNCTION = tmsg.wParam
             
    END FUNCTION
             
    '-------------------------------------------------------------------------------
    '
    ' PROCEDURE: Form2_WndProc
    ' PURPOSE:   Processes messages for the Form2 window.
    '
    '-------------------------------------------------------------------------------
            
    FUNCTION Form2_WndProc _
      ( _
      BYVAL hWnd    AS DWORD, _ ' window handle
      BYVAL uMsg    AS DWORD, _ ' type of message
      BYVAL wParam  AS DWORD, _ ' first message parameter
      BYVAL lParam  AS LONG _   ' second message parameter
      ) EXPORT AS LONG
            
      LOCAL hWndChild   AS DWORD    ' handle of child window
      LOCAL hFont       AS DWORD    ' handle of font used by parent
             
      SELECT CASE uMsg
        CASE %WM_COMMAND
           
          SELECT CASE LOWRD(wParam)
            CASE %IDC_FORM2_LOOKUP1
                    
              SELECT CASE HIWRD(wParam)
                CASE %LUN_CHANGE
                      
                CASE %LUN_UPDATE
                        
                CASE %LUN_CLICKED
                  MSGBOX "Input extra info"
              END SELECT
                    
            CASE %IDOK
              IF HIWRD(wParam) = %BN_CLICKED THEN
                PostMessage hWnd, %WM_CLOSE, 0, 0
              END IF
          END SELECT
                      
        CASE %WM_ACTIVATE
          ' Set the keyboard focus to the first control that is
          ' visible, not disabled, and has the WS_TABSTOP style
          IF LOWRD(wParam) = %WA_ACTIVE THEN
            SetFocus GetNextDlgTabItem(hWnd, %NULL, %FALSE)
          END IF
          FUNCTION = %FALSE
          EXIT FUNCTION
                   
        CASE %WM_DESTROY
          PostQuitMessage 0
          FUNCTION = %FALSE
          EXIT FUNCTION
               
        CASE %WM_CREATE
          ' Create font used by container
          hFont = GetStockObject(%DEFAULT_GUI_FONT)
                   
          ' Create the LookUp control
          hWndChild = CreateWindowEx(%WS_EX_CLIENTEDGE, _                                 ' extended styles
                                     "LookUpClass32", _                                            ' class name
                                     "", _                                                ' caption
                                     %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, _         ' window styles
                                     16, 10, _                                            ' left, top
                                     212, 22, _                                           ' width, height
                                     hWnd, %IDC_FORM2_LOOKUP1, _                            ' handle of parent, control ID
                                     ghInstance, BYVAL %NULL)                             ' handle of instance, creation parameters
          SendMessage hWndChild, %WM_SETFONT, hFont, %TRUE
                       
          ' Create the LookUpTextBtn1 text button
          hWndChild = CreateWindowEx(%NULL, _                                             ' extended styles
                                     "Button", _                                          ' class name
                                     "OK", _                                              ' caption
                                     %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _         ' window styles
                                     %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, _       ' class styles
                                     145, 106, _                                          ' left, top
                                     63, 23, _                                            ' width, height
                                     hWnd, %IDC_FORM2_TEXTBTN1, _                         ' handle of parent, control ID
                                     ghInstance, BYVAL %NULL)                             ' handle of instance, creation parameters
          SendMessage hWndChild, %WM_SETFONT, hFont, %TRUE
                   
          FUNCTION = %FALSE
          EXIT FUNCTION
      END SELECT
                  
      FUNCTION = DefWindowProc(hWnd, uMsg, wParam, lParam)
                 
    END FUNCTION
    ===============================
    Looup Include File - LookUp.inc
    ===============================
    Code:
    ' LookUp Styles
    ' -------------
    ' This control has no per instance class styles
                 
    ' LookUp Notification Codes(sent via the WM_COMMAND message)
    ' -------------------------
    %LUN_CLICKED   = %WM_USER + &H7F00 
    ' Purpose: sent when the child button control is clicked.
    ' wParam:  lowrd = cutom control id.  Hiwrd = notification
    ' lParam:  handle of custom control
    ' Return:
              
    %LUN_SETFOCUS  = %WM_USER + &H7F01 
    ' Purpose: sent when the child edit control gains the keyboard focus.
    ' wParam:  lowrd = cutom control id.  Hiwrd = notification
    ' lParam:  handle of custom control
    ' Return:
            
    %LUN_KILLFOCUS = %WM_USER + &H7F02
    ' Purpose: sent when the child edit control loses the keyboard focus.
    ' wParam:  lowrd = cutom control id.  Hiwrd = notification
    ' lParam:  handle of custom control
    ' Return:
              
    %LUN_CHANGE    = %WM_USER + &H7F03 
    ' Purpose: sent after the child edit control displays altered text.
    ' wParam:  lowrd = cutom control id.  Hiwrd = notification
    ' lParam:  handle of custom control
    ' Return:
              
    %LUN_UPDATE    = %WM_USER + &H7F04
    ' Purpose: sent when the child edit control is about to display altered text.
    ' wParam:  lowrd = cutom control id.  Hiwrd = notification
    ' lParam:  handle of custom control
    ' Return:
             
    ' LookUp Messages
    ' ---------------
    %LUM_SETLIMITTEXT    = %WM_USER + &H7F00
    ' Purpose: gets the handle of the child listview control.
    ' wParam:  new text limits, in bytes
    ' lParam:  N/A
    ' Return:
              
    %LUM_GETLIMITTEXT    = %WM_USER + &H7F01
    ' Purpose: retrieves the current text limit, in characters, for child edit control.
    ' wParam:  N/A
    ' lParam:  N/A
    ' Return:  text limit
            
    %LUM_GETEDITHANDLE   = %WM_USER + &H7F02
    ' Purpose: gets the handle of the child edit control.
    ' wParam:  N/A
    ' lParam:  N/A
    ' Return:  handle of child edit control
              
    %LUM_GETBUTTONHANDLE = %WM_USER + &H7F03
    ' Purpose: gets the handle of the child button control.
    ' wParam:  N/A
    ' lParam:  N/A
    ' Return:  handle of child button control
            
    ' LookUp Child Controls
    %IDC_LOOKUPEDIT1                            = 20
    %IDC_LOOKUPTEXTBTN1                         = 21
            
    '-------------------------------------------------------------------------------
    '
    ' PROCEDURE: RegisterLookUpClass32
    ' PURPOSE:   Registers the LookUp control class.
    '
    '-------------------------------------------------------------------------------
           
    FUNCTION RegisterLookUpClass32 () AS LONG
         
      LOCAL szClassName   AS ASCIIZ * %MAX_PATH   ' class name
      LOCAL twcx          AS WNDCLASSEX           ' class information
           
      ' Register the LookUp window
      szClassName        = "LookUpClass32"
      twcx.cbSize        = SIZEOF(twcx)                               ' size of WNDCLASSEX structure
      twcx.style         = %CS_DBLCLKS OR %CS_GLOBALCLASS             ' class styles
      twcx.lpfnWndProc   = CODEPTR(LookUpClass32_WndProc)             ' address of window procedure used by class
      twcx.cbClsExtra    = 0                                          ' extra class bytes
      twcx.cbWndExtra    = 0                                          ' extra window bytes
      twcx.hInstance     = GetModuleHandle(BYVAL %NULL)               ' instance of the EXE/DLL that is registering the window
      twcx.hIcon         = %NULL                                      ' handle of class icon
      twcx.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)        ' handle of class cursor
      twcx.hbrBackground = %COLOR_BTNFACE + 1                         ' brush used to fill background of window's client area
      twcx.lpszMenuName  = %NULL                                      ' resource identifier of the class menu
      twcx.lpszClassName = VARPTR(szClassName)                        ' class name
      twcx.hIconSm       = %NULL                                      ' handle of small icon shown in caption/system Taskbar
      RegisterClassEx twcx
                     
    END FUNCTION
            
    '----------------------------------------------------------------------
    '
    '   FUNCTION: UnRegisterLookUpClass32()
    '   PURPOSE:  Unregisters the LookUp control class.
    '   RETURNS:
    '
    '----------------------------------------------------------------------
                
    FUNCTION UnRegisterLookUpClass32() AS LONG
             
      UnregisterClass "LookUpClass32", GetModuleHandle(BYVAL %NULL)
           
    END FUNCTION
             
    '-------------------------------------------------------------------------------
    '
    ' PROCEDURE: LookUpClass32_WndProc
    ' PURPOSE:   Processes messages for the LookUp window.
    '
    '-------------------------------------------------------------------------------
               
    FUNCTION LookUpClass32_WndProc _
      ( _
      BYVAL hWnd    AS DWORD, _ ' window handle
      BYVAL uMsg    AS DWORD, _ ' type of message
      BYVAL wParam  AS DWORD, _ ' first message parameter
      BYVAL lParam  AS LONG _   ' second message parameter
      ) EXPORT AS LONG
            
      LOCAL szItem      AS ASCIIZ * %MAX_PATH
      LOCAL tsize       AS APISIZE
      LOCAL hInstance   AS DWORD
      LOCAL hWndChild   AS DWORD    ' handle of child window
      LOCAL dwID        AS DWORD
      LOCAL hFont       AS DWORD    ' handle of font used by parent
      LOCAL hDC         AS DWORD
      LOCAL dx          AS LONG
      LOCAL cxButton    AS LONG
             
      SELECT CASE uMsg
        CASE %WM_COMMAND
          ' We replace the ids and handles of the child controls with the id and handle
          ' of the container when passing notifications to the parent of our custom control.
          dwID = GetWindowLong(hWnd, %GWL_ID)
                   
          ' Pass the notifications from the children to the parent of our custom control
          SELECT CASE LOWRD(wParam)
            CASE %IDC_LOOKUPEDIT1
                    
              SELECT CASE HIWRD(wParam)
                CASE %EN_CHANGE
                  SendMessage GetParent(hWnd), uMsg, MAKDWD(dwID, %LUN_CHANGE), hWnd
                       
                CASE %EN_KILLFOCUS
                  SendMessage GetParent(hWnd), uMsg, MAKDWD(dwID, %LUN_KILLFOCUS), hWnd
                       
                CASE %EN_SETFOCUS
                  SendMessage GetParent(hWnd), uMsg, MAKDWD(dwID, %LUN_SETFOCUS), hWnd
                       
                CASE %EN_UPDATE
                  SendMessage GetParent(hWnd), uMsg, MAKDWD(dwID, %LUN_UPDATE), hWnd
              END SELECT
                     
            CASE %IDC_LOOKUPTEXTBTN1
                      
              SELECT CASE HIWRD(wParam)
                CASE %BN_CLICKED
                  ' Remove ugly border
                  SendMessage lParam, %BM_SETSTYLE, %BS_PUSHBUTTON, 0
                  SetFocus GetDlgItem(hWnd, %IDC_LOOKUPEDIT1)
                  SendMessage GetParent(hWnd), uMsg, MAKDWD(dwID, %LUN_CLICKED), hWnd
              END SELECT
                     
          END SELECT
                     
        CASE %WM_SETFOCUS
          ' Set the keyboard focus to the child edit control
          SetFocus GetDlgItem(hWnd, %IDC_LOOKUPEDIT1)
                     
        CASE %WM_SIZE
          ' Size the children of our custom control
          hDC = GetDC(%NULL)
          szItem = "..."
          GetTextExtentPoint32 hDC, szItem, LEN(szItem), tsize
          ReleaseDC %NULL, hDC
          dx = GetSystemMetrics(%SM_CXFIXEDFRAME)
          cxButton = dx + tsize.cx + dx
          hWndChild = GetDlgItem(hWnd, %IDC_LOOKUPTEXTBTN1)
          SetWindowPos hWndChild, %NULL, LOWRD(lParam) - cxButton, 0, cxButton, HIWRD(lParam), %SWP_NOZORDER OR %SWP_NOACTIVATE
          hWndChild = GetDlgItem(hWnd, %IDC_LOOKUPEDIT1)
          SetWindowPos hWndChild, %NULL, 0, 0, LOWRD(lParam) - cxButton - 1, HIWRD(lParam), %SWP_NOZORDER OR %SWP_NOACTIVATE
                  
        CASE %WM_SETFONT
          ' When our custom control receives this message we pass it on to its children
          SendMessage GetDlgItem(hWnd, %IDC_LOOKUPTEXTBTN1), uMsg, wParam, lParam
          FUNCTION = SendMessage(GetDlgItem(hWnd, %IDC_LOOKUPEDIT1), uMsg, wParam, lParam)
          EXIT FUNCTION
                 
        CASE %WM_GETFONT
          ' We are cheating here.  Our custom control does not assign memory to keep track
          ' of mundane things like font handles and text buffers.  The kids already do that.
          FUNCTION = SendMessage(GetDlgItem(hWnd, %IDC_LOOKUPEDIT1), uMsg, wParam, lParam)
          EXIT FUNCTION
                 
        CASE %WM_SETTEXT
          FUNCTION = SendMessage(GetDlgItem(hWnd, %IDC_LOOKUPEDIT1), uMsg, wParam, lParam)
          EXIT FUNCTION
                  
        CASE %WM_GETTEXT
          FUNCTION = SendMessage(GetDlgItem(hWnd, %IDC_LOOKUPEDIT1), uMsg, wParam, lParam)
          EXIT FUNCTION
                    
        CASE %LUM_SETLIMITTEXT
          FUNCTION = SendMessage(GetDlgItem(hWnd, %IDC_LOOKUPEDIT1), %EM_SETLIMITTEXT, wParam, lParam)
          EXIT FUNCTION
                     
        CASE %LUM_GETLIMITTEXT
          FUNCTION = SendMessage(GetDlgItem(hWnd, %IDC_LOOKUPEDIT1), %EM_GETLIMITTEXT, wParam, lParam)
          EXIT FUNCTION
                 
        CASE %LUM_GETEDITHANDLE
          FUNCTION = GetDlgItem(hWnd, %IDC_LOOKUPEDIT1)
          EXIT FUNCTION
                 
        CASE %LUM_GETBUTTONHANDLE
          FUNCTION = GetDlgItem(hWnd, %IDC_LOOKUPTEXTBTN1)
          EXIT FUNCTION
                  
        CASE %WM_CREATE
          hInstance = GetModuleHandle(BYVAL %NULL)
                   
          ' Create the LookUpEdit1 edit control
          hWndChild = CreateWindowEx(%NULL, _                                             ' extended styles
                                     "Edit", _                                            ' class name
                                     "", _                                                ' caption
                                     %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR _         ' window styles
                                     %ES_LEFT OR %ES_AUTOHSCROLL, _                       ' class styles
                                     0, 0, _                                              ' left, top
                                     166, 15, _                                           ' width, height
                                     hWnd, %IDC_LOOKUPEDIT1, _                            ' handle of parent, control ID
                                     hInstance, BYVAL %NULL)                              ' handle of instance, creation parameters
                                                
          ' Create the LookUpTextBtn1 text button
          hWndChild = CreateWindowEx(%NULL, _                                             ' extended styles
                                     "Button", _                                          ' class name
                                     "...", _                                             ' caption
                                     %WS_CHILD OR %WS_VISIBLE OR _                        ' window styles
                                     %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER, _       ' class styles
                                     167, 0, _                                            ' left, top
                                     15, 15, _                                            ' width, height
                                     hWnd, %IDC_LOOKUPTEXTBTN1, _                         ' handle of parent, control ID
                                     hInstance, BYVAL %NULL)                              ' handle of instance, creation parameters
                                
          FUNCTION = %FALSE
          EXIT FUNCTION
      END SELECT
               
      FUNCTION = DefWindowProc(hWnd, uMsg, wParam, lParam)
              
    END FUNCTION
    Added documentation for the notifications.
    Edited code to pass handle of custom control instead of handle of child control to parent.

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



    [This message has been edited by Dominic Mitchell (edited February 13, 2003).]
    Dominic Mitchell
    Phoenix Visual Designer
    http://www.phnxthunder.com

    Comment


    • #3
      All I can say is wow, what an incredible support forum. I've been
      alone all these years and had to dig through issues on my own.

      Dominic, thank you. You captured what I was trying to accomplish
      exactly, gave me a understandable explanation and a great working
      model of what I was trying to do.

      I believe I get it now. I do however reserve the right to ask
      more questions.


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

      Comment


      • #4
        In hopes of learning more about what I have read about the problem of intermixing DDT code and SDK style code, I offer the following DDT code, while keeping Dominic's INCLUDE file the same. If this is dangerous way to code, please explain why... I'm just tying to get a handle on custom controls (no pun intended)

        Code:
        #DIM ALL
        #REGISTER NONE
        #COMPILE EXE
        #OPTION VERSION4
        
        #INCLUDE "WIN32API.INC"
        #INCLUDE "LOOKUP.INC"
        
        '=========================== [ Control Identifiers ] ===========================
        ' Form2
        %IDD_FORM2                                  = 1000
        %IDC_FORM2_LOOKUP1                          = 1001
        %IDC_FORM2_TEXTBTN1                         = 1002
        
        '====================== [ Global Variable Declarations ] =======================
        GLOBAL  ghInstance    AS DWORD    ' handle of the application instance
        
        DECLARE CALLBACK FUNCTION Form2_WndProc()
        
        FUNCTION PBMAIN
           LOCAL hWnd AS LONG, style AS LONG
           LOCAL x AS LONG, y AS LONG, xx AS LONG, yy AS LONG
           style = %WS_SYSMENU OR %WS_MINIMIZEBOX
           DIALOG NEW 0, "Custom Control Demo", x, y, xx, yy, style TO hWnd
           x = 70: y = 94
           DIALOG PIXELS hWnd, x, y TO UNITS x, y
           xx = 360: yy = 178
           DIALOG PIXELS hWnd, xx, yy TO UNITS xx, yy
           DIALOG SET LOC hWnd, x, y
           DIALOG SET SIZE hWnd, xx, yy
           DIALOG SHOW MODAL hWnd, CALL Form2_WndProc
        END FUNCTION
        
        CALLBACK FUNCTION Form2_WndProc
          LOCAL hFont AS LONG, style AS LONG
          LOCAL x AS LONG, y AS LONG, xx AS LONG, yy AS LONG
          SELECT CASE CBMSG
            CASE %WM_INITDIALOG
              'register class
              RegisterLookUpClass32
              
              ' Create font used by container
              hFont = GetStockObject(%DEFAULT_GUI_FONT)
        
              ' Create the LookUp control
              style = %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP
              x = 16: y = 10: DIALOG PIXELS CBHNDL, x, y TO UNITS x, y
              xx = 212: yy = 22: DIALOG PIXELS CBHNDL, xx, yy TO UNITS xx, yy
              CONTROL ADD "LookUpClass32", CBHNDL, %IDC_FORM2_LOOKUP1, "", x, y, xx, yy, style
        
              'create OK button
              style = %WS_TABSTOP OR %BS_PUSHBUTTON OR %BS_CENTER OR %BS_VCENTER
              x = 145: y = 106: DIALOG PIXELS CBHNDL, x, y TO UNITS x, y
              xx = 63: yy = 23: DIALOG PIXELS CBHNDL, xx, yy TO UNITS xx, yy
              CONTROL ADD BUTTON, CBHNDL, %IDC_FORM2_TEXTBTN1, "OK", x, y, xx, yy, style
              FUNCTION = %FALSE
              EXIT FUNCTION
            CASE %WM_COMMAND
        
              SELECT CASE LOWRD(CBWPARAM)
                CASE %IDC_FORM2_LOOKUP1
        
                  SELECT CASE HIWRD(CBWPARAM)
                    CASE %LUN_CHANGE
        
                    CASE %LUN_UPDATE
        
                    CASE %LUN_CLICKED
                      MSGBOX "Input extra info"
                  END SELECT
        
                CASE %IDOK
                  IF HIWRD(CBWPARAM) = %BN_CLICKED THEN
                    PostMessage CBHNDL, %WM_CLOSE, 0, 0
                  END IF
              END SELECT
        
            CASE %WM_ACTIVATE
              ' Set the keyboard focus to the first control that is
              ' visible, not disabled, and has the WS_TABSTOP style
              IF LOWRD(CBWPARAM) = %WA_ACTIVE THEN
                SetFocus GetNextDlgTabItem(CBHNDL, %NULL, %FALSE)
              END IF
              FUNCTION = %FALSE
              EXIT FUNCTION
        
            CASE %WM_DESTROY
              PostQuitMessage 0
              FUNCTION = %FALSE
              EXIT FUNCTION
        
          END SELECT
        
        END FUNCTION
        ------------------


        [This message has been edited by Charles Dietz (edited February 12, 2003).]

        Comment


        • #5
          Good Question!! Charles,

          I've been much confused about DDT w/ SDK also... I hope you get some response...
          I'm also curious about how Modal vs. Modeless influences the sdk operations...

          Thank's
          Brad

          ------------------
          Wash DC Area
          mailto:[email protected][email protected]</A>

          Comment


          • #6
            A dialog procedure is a bit different from "SDK-style" Window procedure.
            For example, there is no DefWindowProc -call to consider at the end of it,
            so FUNCTION = 0 : EXIT FUNCTION is not needed here, because default is
            to leave dialog procedure with zero return.

            Also, in DDT engine you should use DIALOG END .. instead of sending a
            WM_CLOSE and use PostQuitMessage. LOWRD(CBWPARAM) is ok, but can also
            be lazy and use shorter CBCTL. And LOWRD(CBWPARAM) can be replaced
            with CBCTLMSG.

            BTW, Modal or Modeless dialog does not affect a SDK-style created control's
            behaviour. SDK-style custom control has its own window procedure where you
            have (almost) full control over it. But make sure to pass on messages to
            parent dialog.

            ------------------
            http://www.tolkenxp.com/pb
            Download: incLean, PBcodec, custom controls and code, etc.
            Borje Hagsten - [email protected]



            [This message has been edited by Borje Hagsten (edited February 12, 2003).]

            Comment


            • #7
              Thank's Borje

              also, I still don't really understand the difference between using
              DIALOG DO EVENTS, and GetMessage()...Lance mentioned that the DDT engine
              handles the keyboard accelerators for us, and GetMessage() doesn't..
              anything else?...also I've seen examples where there are many DIALOG DO EVENTS,
              why would we need more than one... I know I can figure this out myself..
              but if anyone has a good grasp on it???

              Thx, Brad

              ------------------
              Wash DC Area
              mailto:[email protected][email protected]</A>

              Comment


              • #8
                dialog doevents does not clear entire message que - that's why we sometimes use multiple
                ones. a solution that works fine for me is to use the following, when needed: (is very
                effective in wm_initdialog, for example, to make sure all is processed before dialog
                is shown - then redraw in slower machines looks better - quicker)
                Code:
                sub newevents
                  local msg as tagmsg
                  do while peekmessage(msg, 0, 0, 0, %pm_noremove) 'peek only, not remove
                     dialog doevents                               'let ddt handle all pending messages
                  loop
                end sub
                note: normally we don't have to use like the above doevents loop, but if many
                things is done on load, like many controls are initated, etc, it can help a lot.

                btw, a somewhat confusing discussion about this can be found in following thread:

                http://www.powerbasic.com/support/pb...ead.php?t=6989


                ------------------
                http://www.tolkenxp.com/pb
                download: inclean, pbcodec, custom controls and code, etc.
                borje hagsten - [email protected]



                [this message has been edited by borje hagsten (edited february 13, 2003).]

                Comment


                • #9
                  Thanks, Borje

                  I havn't a "queue" what that tread is about

                  Good Thread, I'll obviously study it again...

                  Brad

                  ------------------
                  Wash DC Area
                  mailto:[email protected][email protected]</A>

                  Comment


                  • #10
                    Glad you found it helpful.
                    Fixed an error in the code. Edited code to pass handle of custom control
                    instead of handle of child control to parent.

                    ------------------
                    Dominic Mitchell
                    Dominic Mitchell
                    Phoenix Visual Designer
                    http://www.phnxthunder.com

                    Comment


                    • #11
                      BTW, Modal or Modeless dialog does not affect a SDK-style created control's behaviour
                      Behavior of controls within the dialog proc, no, but they are created and ended differently....
                      Code:
                      MODAL   : DialogBox[Indirect][Param]   <==> EndDialog hWnd, RC
                      MODELESS: CreateDialog[Indirect][Param]<==> DestroyWindow hWnd
                      With DDT, modal/modeless are controlled by DIALOG SHOW, but the create (DIALOG NEW) and end (DIALOG END) functions are the same regardless; and DDT controls have default styles which SDK-created controls do not.

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

                      Comment


                      • #12
                        Just for fun, you can do the same thing <U>without</U> superclassing or subclassing or DLL's. You can do it in pure DDT with a couple of mods to syles of a child dialog that is the container, so you can put in a re-usable include. If needs be you can sub-class the TextBox in the include to trap keystrokes and the like. No mess, no fuss, no SDK. You can even modify the code so the "table" dialog is included in the include or a handle to that dialog is passed when the control is created so you can press the elipse button and get you pop-up. From your description it would be a very straight forward task to add a second dialog in the include that tracks with the control and pops up at the button press. You could even feed a file name or array handle to the "control" when it is called so you set a global there to use to "fill" the list in the pop-up.

                        You can also modify the include to pass handles or ID's of the Text box back to the main program dialog that is using it sos that the text is retrieved easily there, etc., etc. Not hard to standardize on a method and end up with 1 self-contained executable to distribute

                        So for just for fun here is the other way to do this. By setting the container background and some textbox styles, it looks like a single control. It is closed in the callback for the main dialog

                        It might not be to hard to pop the include in a DLL and distribute it if that were your goal.

                        Code:
                        #PBFORMS Created
                        '--------------------------------------------------------------------------------
                        ' The first line in this file is a PBForms metastatement.
                        ' It should ALWAYS be the first line of the file. Other
                        ' PBForms metastatements are placed at the beginning and
                        ' ending of blocks of code that should be edited using
                        ' PBForms only. Do not edit or delete these
                        ' metastatements or PBForms will not be able to reread
                        ' the file correctly. See the PBForms documentation for
                        ' more information.
                        ' Beginning blocks begin like this: #PBForms Begin ...
                        ' Ending blocks begin like this:    #PBForms End ...
                        ' Other PBForms metastatements such as:
                        '     #PBForms Declarations
                        ' are used to tell PBForms where to insert additional
                        ' code. Feel free to make changes anywhere else in the file.
                        '--------------------------------------------------------------------------------
                        
                        #COMPILE EXE
                        #DIM ALL
                        
                        '--------------------------------------------------------------------------------
                        '   ** Includes **
                        '--------------------------------------------------------------------------------
                        #PBFORMS Begin Includes
                        #IF NOT %DEF(%WINAPI)
                            #INCLUDE "WIN32API.INC"
                        #ENDIF
                        #INCLUDE "PBForms.INC"
                        #PBFORMS End Includes
                        '--------------------------------------------------------------------------------
                        
                        '--------------------------------------------------------------------------------
                        '   ** Constants **
                        '--------------------------------------------------------------------------------
                        #PBFORMS Begin Constants
                        %IDD_DIALOG1        = 101
                        #PBFORMS End Constants
                        '--------------------------------------------------------------------------------
                        'set an offset above the those made by PBFORMS or yourself
                        %MYOFFSET=5000
                        
                        ' include the file
                        #INCLUDE "TextBtnCtrl.inc"
                        
                        '--------------------------------------------------------------------------------
                        '   ** Declarations **
                        '--------------------------------------------------------------------------------
                        DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
                        DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                        #PBFORMS Declarations
                        '--------------------------------------------------------------------------------
                        'assign a global you will use for your composite control
                        'there are other ways to implement but this works well to illustrate
                        GLOBAL hMyTextButtonCtrl AS DWORD
                        '--------------------------------------------------------------------------------
                        FUNCTION PBMAIN()
                            ShowDIALOG1 %HWND_DESKTOP
                        END FUNCTION
                        
                        '--------------------------------------------------------------------------------
                        '   ** CallBacks **
                        '--------------------------------------------------------------------------------
                        CALLBACK FUNCTION ShowDIALOG1Proc()
                        
                            SELECT CASE CBMSG
                                CASE %WM_COMMAND
                                    SELECT CASE CBCTL
                        
                                    END SELECT
                                CASE %WM_DESTROY
                                    DIALOG END hMyTextButtonCtrl
                            END SELECT
                        
                        END FUNCTION
                        
                        '--------------------------------------------------------------------------------
                        '   ** Dialogs **
                        '--------------------------------------------------------------------------------
                        FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                            LOCAL lRslt AS LONG
                        #PBFORMS Begin Dialog %IDD_DIALOG1->->
                            LOCAL hDlg AS DWORD
                        
                            DIALOG NEW hParent, "TestControl",,, 200, 100, %WS_POPUP OR _
                                %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR _
                                %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_WINDOWEDGE OR _
                                %WS_EX_CONTROLPARENT OR %WS_EX_APPWINDOW OR %WS_EX_LEFT OR _
                                %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                        
                        #PBFORMS End Dialog
                            ShowTB_BTN_CTRL hDlg, 10, 10, hMyTextButtonCtrl
                            DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                        
                            FUNCTION = lRslt
                        END FUNCTION
                        '--------------------------------------------------------------------------------
                        the include file code ...
                        Code:
                        %IDD_TB_BTN_CTRL    = %MYOFFSET
                        %IDC_TEXTBOX1       = %MYOFFSET + 1
                        %IDC_BUTTON1        = %MYOFFSET + 2
                        
                        DECLARE CALLBACK FUNCTION ShowTB_BTN_CTRLProc()
                        DECLARE FUNCTION ShowTB_BTN_CTRL(BYVAL hParent AS DWORD,BYVAL x AS LONG, BYVAL y AS LONG, TBCtl AS DWORD) AS LONG
                        
                        '--------------------------------------------------------------------------------
                        CALLBACK FUNCTION ShowTB_BTN_CTRLProc()
                        
                            SELECT CASE CBMSG
                                CASE %WM_COMMAND
                                    SELECT CASE CBCTL
                                        CASE %IDC_TEXTBOX1
                                        CASE %IDC_BUTTON1
                                            IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                MSGBOX "Pop up the list dialog at this point", _
                                                       %MB_ICONINFORMATION OR %MB_OK, "Your code here ..."
                                            END IF
                        
                                    END SELECT
                            END SELECT
                        
                        END FUNCTION
                        '--------------------------------------------------------------------------------
                        FUNCTION ShowTB_BTN_CTRL(BYVAL hParent AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, TBCtl AS DWORD) AS LONG
                            LOCAL lRslt AS LONG
                            LOCAL hDlg AS DWORD
                            LOCAL hFont1 AS DWORD
                        
                            DIALOG NEW hParent, "TB_BTN_CTRL", x, y, 140, 80, %WS_CHILD OR %WS_BORDER OR _
                                %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_VISIBLE OR _
                                %DS_CONTROL OR %DS_NOFAILCREATE OR _
                                %DS_SETFONT, %WS_EX_WINDOWEDGE OR %WS_EX_CONTROLPARENT OR %WS_EX_LEFT _
                                OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                            DIALOG SET COLOR hDlg,%GRAY,%WHITE
                            CONTROL ADD TEXTBOX, hDlg, %IDC_TEXTBOX1, "TextBox1", 0, 0, 130, 80, _
                                        %ES_WANTRETURN OR %ES_MULTILINE
                            CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "...", 130, 0, 10, 15
                        
                            hFont1 = PBFormsMakeFont("MS Sans Serif", 12, 700, %FALSE, %FALSE, %FALSE, %ANSI_CHARSET)
                        
                            CONTROL SEND hDlg, %IDC_BUTTON1, %WM_SETFONT, hFont1, 0
                        
                            TBCtl = hDlg
                            DIALOG SHOW MODELESS hDlg, CALL ShowTB_BTN_CTRLProc TO lRslt
                        
                            DeleteObject hFont1
                        
                            FUNCTION = lRslt
                        END FUNCTION
                        '--------------------------------------------------------------------------------
                        Pop this into a couple of files and compile, make sure you keep the name of the include file the same or changed to what you would save this as.

                        ------------------
                        Rick Angell

                        [This message has been edited by Richard Angell (edited February 13, 2003).]
                        Rick Angell

                        Comment


                        • #13
                          Rick, you have some great ideas, thanks for your reply. I like
                          the idea of using standard dialogs in an include file. I, like
                          Charles in this thread, am using DDT. I'm also using PBForms.

                          I like the solution Dominic provided because I was trying to grasp
                          the concepts of containers and custom controls. Dominic's example
                          was very educational for me. I don't have to program with SDK to
                          appreciate the concepts.

                          With this include file as writen, using PBForms, I was able to
                          put one or multiple custom controls on my diolog of what ever
                          size I wanted, with whatever frame I wanted and trap the lookup
                          button or text input. This was exactly what I was looking for.
                          I'm a happy camper now.

                          Here is the example designed in PBForms.

                          Code:
                          #PBFORMS Created
                          #COMPILE EXE
                          #DIM ALL
                          
                          '--------------------------------------------------------------------------------
                          '   ** Includes **
                          '--------------------------------------------------------------------------------
                          #PBFORMS Begin Includes
                          #IF NOT %DEF(%WINAPI)
                              #INCLUDE "WIN32API.INC"
                          #ENDIF
                          #PBFORMS End Includes
                          #INCLUDE "Lookup.inc"
                          '--------------------------------------------------------------------------------
                          
                          '--------------------------------------------------------------------------------
                          '   ** Constants **
                          '--------------------------------------------------------------------------------
                          #PBFORMS Begin Constants
                          %IDD_DIALOG1        = 101
                          %IDC_BUTTON1        = 1002
                          %IDC_LookupClass1   = 1001
                          %IDC_LookupClass2   = 1003
                          #PBFORMS End Constants
                          '--------------------------------------------------------------------------------
                          
                          '--------------------------------------------------------------------------------
                          '   ** Declarations **
                          '--------------------------------------------------------------------------------
                          DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
                          DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                          #PBFORMS Declarations
                          '--------------------------------------------------------------------------------
                          
                          '--------------------------------------------------------------------------------
                          FUNCTION PBMAIN()
                              ShowDIALOG1 %HWND_DESKTOP
                          END FUNCTION
                          '--------------------------------------------------------------------------------
                          
                          '--------------------------------------------------------------------------------
                          '   ** CallBacks **
                          '--------------------------------------------------------------------------------
                          CALLBACK FUNCTION ShowDIALOG1Proc()
                          
                              SELECT CASE CBMSG
                                  CASE %WM_COMMAND
                                      SELECT CASE CBCTL
                                          CASE %IDC_LookupClass1
                                              SELECT CASE CBCTLMSG
                                                  CASE %LUN_CHANGE
                          
                                                  CASE %LUN_UPDATE
                          
                                                  CASE %LUN_CLICKED
                                                      MSGBOX "Input extra info 1"
                                              END SELECT
                          
                                          CASE %IDC_LookupClass2
                                              SELECT CASE CBCTLMSG
                                                  CASE %LUN_CHANGE
                          
                                                  CASE %LUN_UPDATE
                          
                                                  CASE %LUN_CLICKED
                                                      MSGBOX "Input extra info 2"
                                              END SELECT
                          
                                          CASE %IDC_BUTTON1
                                              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                                  DIALOG END CBHNDL
                                              END IF
                          
                                      END SELECT
                              END SELECT
                          
                          END FUNCTION
                          '--------------------------------------------------------------------------------
                          
                          '--------------------------------------------------------------------------------
                          '   ** Dialogs **
                          '--------------------------------------------------------------------------------
                          FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                              LOCAL lRslt AS LONG
                              registerLookupClass32
                          #PBFORMS Begin Dialog %IDD_DIALOG1->->
                              LOCAL hDlg AS DWORD
                          
                          
                              DIALOG NEW hParent, "Lookup pbform", 69, 74, 182, 111, %WS_POPUP OR _
                                  %WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR %WS_MINIMIZEBOX OR _
                                  %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR _
                                  %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_WINDOWEDGE OR _
                                  %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                  %WS_EX_RIGHTSCROLLBAR, TO hDlg
                              CONTROL ADD "LookupClass32", hDlg, %IDC_LookupClass1, "", 5, 5, 120, 15, _
                                  %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, %WS_EX_CLIENTEDGE OR _
                                  %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
                              CONTROL ADD "LookupClass32", hDlg, %IDC_LookupClass2, "", 5, 25, 170, 15, %WS_CHILD OR _
                                  %WS_VISIBLE OR %WS_TABSTOP, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                                  %WS_EX_RIGHTSCROLLBAR
                              CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Ok", 60, 70, 50, 15
                          
                          #PBFORMS End Dialog
                              CONTROL SEND hDlg, %IDC_LookupClass1, %LUM_SETLIMITTEXT, 20,0
                              CONTROL SEND hDlg, %IDC_LookupClass2, %LUM_SETLIMITTEXT, 30,0
                              DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                          
                              FUNCTION = lRslt
                          END FUNCTION
                          '--------------------------------------------------------------------------------
                          ------------------

                          Comment


                          • #14
                            Yes, for multiple instances you can certainly use the registered control. For "one of's" the 'for fun" DDT approach is sufficient. Using includes benefits keeping track of the deliverables ... only one to wory about It might be possible to modify the "for fun" include to do multiple instances, such as an array of controls, as well. It would likely involve a global variable, separate dialog handles and control ID offsets to be sorted out, not much more than that maybe. I did someting like this in an example for a different problem many moons ago ... but I'll just leave the thought about the possible on the table for now,

                            The key is that you sophisticate the CALLBACK to discern the calling instance of the control. and then launch the appropriate list dialog and you modify the Show function to assign unique idntifiers each time it is called. In your example, the button is the only active control needed to translate into an external action so that makes the task with the example fairly straight forward.

                            As you sort of noted all this was generated in a matter of a few minutes with PBFORMS. Cut and spliced and tried in a couple more. Glad you had some fun with it!

                            ------------------
                            Rick Angell
                            Rick Angell

                            Comment

                            Working...
                            X