PlanetSquires Forums

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 2 [3]

Author Topic: CWindow RC10  (Read 9560 times)

Paul Squires

  • Administrator
  • Guru Member
  • *****
  • Posts: 9313
  • Windows 10
    • PlanetSquires Software
Re: CWindow RC10
« Reply #30 on: June 21, 2016, 05:10:26 PM »

This is such a great idea. Many times I have been asked how to scroll regular forms/windows. It is great that now there is a class for this and also a class for automatic resizing and repositioning of forms and controls. The framework is really growing into a strong toolbox.
Logged
Paul Squires
PlanetSquires Software
WinFBE Editor and Visual Designer

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3282
Re: CWindow RC10
« Reply #31 on: June 21, 2016, 05:25:58 PM »

If you want to make it not resizable use

Code: [Select]
   pWindow.Create(NULL, "CWindow with a button", @WndProc)
   AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME)

That will work just fine. Thank You.

Edit: Woops still has a max button. This works"
Code: [Select]
AfxRemoveWindowStyle(pWindow.hWindow, WS_THICKFRAME OR WS_MAXIMIZEBOX)


James


With the next version of CWindow you can do:

pWindow.ClassStyle = <styles>

e.g.

pWindow.WindowStyle = WS_VISIBLE OR WS_CAPTION OR WS_POPUPWINDOW

There is also a property to set the extended styles.

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3282
Re: CWindow RC10
« Reply #32 on: June 21, 2016, 07:46:25 PM »

This is such a great idea. Many times I have been asked how to scroll regular forms/windows. It is great that now there is a class for this and also a class for automatic resizing and repositioning of forms and controls. The framework is really growing into a strong toolbox.

These are the kind of things that I no longer do for PB because PBer's don't use it. I'm so bored of only seeing DDT code, that I only read a few posts.

One good thing is that as it is standalone class, if someone can do it better he simply has to write his own class and offer it as an alternative.
« Last Edit: June 21, 2016, 07:49:12 PM by Jose Roca »
Logged

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3282
Re: CWindow RC10
« Reply #33 on: June 21, 2016, 09:32:53 PM »

Now that I have the scroll class working well, I will modify the CWindow and CTabPage classes to allow to store the pointer to the scroll class to delete it when the window or the tab page is destroyed. It will also allow to get a pointer to it calling a method instead of having to use a SetPropW / GetPropW / RemovePropW.

In this post, an user asked you how to create a scrollable tab page: http://www.planetsquires.com/protect/forum/index.php?topic=3795.msg27648#msg27648

With CWindow and CScrollWindow it is a piece of cake:

The "trick" is to get the client size of the tab page, make it larger, attach it to an instance of CScrollWindow, and restore the original client size.

Code: [Select]
   ' ************************************************************************
   ' // Make the first tab page scrollable
   ' // TODO: Modify the CTabPage class to set the pointer to CScrollWindow
   ' // to delete this class when the tab page is destroyed.
   ' ************************************************************************
   ' // Get the client size of the first page and make it greater
   DIM nWidth AS LONG = pTabPage1->ClientWidth
   DIM nHeight AS LONG = pTabPage1->ClientHeight
   pTabPage1->SetClientSize(nWidth + 150, nHeight + 150)
   ' // Create an instance of the CScrollWindow class and attach the window handle to it
   DIM pScrollWindow AS CScrollWindow = pTabPage1->hTabPage
   SetPropW pTabPage1->hTabPage,"CSCROLLWINDOWPTR", @pScrollWindow
   ' // Shrink the client size back to original
   pTabPage1->SetClientSize(nWidth, nHeight)

CScrollWindow will automatically display or hide the scroll bars and do the scrolling. The best thing of the good ideas is that they are simple; the worst thing is that we only got it after having tried many other complicated and unsatisfactory ways.

Full example code:

Code: [Select]
' ########################################################################################
' Microsoft Windows
' File: CW_COMMCTRL_TabControlDemo.fbtpl - Template
' Contents: CWindow Tab Control template
' Remarks: Demonstrates the use of the CTabPage class
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2016 Jose Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#INCLUDE ONCE "Afx/CWindow.inc"
#INCLUDE ONCE "Afx/CScrollWindow.inc"
USING Afx.CWindowClass

