Announcement

Collapse
No announcement yet.

Tab controls --Subclassing

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

  • Lance Edmonds
    replied
    Also, when using BeginPaint() and EndPaint(), is it necessary to DeleteObject for any pens created and ReleaseDC?
    Definitely! You should save the initial handle that is returned from the first SelectObject() call (the handle to the "existing" object), and restore it before terminating your %WM_PAINT handler.
    Also, you cannot delete any object that is still selected into a Device Context - the following psuedocode example demonstrates how to correctly handle the dynamic creation and destruction of GDI objects:
    Code:
    'psuedocode
    CASE %WM_PAINT
      hDC = BeginPaint(...)
      hBrush = CreateBrushIndirect(...)
      hBrushOld = SelectObject(hDC, hBrush)
      ...drawing code
      DeleteOnject SelectObject(hDC, hBrushOld)
      EndPaint <params>
    When creating new graphs/displays for the other tab pages, would you recommend setting up seperate subclass functions to handle this via:
    Subclassing it not usually required at all for this type of task... just a callback for the modeless dialog should be sufficient - it is all I've ever needed to do.

    I'm not at my DEV PC to run your code, but a quick look reveals that your code does not have a message pump for the child dialogs, so the events for these dialogs are never dispatched.

    The correct way to handle this would work like this:
    1. Create the parent dialog, and the tab control as a child control to that dialog. The dialog should have the extended %WS_EX_CONTROLPARENT style.
    2. Create the child (modeless) dialogs as children of the main dialog, NOT the tab control. These dialogs should have the %DS_CONTROL style.
    3. Use a DIALOG SHOW MODELESS statement for each of the child dialogs, and then hide each one with DIALOG SET STATE (or is it DIALOG SHOW STATE, I forget)
    4. Use DIALOG SHOW MODAL to launch the main dialog.
    5. In the dialog handler for the main dialog, process %WM_INITDIALOG and use PostMessage CBHNDL,%WM_USER + 999,0,0 to post a user-defined message to itself.
    6. Process %WM_USER + 999& and execute a DIALOG DOEVENTS message loop which should run until the child modeless dialogs are all destroyed. This means that this event handler should run all the time, but the callback will still be able to process other messages normally.

    The message pump for the modeless dialogs should look something like this:
    Code:
    SELECT CASE CBMSG
    CASE %WM_INTIDIALOG
      ... general init code goes here.
      PostMessage CHNDL, %WM_USER+999, 0, 0
      EXIT FUNCTION
    CASE %WM_USER + 999
      DO
        DIALOG DOEVENTS to nModelessCount& ' (check the syntax here... this is off the top of my head!)
      LOOP UNTIL nModelessCount& = 0
      EXIT FUNCTION
    The reason for using the custom message to kick the message pump off ensures that the pump's operation does not affect the operation of normal messages that the callback can process.
    I hope this helps. Tab controls are a challenge, but forgetting the message pump for modeless dialogs is a common mistake.

    There is another approach to this whole tab control application - simply use modeless dialogs for everything, and place the message pump in the main (PBMAIN) code.

    if this is a better choice for you, then the process would work like this:
    1. Create the parent dialog, and the tab control as a child control to that dialog. The dialog should have the extended %WS_EX_CONTROLPARENT style.
    2. Create the child (modeless) dialogs as children of the main dialog, NOT the tab control. These dialogs should have the %DS_CONTROL style.
    3. Use a DIALOG SHOW MODELESS statement for each of the child dialogs, and then hide each one with DIALOG SET STATE (or is it DIALOG SHOW STATE, I forget)
    4. Use DIALOG SHOW MODELESS to launch the main dialog.
    5. start the message pump right here in PBMAIN.
    Code:
    'psuedocode
    FUNCTION PBMAIN()
      DIALOG NEW 0,..., to hDlg
      CONTROL ADD "thetabcontrolclassname",..., to hTab
      DIALOG NEW hDlg,..., to hTabPage1
      DIALOG NEW hDlg,..., to hTabPage2
      DIALOG NEW hDlg,..., to hTabPage3
      DIALOG SHOW MODELESS hTabPage1 CALL ChildTabCallback1
      DIALOG SHOW MODELESS hTabPage2 CALL ChildTabCallback2
      DIALOG SHOW MODELESS hTabPage3 CALL ChildTabCallback3
      DIALOG SHOW MODELESS hDlg CALL ParentCallback
      DO
        DIALOG DOEVENTS To nModelessCOunt&
      LOOP UNTIL nModelessCount& = 0
    END FUNCTION
    That lot should keep you going for a while!


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

    Leave a comment:


  • Todd Wasson
    replied
    Lance, thank you for the tips on handling drawing via %WM_PAINT, InvalidateRect() and UpdateWindow(). This version works as planned.
    Code:
    #COMPILE EXE
    #INCLUDE "commctrl.inc"
    #INCLUDE "TabDDT.inc"
    %IDC_TAB  = 1000
    %IDLABEL1 = 1
    
        GLOBAL hDlg AS LONG
        GLOBAL hTab AS LONG
        GLOBAL hTabDlg1 AS LONG
        GLOBAL hTabDlg2 AS LONG
        GLOBAL hTabDlg3 AS LONG
        GLOBAL point AS POINTAPI
        GLOBAL last_point AS POINTAPI
        GLOBAL hpen AS LONG
        GLOBAL hDc AS LONG
        GLOBAL DefaultTabProc AS LONG
    
    DECLARE CALLBACK FUNCTION MainDlgProc
    DECLARE FUNCTION TabSubClassProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    
    FUNCTION PBMAIN
        LOCAL th AS TABHDR
        LOCAL TEXT AS STRING
    
        ' Main dialog
        DIALOG NEW 0, "DDT - Tab Example",,,400, 300, %WS_SYSMENU OR %WS_MINIMIZEBOX OR %DS_CENTER TO hDlg
    CONTROL ADD LABEL, hDlg,%IDLABEL1,"-------- ",5,5,60,12,0
    
        ' Tab control
        hTab = TabCtrl(hDlg, %IDC_TAB, 20, 20, 300, 250)
        ' Tab - dialog 1
        DIALOG NEW hTab, "Tab 1",,,400, 300, %WS_CHILD OR %WS_VISIBLE  TO hTabDlg1
        ' Tab - dialog 2
        DIALOG NEW hTab, "Tab 2",,,400, 300, %WS_CHILD OR %WS_VISIBLE TO hTabDlg2
        CONTROL ADD LABEL, hTabDlg2, -1, "This is Tab 2", 5,5,50,14
        ' Tab - dialog 3
        DIALOG NEW hTab, "Tab 3",,,400,300, %WS_CHILD OR %WS_VISIBLE TO hTabDlg3
        CONTROL ADD BUTTON, hTabDlg3, 100, "A button",50,50, 90,90
        th.lID = %IDC_TAB
        th.cDialogs = 3
    
        th.DlgHdr(0).hTabDlg       = hTabDlg1
        th.DlgHdr(0).lpfnCallback  = CODEPTR(cbTab1)
    
        th.DlgHdr(1).hTabDlg       = hTabDlg2
        th.DlgHdr(1).lpfnCallback  = CODEPTR(cbTab2)
    
        th.DlgHdr(2).hTabDlg       = hTabDlg3
        th.DlgHdr(2).lpfnCallback  = CODEPTR(cbTab3)
    
        InitTabControl hDlg, th
    
        DIALOG SHOW MODAL hDlg CALL MainDlgProc
    
    END FUNCTION
    
    CALLBACK FUNCTION MainDlgProc
        
        SELECT CASE CBMSG
            CASE %WM_INITDIALOG
            DefaultTabProc = SetWindowLong(hTabDlg2, %GWL_WNDPROC, CODEPTR(TabSubClassProc))
    
            CASE %WM_NOTIFY
                OnTabNotify CBHNDL, CBLPARAM
          END SELECT
    
    END FUNCTION
    
    CALLBACK FUNCTION cbTab1
        SELECT CASE CBMSG
            CASE %WM_INITDIALOG
            CASE %WM_COMMAND
                SELECT CASE LOWRD(CBWPARAM)
               END SELECT
      END SELECT
    
    END FUNCTION
    
    
    CALLBACK FUNCTION cbTab2
      SELECT CASE CBMSG
             CASE %WM_INITDIALOG
             CASE %WM_COMMAND
                  SELECT CASE LOWRD(CBWPARAM)
                  END SELECT
      END SELECT
    
    END FUNCTION
    
    CALLBACK FUNCTION cbTab3
      SELECT CASE CBMSG
             CASE %WM_INITDIALOG
             CASE %WM_COMMAND
                  SELECT CASE LOWRD(CBWPARAM)
                  END SELECT
      END SELECT
    
    END FUNCTION
    
    
    FUNCTION TabSubClassProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
        BYVAL wParam AS LONG, BYVAL lParam AS LONG) EXPORT AS LONG
             LOCAL  ps     AS PAINTSTRUCT
            IF wMsg= %WM_SHOWWINDOW THEN
               BEEP
            Last_Point.x=-1
            Last_Point.y=-1
            END IF
            IF wMsg= %WM_PAINT THEN
            hdc = BeginPaint(hWnd, ps)
            hpen = CreatePen (%PS_SOLID,1,RGB(255,255,255))
            SelectObject hDC,hpen
            SetROP2 hDC, %R2_COPYPEN
            ''Draw graph here
            MoveTo hDC, 20,200
            LineTo hDC, 200,300
            MoveTo hDC, 300,50
            LineTo hDC, 50,50
            ''Draw vertical scrolling line here
            SetROP2 hDC, %R2_XORPEN
            MoveTo hDC, LAST_POINT.X,0
            LineTo hDC, LAST_POINT.X,350
            MoveTo hDC, POINT.X,0
            LineTo hDC, POINT.X,350
    
            DeleteObject hpen
            EndPaint hWnd, ps
            Last_Point=Point
            END IF
    
          IF wMsg= %WM_MOUSEMOVE THEN
            Point.X = LOWRD(lParam)
    '        Point.Y = HIWRD(lParam)
            InvalidateRect hWnd, BYVAL 0, %FALSE
            UpdateWindow hWnd
            TEXT$="X: "+STR$(POINT.X)+"  Y: "+STR$(POINT.Y)
            CONTROL SET TEXT hdlg,%IDLABEL1, TEXT$
             ELSE
              FUNCTION = CallWindowProc(DefaultTabProc, hWnd, wMSg, WParam, Lparam)
    END IF
    END FUNCTION
    Code:
    '------- TabDDT.inc ---------------
    '----------------------------------
    ' DDT Tab Control
    ' Peter Stephensen 2000
    '----------------------------------
    %TRUE=1
    #IF NOT %DEF(%TAB_DLGMAX)
        %TAB_DLGMAX = 10                ' Maximal number of tab items
    #ENDIF
    
    #IF NOT %DEF(%TAB_LINES)
        %TAB_LINES = 2                  ' Number of lines in Tab control. Set this to 2
    #ENDIF                              ' if multiline-style is used
    
    TYPE DLGHDR
        hTabDlg AS LONG
        lpfnCallback AS LONG
    END TYPE
    
    TYPE TABHDR
        lID AS LONG                     ' Integer ID for Tab Control
        cDialogs AS LONG                ' Number of dialogs
        DlgHdr(%TAB_DLGMAX) AS DLGHDR   ' Dialogs
    END TYPE
    
    DECLARE SUB TabDisplay(hDlg AS LONG,TabID AS LONG,newTab AS LONG)
    
    GLOBAL pth AS TABHDR PTR
    
    FUNCTION TabCtrl(BYVAL hDlg AS LONG, BYVAL ID AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL xx AS LONG, BYVAL yy AS LONG) AS LONG
    
        LOCAL hTab AS LONG
    
        IF hDlg = 0 THEN EXIT FUNCTION
        CONTROL ADD "SysTabControl32", hDlg, ID, "", x, y, xx, yy, %WS_CHILD OR %WS_VISIBLE
        CONTROL HANDLE hDlg, ID TO hTab
    
        FUNCTION = hTab
    
    END FUNCTION
    
    FUNCTION InitTabControl(hDlg AS LONG, th AS TABHDR) AS LONG
    
        LOCAL tie AS TC_ITEM
        LOCAL rcTab AS RECT
        LOCAL i AS LONG
        LOCAL hInst AS LONG
        LOCAL hWndTab AS LONG
        LOCAL zBuffer AS ASCIIZ*128
    
        InitCommonControls
    
        pth = LocalAlloc(%LPTR, SIZEOF(@pth))
    
        hInst = GetModuleHandle(BYVAL 0)
        hWndTab = GetDlgItem(hDlg,th.lID)
    
        GetClientRect hwndTab,rcTab
    
        ' Add a tab for each of the child dialog boxes.
        FOR i = 0 TO th.cDialogs-1
            tie.mask = %TCIF_TEXT OR %TCIF_IMAGE
            tie.iImage = -1
            GetWindowText th.DlgHdr(i).hTabDlg, zBuffer, 128
            tie.pszText = VARPTR(zBuffer)
            TabCtrl_InsertItem hwndTab, i, tie
    
            MoveWindow th.DlgHdr(i).hTabDlg, _
                       4, _
                       %TAB_LINES*23, _
                       rcTab.nRight-rcTab.nLeft-11, _
                       rcTab.nBottom-rcTab.nTop-%TAB_LINES*23-3, _
                       %TRUE
        NEXT i
    
        @pth = th
        TabDisplay hDlg, th.lID, 0
    
    END FUNCTION
    
    SUB TabDisplay(hDlg AS LONG,TabID AS LONG, TabIndex AS LONG)
    
        STATIC PrevTabIndex AS LONG
        LOCAL i AS LONG
    
        IF PrevTabIndex THEN
            ShowWindow PrevTabIndex, %SW_HIDE
        END IF
    
        IF pth = 0 THEN EXIT SUB
    
        ShowWindow @pth.DlgHdr(TabIndex).hTabDlg, %SW_SHOW
        PrevTabIndex = @pth.DlgHdr(TabIndex).hTabDlg
    
    END SUB
    
    SUB OnTabNotify (BYVAL hDlg AS LONG, BYVAL lParam AS LONG )
    
        LOCAL lpNmh   AS NMHDR PTR
    
        IF pth = 0 THEN EXIT SUB
    
        lpNmh = lParam
        SELECT CASE @lpNmh.Code
        CASE %TCN_LAST TO %TCN_FIRST
            SELECT CASE @lpNmh.idFrom
            CASE @pth.lID
                SELECT CASE @lpNmh.Code
                CASE %TCN_SELCHANGE
                    TabDisplay hDlg, @pth.lID, TabCtrl_GetCurSel(GetDlgItem(hDlg,@pth.lID))
                END SELECT
            END SELECT
        END SELECT
    
    END SUB
    Do you see a problem with TabDDT.Inc (courtesy of Peter Stephensen 2000, thank you Peter) that causes the cbtab(1,2,3) functions not to work?
    Also, when using BeginPaint() and EndPaint(), is it necessary to DeleteObject for any pens created and ReleaseDC?
    When creating new graphs/displays for the other tab pages,
    would you recommend setting up seperate subclass functions to handle this via:
    Code:
     
    DefaultTabProc1 = SetWindowLong(hTabDlg1, %GWL_WNDPROC, CODEPTR(TabSubClassProc1))
    DefaultTabProc2 = SetWindowLong(hTabDlg2, %GWL_WNDPROC, CODEPTR(TabSubClassProc2))
    DefaultTabProc3 = SetWindowLong(hTabDlg3, %GWL_WNDPROC, CODEPTR(TabSubClassProc3))
    Or is there a better way?

    Semen, I like your code format better and will probably switch. It would be better for me to learn how tab controls work rather than rely on an Inc file. Will keep and study your example.

    Thank you, Lance and Semen,
    Todd Wasson





    [This message has been edited by Todd Wasson (edited May 28, 2000).]

    Leave a comment:


  • Semen Matusovski
    replied
    Todd --
    probably, you will understand, how to organize callback functions from my training code (based on sample from http://www.powerbasic.com/files/pub/pbwin/ )
    Code:
       #Compile Exe
       #Register None
       #Dim All
       #Include "commctrl.inc"
    
       %ID_TAB = 1001
       
       CallBack Function TabProc1
          Select Case CbMsg
             Case %WM_INITDIALOG
                Control Add TextBox, CbHndl, -1, "Tab 1", 0, 0, 255, 140, , %WS_EX_CLIENTEDGE
          End Select
       End Function
       CallBack Function TabProc2
          Select Case CbMsg
             Case %WM_INITDIALOG
                Control Add TextBox, CbHndl, -1, "Tab 2", 0, 0, 255, 140, , %WS_EX_CLIENTEDGE
          End Select
       End Function
       CallBack Function TabProc3
          Select Case CbMsg
             Case %WM_INITDIALOG
                Control Add Button, CbHndl, -1, "Tab 3", 0, 0, 255, 140
          End Select
       End Function
    
       CallBack Function MainDlgProc
          Static LastIdx As Long, hWndTab() As Long
          Local tie As TC_ITEM, i As Long, Caption As String
          %nTabCh = 3
          Select Case CbMsg
             Case %WM_INITDIALOG
                ReDim hWndTab(1 To %nTabCh)
                For i = 1 To %nTabCh
                   Dialog New CbHndl, "", 20, 35, 255, 140, %DS_CONTROL Or %WS_CHILD To hWndTab(i)
                   Select Case i
                      Case 1
                         Dialog Show Modeless hWndTab(i) Call TabProc1: Caption = " One "
                      Case 2
                         Dialog Show Modeless hWndTab(i) Call TabProc2: Caption = " Two "
                      Case 3
                         Dialog Show Modeless hWndTab(i) Call TabProc3: Caption = " Three "
                   End Select
                   If i = 1 Then ShowWindow hWndTab(i), %SW_SHOW Else _
                      ShowWindow hWndTab(i), %SW_HIDE
                   tie.mask = %TCIF_TEXT Or %TCIF_IMAGE
                   tie.iImage = -1
                   tie.pszText = StrPtr(Caption)
                   TabCtrl_InsertItem GetDlgItem(CbHndl, %ID_TAB), i, tie
                Next
                SetFocus GetDlgItem(CbHndl, %ID_TAB)
             Case %WM_NOTIFY
                Local lpNmh As NMHDR Ptr
                lpNmh = CbLparam
                Select Case @lpNmh.Code
                   Case %TCN_LAST To %TCN_FIRST
                      Select Case @lpNmh.idFrom
                         Case %ID_TAB
                           Select Case @lpNmh.Code
                              Case %TCN_SELCHANGE
                                 i = TabCtrl_GetCurSel(GetDlgItem(CbHndl,%ID_TAB))
                                 ShowWindow hWndTab(LastIdx + 1), %SW_HIDE
                                 LastIdx = i: ShowWindow hWndTab(LastIdx + 1), %SW_SHOW
                           End Select
                   End Select
                End Select
          End Select
       End Function
    
       Function PbMain
          Local hDlg As Long
          InitCommonControls
          Dialog New 0, "DDT - Tab Example",,, 300, 200, _
             %WS_MINIMIZEBOX Or %WS_CAPTION Or %WS_SYSMENU, %WS_EX_CONTROLPARENT To hDlg
          Control Add "SysTabControl32", hDlg, %ID_TAB, "", 10, 10, 280, 180, %WS_CHILD Or %WS_VISIBLE
          Dialog Show Modal hDlg Call MainDlgProc
       End Function

    Leave a comment:


  • Lance Edmonds
    replied
    Todd, I can't run your code because the TABDDT.INC file is missing. However, some general comments shpould help you here anyway:

    1. The parent of the tab control (the dialog) should have the style %WS_EX_CONTROLPARENT, and the individual tab pages (modeless dialogs) should have the style %DS_CONTROL. These "page dialogs" should be started with DIALOG SHOW MODELESS, and your app should provide a message pump that runs for the duration of the modeless dialogs.

    2. Drawing on dialogs (or controls) should only occur during %WM_PAINT. Therefore, your code should only be calculating drawing positions duing %WM_MOUSEMOVE, but then call InvalidateRect() followed by UpdateWindow() which causes a %WM_PAINT even to occur. Then, using the these calculated positions, your %WM_PAINT handler does the drawing. This ensures that your "lines" are repainted correctly if the dialog needs to be repainted because of any reason other than the forced repaint your code is issuing.

    3. The tab callback issues are probably caused by whatever is in TABDDT.INC. I suspect part of the problem relates to #1 and #4.

    4. The child modeless dialogs that form the tab pages should be children of the DIALOG that contains the tab control, NOT the tab control itself! This is opposite to how VB does things, but it is the correct way to do it with DDT and/or SDK-style applications.


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

    Leave a comment:


  • Todd Wasson
    started a topic Tab controls --Subclassing

    Tab controls --Subclassing

    These tab controls work basically ok. Tab number 2 is subclassed so %WM_MOUSEMOVE events can be used to draw a vertical line that moves through the tab page with the mouse.

    Code:
    #COMPILE EXE
    #INCLUDE "commctrl.inc"
    #INCLUDE "TabDDT.inc"
    %IDC_TAB  = 1000
    %IDLABEL1 = 1
    
        GLOBAL hDlg AS LONG
        GLOBAL hTab AS LONG
        GLOBAL hTabDlg1 AS LONG
        GLOBAL hTabDlg2 AS LONG
        GLOBAL hTabDlg3 AS LONG
        GLOBAL point AS POINTAPI
        GLOBAL last_point AS POINTAPI
        GLOBAL hpen AS LONG
        GLOBAL hDc AS LONG
        GLOBAL DefaultTabProc AS LONG
        
    DECLARE CALLBACK FUNCTION MainDlgProc
    DECLARE FUNCTION TabSubClassProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    
    FUNCTION PBMAIN
        LOCAL th AS TABHDR
        LOCAL TEXT AS STRING
    
        ' Main dialog
        DIALOG NEW 0, "DDT - Tab Example",,,400, 300, %WS_SYSMENU OR %WS_MINIMIZEBOX OR %DS_CENTER TO hDlg
    CONTROL ADD LABEL, hDlg,%IDLABEL1,"-------- ",5,5,60,12,0
    
        ' Tab control
        hTab = TabCtrl(hDlg, %IDC_TAB, 20, 20, 300, 250)
        ' Tab - dialog 1
        DIALOG NEW hTab, "Tab nr. 1",,,400, 300, %WS_CHILD OR %WS_VISIBLE  TO hTabDlg1
        ' Tab - dialog 2
        DIALOG NEW hTab, "Tab nr. 2",,,400, 300, %WS_CHILD OR %WS_VISIBLE TO hTabDlg2
        CONTROL ADD LABEL, hTabDlg2, -1, "This is Tab 2", 5,5,50,14
        ' Tab - dialog 3
        DIALOG NEW hTab, "Super tab number 3",,,400,300, %WS_CHILD OR %WS_VISIBLE TO hTabDlg3
        CONTROL ADD BUTTON, hTabDlg3, 100, "A button",50,50, 90,90
        th.lID = %IDC_TAB
        th.cDialogs = 3
    
        th.DlgHdr(0).hTabDlg       = hTabDlg1
        th.DlgHdr(0).lpfnCallback  = CODEPTR(cbTab1)
    
        th.DlgHdr(1).hTabDlg       = hTabDlg2
        th.DlgHdr(1).lpfnCallback  = CODEPTR(cbTab2)
    
        th.DlgHdr(2).hTabDlg       = hTabDlg3
        th.DlgHdr(2).lpfnCallback  = CODEPTR(cbTab3)
    
        InitTabControl hDlg, th
    
        DIALOG SHOW MODAL hDlg CALL MainDlgProc
    
    END FUNCTION
    
    CALLBACK FUNCTION MainDlgProc
        SELECT CASE CBMSG
            CASE %WM_INITDIALOG
            DefaultTabProc = SetWindowLong(hTabDlg2, %GWL_WNDPROC, CODEPTR(TabSubClassProc))
    
            CASE %WM_NOTIFY
                OnTabNotify CBHNDL, CBLPARAM
                 
    '        CASE %WM_COMMAND
    '             SELECT CASE LOWRD(CBWPARAM)
    '            END SELECT
      END SELECT
    
    END FUNCTION
    
    CALLBACK FUNCTION cbTab1
        SELECT CASE CBMSG
            CASE %WM_INITDIALOG
            CASE %WM_COMMAND
                SELECT CASE LOWRD(CBWPARAM)
               END SELECT
      END SELECT
    
    END FUNCTION
    
    
    CALLBACK FUNCTION cbTab2
      SELECT CASE CBMSG
             CASE %WM_INITDIALOG
             CASE %WM_COMMAND
                  SELECT CASE LOWRD(CBWPARAM)
                  END SELECT
      END SELECT
    
    END FUNCTION
    
    CALLBACK FUNCTION cbTab3
      SELECT CASE CBMSG
             CASE %WM_INITDIALOG
             CASE %WM_COMMAND
                  SELECT CASE LOWRD(CBWPARAM)
                  END SELECT
      END SELECT
    
    END FUNCTION
    
    
    FUNCTION TabSubClassProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
        BYVAL wParam AS LONG, BYVAL lParam AS LONG) EXPORT AS LONG
    
           IF wMsg= %WM_SHOWWINDOW THEN
           Point.x=0
           Point.y=0
           ''Draw a couple lines
            hDC = GetDC(hTabDlg2)
            hpen = CreatePen (%PS_SOLID,2,RGB(255,255,255))
            SelectObject hDC,hpen
            SetROP2 hDC, %R2_COPYPEN
            MoveTo hDC, 100,200
            LineTo hDC, 200,300
            MoveTo hDC, 300,50
            LineTo hDC, 50,50
            ReleaseDC hTabDlg2, hDc
            DeleteObject hpen
            END IF
    
          IF wMsg= %WM_MOUSEMOVE THEN
            Last_Point=Point
            GetCursorPos Point
            TEXT$="X: "+STR$(POINT.X)+"  Y: "+STR$(POINT.Y)
            CONTROL SET TEXT hdlg,%IDLABEL1, TEXT$
            hDC = GetDC(hTabDlg2)
            hpen = CreatePen (%PS_SOLID,2,RGB(255,255,255))
            SelectObject hDC,hpen
            SetROP2 hDC, %R2_XORPEN
            MoveTo hDC, LAST_POINT.X-137,0
            LineTo hDC, LAST_POINT.X-137,350
            MoveTo hDC, POINT.X-137,0
            LineTo hDC, POINT.X-137,350
            ReleaseDC hTabDlg2, hDc
            DeleteObject hpen
             ELSE
              FUNCTION = CallWindowProc(DefaultTabProc, hWnd, wMSg, WParam, Lparam)
    END IF
    END FUNCTION
    
    '------- TabDDT.inc ---------------
    '----------------------------------
    ' DDT Tab Control
    ' Peter Stephensen 2000
    '----------------------------------
    %TRUE=1
    #IF NOT %DEF(%TAB_DLGMAX)
        %TAB_DLGMAX = 10                ' Maximal number of tab items
    #ENDIF
    
    #IF NOT %DEF(%TAB_LINES)
        %TAB_LINES = 2                  ' Number of lines in Tab control. Set this to 2
    #ENDIF                              ' if multiline-style is used
    
    TYPE DLGHDR
        hTabDlg AS LONG
        lpfnCallback AS LONG
    END TYPE
    
    TYPE TABHDR
        lID AS LONG                     ' Integer ID for Tab Control
        cDialogs AS LONG                ' Number of dialogs
        DlgHdr(%TAB_DLGMAX) AS DLGHDR   ' Dialogs
    END TYPE
    
    DECLARE SUB TabDisplay(hDlg AS LONG,TabID AS LONG,newTab AS LONG)
    
    GLOBAL pth AS TABHDR PTR
    
    FUNCTION TabCtrl(BYVAL hDlg AS LONG, BYVAL ID AS LONG, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL xx AS LONG, BYVAL yy AS LONG) AS LONG
    
        LOCAL hTab AS LONG
    
        IF hDlg = 0 THEN EXIT FUNCTION
        CONTROL ADD "SysTabControl32", hDlg, ID, "", x, y, xx, yy, %WS_CHILD OR %WS_VISIBLE
        CONTROL HANDLE hDlg, ID TO hTab
    
        FUNCTION = hTab
    
    END FUNCTION
    
    FUNCTION InitTabControl(hDlg AS LONG, th AS TABHDR) AS LONG
    
        LOCAL tie AS TC_ITEM
        LOCAL rcTab AS RECT
        LOCAL i AS LONG
        LOCAL hInst AS LONG
        LOCAL hWndTab AS LONG
        LOCAL zBuffer AS ASCIIZ*128
    
        InitCommonControls
    
        pth = LocalAlloc(%LPTR, SIZEOF(@pth))
    
        hInst = GetModuleHandle(BYVAL 0)
        hWndTab = GetDlgItem(hDlg,th.lID)
    
        GetClientRect hwndTab,rcTab
    
        ' Add a tab for each of the child dialog boxes.
        FOR i = 0 TO th.cDialogs-1
            tie.mask = %TCIF_TEXT OR %TCIF_IMAGE
            tie.iImage = -1
            GetWindowText th.DlgHdr(i).hTabDlg, zBuffer, 128
            tie.pszText = VARPTR(zBuffer)
            TabCtrl_InsertItem hwndTab, i, tie
    
            MoveWindow th.DlgHdr(i).hTabDlg, _
                       4, _
                       %TAB_LINES*23, _
                       rcTab.nRight-rcTab.nLeft-11, _
                       rcTab.nBottom-rcTab.nTop-%TAB_LINES*23-3, _
                       %TRUE
        NEXT i
    
        @pth = th
        TabDisplay hDlg, th.lID, 0
    
    END FUNCTION
    
    SUB TabDisplay(hDlg AS LONG,TabID AS LONG, TabIndex AS LONG)
    
        STATIC PrevTabIndex AS LONG
        LOCAL i AS LONG
    
        IF PrevTabIndex THEN
            ShowWindow PrevTabIndex, %SW_HIDE
        END IF
    
        IF pth = 0 THEN EXIT SUB
    
        ShowWindow @pth.DlgHdr(TabIndex).hTabDlg, %SW_SHOW
        PrevTabIndex = @pth.DlgHdr(TabIndex).hTabDlg
    
    END SUB
    
    SUB OnTabNotify (BYVAL hDlg AS LONG, BYVAL lParam AS LONG )
    
        LOCAL lpNmh   AS NMHDR PTR
    
        IF pth = 0 THEN EXIT SUB
    
        lpNmh = lParam
        SELECT CASE @lpNmh.Code
        CASE %TCN_LAST TO %TCN_FIRST
            SELECT CASE @lpNmh.idFrom
            CASE @pth.lID
                SELECT CASE @lpNmh.Code
                CASE %TCN_SELCHANGE
                    TabDisplay hDlg, @pth.lID, TabCtrl_GetCurSel(GetDlgItem(hDlg,@pth.lID))
                END SELECT
            END SELECT
        END SELECT
    
    END SUB
    The problem I'm having is trying to get the "draw a couple lines" graphics in TabSubClassProc() to appear when tab 2 is initially selected. When selecting a different tab, the graphics flash and disappear. I'm sure the %WM_SHOWWINDOW is not appropriate to use here. The graphics are being drawn probably, but the tab control is just being drawn over them immediately after. Is there a message sent when the tab control is finished drawing itself that I can use to trigger my "draw a couple lines" section? Or am I taking care of this in the wrong place?
    Thanks,
    Todd Wasson

    P.S. Oh yes, one more thing! How can I get the tab callback functions (cbTab1,cbTab2,cbTab3) to work? Once they work, can they be used to "draw a couple lines"? Tab 2 should eventually show a graph that gets drawn when it is selected, then the mouse should control a vertical line that scrolls over it.

    ::TabDDT.INC now included here, thanks to Peter Stephenson.



    [This message has been edited by Todd Wasson (edited May 28, 2000).]
Working...
X