CONST IDC_TAB       = 1001
CONST IDC_EDIT1     = 1002
CONST IDC_EDIT2     = 1003
CONST IDC_BTNSUBMIT = 1004
CONST IDC_COMBO     = 1005
CONST IDC_LISTBOX   = 1006

' // Forward declarations
DECLARE FUNCTION TabPage1_WndProc(BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION TabPage2_WndProc(BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT
DECLARE FUNCTION TabPage3_WndProc(BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                          BYVAL hPrevInstance AS HINSTANCE, _
                          BYVAL szCmdLine AS ZSTRING PTR, _
                          BYVAL nCmdShow AS LONG) AS LONG

   END WinMain(GetModuleHandleW(NULL), NULL, COMMAND(), SW_NORMAL)

' ========================================================================================
' Window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      CASE WM_CREATE
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_GETMINMAXINFO
         ' Set the pointer to the address of the MINMAXINFO structure
         DIM ptmmi AS MINMAXINFO PTR = CAST(MINMAXINFO PTR, lParam)
         ' Set the minimum and maximum sizes that can be produced by dragging the borders of the window
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
         IF pWindow THEN
            ptmmi->ptMinTrackSize.x = 460 * pWindow->rxRatio
            ptmmi->ptMinTrackSize.y = 320 * pWindow->ryRatio
         END IF
         EXIT FUNCTION

      CASE WM_SIZE
         DIM pWindow AS CWindow PTR = AfxCWindowPtr(hwnd)
         DIM hTab AS HWND = GetDlgItem(hwnd, IDC_TAB)
         ' / Move the close button
         IF pWindow THEN pWindow->MoveWindow GetDlgItem(hwnd, IDCANCEL), pWindow->ClientWidth - 85, pWindow->ClientHeight - 28, 75, 23, CTRUE
         ' // Resize the tab control
         IF pWindow THEN pWindow->MoveWindow(hTab, 10, 10, pWindow->ClientWidth - 20, pWindow->ClientHeight - 42, CTRUE)
         ' // Resize the tab pages
         AfxResizeTabPages hTab
         EXIT FUNCTION

      CASE WM_NOTIFY

         DIM nPage AS DWORD              ' // Page number
         DIM pTabPage AS CTabPage PTR    ' // Tab page object reference
         DIM tci AS TCITEMW              ' // TCITEMW structure

         DIM ptnmhdr AS NMHDR PTR   ' // Information about a notification message
         ptnmhdr = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TAB
               SELECT CASE ptnmhdr->code
                  CASE TCN_SELCHANGE
                     ' // Show the selected page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom)
                     IF pTabPage THEN ShowWindow pTabPage->hTabPage, SW_SHOW
                  CASE TCN_SELCHANGING
                     ' // Hide the current page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom)
                     IF pTabPage THEN ShowWindow pTabPage->hTabPage, SW_HIDE
               END SELECT

         END SELECT

    CASE WM_DESTROY
         ' // Destroy the tab pages
         AfxDestroyAllTabPages(GetDlgItem(hwnd, IDC_TAB))
         ' // Quit the application
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                  BYVAL hPrevInstance AS HINSTANCE, _
                  BYVAL szCmdLine AS ZSTRING PTR, _
                  BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   AfxSetProcessDPIAware

   DIM pWindow AS CWindow
   pWindow.Create(NULL, "CWindow with a Tab Control", @WndProc)
   pWindow.SetClientSize(500, 320)
   pWindow.Center

   ' // Add a tab control
   DIM hTab AS HWND = pWindow.AddControl("Tab", , IDC_TAB, "", 10, 10, pWindow.ClientWidth - 20, pWindow.ClientHeight - 42)

   ' // Create the first tab page
   DIM pTabPage1 AS CTabPage PTR = NEW CTabPage
   pTabPage1->InsertPage(hTab, 0, "Tab 1", -1, @TabPage1_WndProc)
   ' // Add controls to the first page
   pTabPage1->AddControl("Label", pTabPage1->hTabPage, -1, "First name", 15, 15, 121, 21)
   pTabPage1->AddControl("Label", pTabPage1->hTabPage, -1, "Last name", 15, 50, 121, 21)
   pTabPage1->AddControl("Edit", pTabPage1->hTabPage, IDC_EDIT1, "", 165, 15, 186, 21)
   pTabPage1->AddControl("Edit", pTabPage1->hTabPage, IDC_EDIT2, "", 165, 50, 186, 21)
   pTabPage1->AddControl("Button", pTabPage1->hTabPage, IDC_BTNSUBMIT, "Submit", 340, 185, 76, 26, BS_DEFPUSHBUTTON)

   ' // Create the second tab page
   DIM pTabPage2 AS CTabPage PTR = NEW CTabPage
   pTabPage2->InsertPage(hTab, 1, "Tab 2", -1, @TabPage2_WndProc)
   ' // Add controls to the second page
   DIM hComboBox AS HWND = pTabPage2->AddControl("ComboBox", pTabPage2->hTabPage, IDC_COMBO, "", 20, 20, 191, 105)

   ' // Create the third tab page
   DIM pTabPage3 AS CTabPage PTR = NEW CTabPage
   pTabPage3->InsertPage(hTab, 2, "Tab 3", -1, @TabPage3_WndProc)
   ' // Add controls to the third page
'   DIM hListBox AS HWND = pTabPage3->AddControl("ListBox", pTabPage3->hTabPage, IDC_LISTBOX, "", 15, 20, 161, 120)
   DIM hListBox AS HWND = pTabPage3->AddControl("ListBox", pTabPage3->hTabPage, IDC_LISTBOX)
   pTabPage3->SetWindowPos hListBox, NULL, 15, 20, 161, 120, SWP_NOZORDER

   ' // Fill the controls with some data
   DIM i AS LONG = 1, wszText AS WSTRING * 260
   FOR i = 1 TO 9
      wszText = "Item " & RIGHT("00" & STR(i), 2)
      SendMessageW(hComboBox, CB_ADDSTRING, 0, CAST(LPARAM, @wszText))
      SendMessageW(hListBox, LB_ADDSTRING, 0, CAST(LPARAM, @wszText))
   NEXT
   ' // Select the first item in the combo box and the list box
   SendMessageW(hComboBox, CB_SETCURSEL, 0, 0)
   SendMessageW(hListBox, LB_SETCURSEL, 0, 0)

   ' // Add a button
   pWindow.AddControl("Button", , IDCANCEL, "&Close", 415, 292, 75, 23)

   ' ************************************************************************
   ' // Make the first tab page scrollable
   ' // TODO: Modify the CTabPage class to set the pointer to CScrollWindow
   ' // to delete this class when the tab page is destroyed.
   ' ************************************************************************
   ' // Get the client size of the first page and make it greater
   DIM nWidth AS LONG = pTabPage1->ClientWidth
   DIM nHeight AS LONG = pTabPage1->ClientHeight
   pTabPage1->SetClientSize(nWidth + 150, nHeight + 150)
   ' // Create an instance of the CScrollWindow class and attach the main window to it
   DIM pScrollWindow AS CScrollWindow = pTabPage1->hTabPage
   SetPropW pTabPage1->hTabPage,"CSCROLLWINDOWPTR", @pScrollWindow
   ' // Shrink the client size back to original
   pTabPage1->SetClientSize(nWidth, nHeight)
   ' ************************************************************************

   ' // Display the first tab page
   ShowWindow pTabPage1->hTabPage, SW_SHOW

   ' // Set the focus to the first tab
   SendMessageW hTab, TCM_SETCURFOCUS, 0, 0

   

   ' // Dispatch messages
   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Tab page 1 window procedure
' To get a pointer to the CTabPage interface:
' DIM pTabPage AS CTabPage PTR = CAST(CTabPage PTR, GetWindowLongPtr(hwnd, 0))
' ========================================================================================
FUNCTION TabPage1_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   SELECT CASE uMsg

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            CASE IDC_BTNSUBMIT
               IF HIWORD(wParam) = BN_CLICKED THEN
                  MessageBoxW(hWnd, "Submit", "Tab 1", MB_OK)
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnSize(wParam, lParam)
         EXIT FUNCTION

      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION

      CASE WM_HSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = CAST(CScrollWindow PTR, GetPropW(hwnd, "CSCROLLWINDOWPTR"))
         IF pScrollWindow THEN pScrollWindow->OnHScroll(wParam, lParam)
         EXIT FUNCTION

      CASE WM_DESTROY
         ' // Remove the property
         RemovePropW hwnd,"CSCROLLWINDOWPTR"
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Tab page 2 window procedure
' To get a pointer to the CTabPage interface:
' DIM pTabPage AS CTabPage PTR = CAST(CTabPage PTR, GetWindowLongPtr(hwnd, 0))
' ========================================================================================
FUNCTION TabPage2_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM hBrush AS HBRUSH, rc AS RECT, tlb AS LOGBRUSH

   SELECT CASE uMsg

      CASE WM_ERASEBKGND
         GetClientRect hWnd, @rc
         ' Create custom brush
         tlb.lbStyle = BS_SOLID
         tlb.lbColor = &H00CB8734
         tlb.lbHatch = 0
         hBrush = CreateBrushIndirect(@tlb)
         ' Erase background
         FillRect CAST(HDC, wParam), @rc, hBrush
         DeleteObject hBrush
         FUNCTION = CTRUE
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Tab page 3 window procedure
' To get a pointer to the CTabPage interface:
' DIM pTabPage AS CTabPage PTR = CAST(CTabPage PTR, GetWindowLongPtr(hwnd, 0))
' ========================================================================================
FUNCTION TabPage3_WndProc (BYVAL hwnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM hBrush AS HBRUSH, rc AS RECT, tlb AS LOGBRUSH

   SELECT CASE uMsg

      CASE WM_ERASEBKGND
         GetClientRect hWnd, @rc
         ' Create custom brush
         tlb.lbStyle = BS_SOLID
         tlb.lbColor = &H0000FF00
         tlb.lbHatch = 0
         hBrush = CreateBrushIndirect(@tlb)
         ' Erase background
         FillRect CAST(HDC, wParam), @rc, hBrush
         DeleteObject hBrush
         FUNCTION = CTRUE
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================
« Last Edit: June 21, 2016, 09:43:05 PM by Jose Roca »
Logged

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3282
Re: CWindow RC10
« Reply #34 on: June 21, 2016, 11:38:41 PM »

I have added the ScrollWindowPtr property to CWindow.

Now we can use

Code: [Select]
   ' // Create an instance of the CScrollWindow class and attach the main window to it
   DIM pScrollWindow AS CScrollWindow PTR = NEW CScrollWindow(hwndMain)
   pWindow.ScrollWindowPtr = pScrollWindow

and don't have to worry about destroying the CScrollWindow class, that will be destroyed by CWindow.

Also we don't need to use SetPropW, etc., but we can use:

Code: [Select]
      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = AfxCWindowPtr(hwnd)->ScrollWindowPtr
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION

Regarding tab pages, we will use:

Code: [Select]
   ' // Create an instance of the CScrollWindow class and attach the tab page handle to it
   DIM pScrollWindow AS CScrollWindow PTR = NEW CScrollWindow(pTabPage1->hTabPage)
   pTabPage1->ScrollWindowPtr = pScrollWindow

and as the pointer to the class is not stored in the tab page, but in the tab control...

Code: [Select]
      CASE WM_VSCROLL
         DIM pScrollWindow AS CScrollWindow PTR = AfxCTabPagePtr(GetParent(hwnd))->ScrollWindowPtr
         IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)
         EXIT FUNCTION

Josť Roca

  • Moderator
  • Guru Member
  • *****
  • Posts: 3282
Re: CWindow RC10
« Reply #35 on: June 22, 2016, 12:41:30 AM »

We could even use this compound syntax:

Code: [Select]
AfxCWindowPtr(hwnd)->ScrollWindowPtr->OnSize(wParam, lParam)

Code: [Select]
DIM pScrollWindow AS CScrollWindow PTR = AfxCWindowPtr(hwnd)->ScrollWindowPtr
IF pScrollWindow THEN pScrollWindow->OnVScroll(wParam, lParam)

but it's unsafe, because if ScrollWindowPtr returns a null pointer it will GPF.

Only with a compiler with full support for compound syntax could we use it safely. The compiler will check if the result of AfxCWindowPtr(hwnd)->ScrollWindowPtr is null or not and, if it is null, will not call OnVScroll(wParam, lParam). This is what I requested to the late Bob Zale because without this feature, the compound syntax is unsafe.

Pages: 1 2 [3]