Main Menu

Recent posts

#41
PlanetSquires Software / Re: Tiko Editor v1.3.0 release
Last post by Richard Kelly - April 26, 2026, 09:47:01 PM
I downloaded Tiko and built a project with no issues. Found it quite straightforward to use.

Congratulations!

 8)
#42
José Roca Software / Re: Tab Control Question
Last post by Richard Kelly - April 26, 2026, 03:57:01 PM
I updated my notify code to use your macro as shown below and it works perfectly. Thank you for the tip.

      CASE WM_NOTIFY
         DIM uFromSystemDate AS SYSTEMTIME
         DIM pTabPage AS CTabPage PTR    ' // Tab page object reference
         DIM dtp AS NMDATETIMECHANGE
         CBNMTYPESET(dtp, wParam, lParam) ' // Information about a notification message
         SELECT CASE dtp.nmhdr.idFrom
            CASE IDC_TABCONTROL
               SELECT CASE dtp.nmhdr.code
                  CASE TCN_SELCHANGE
                     ' // Show the selected page
                     pTabPage = AfxCTabPagePtr(dtp.nmhdr.hwndFrom, -1)
                     IF pTabPage THEN ..ShowWindow pTabPage->hTabPage, SW_SHOW
                  CASE TCN_SELCHANGING
                     ' // Hide the current page
                     pTabPage = AfxCTabPagePtr(dtp.nmhdr.hwndFrom, -1)
                     IF pTabPage THEN ..ShowWindow pTabPage->hTabPage, SW_HIDE
               END SELECT
            CASE IDC_DATEPICKER
               SELECT CASE dtp.nmhdr.code
                   CASE DTN_DATETIMECHANGE
                       ' // Date Picker sends two DTN_DATETIMECHANGE messages.
                       '//  Check if our global SYSTIME variable is different before updating for date and time
                       CDtPicker.GetSystemtime(dtp.nmhdr.hwndFrom, uFromSystemDate)
                       IF (uSystemDate.wYear <> uFromSystemDate.wYear) OR (uSystemDate.wMonth <> uFromSystemDate.wMonth) OR (uSystemDate.wDay <> uFromSystemDate.wDay) THEN
                          PostMessageW hWnd, WM_USER + 99, 0, 0
                       END IF
               END SELECT
            CASE IDC_TIMEPICKER
               SELECT CASE dtp.nmhdr.code
                   CASE DTN_DATETIMECHANGE
                      PostMessageW hWnd, WM_USER + 99, 0, 0
               END SELECT
         END SELECT
#43
José Roca Software / Re: Tab Control Question
Last post by Richard Kelly - April 26, 2026, 03:27:01 PM
I didn't know that Jose. I do want to use AFXNova as much as possible and I'll switch over my code. I did notice that the datepicker with the drop down calendar sends two DTN_DATETIMECHANGE notifications which I verified via Mr Google. I have a global SYSTIME defined that gets updated when I do my form update on date or time changes and found that if I check the DATEPICKER value and if it's different than my global, then do my form update I can avoid the form update on the second notification as shown below.

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_USER + 99
         ' // Update Form for date and time
         UpdateForm()
      CASE WM_CREATE
         RETURN 0
      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            CASE IDCANCEL
               ' // If ESC key pressed, close the application sending an WM_CLOSE message
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  RETURN 0
               END IF
          END SELECT
         
      CASE WM_NOTIFY
         DIM uFromSystemDate AS SYSTEMTIME
         DIM pTabPage AS CTabPage PTR    ' // Tab page object reference
         DIM ptnmhdr AS NMHDR PTR        ' // Information about a notification message
         ptnmhdr = CAST(NMHDR PTR, lParam)
         SELECT CASE ptnmhdr->idFrom
            CASE IDC_TABCONTROL
               SELECT CASE ptnmhdr->code
                  CASE TCN_SELCHANGE
                     ' // Show the selected page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom, -1)
                     IF pTabPage THEN ..ShowWindow pTabPage->hTabPage, SW_SHOW
                  CASE TCN_SELCHANGING
                     ' // Hide the current page
                     pTabPage = AfxCTabPagePtr(ptnmhdr->hwndFrom, -1)
                     IF pTabPage THEN ..ShowWindow pTabPage->hTabPage, SW_HIDE
               END SELECT
            CASE IDC_DATEPICKER
               SELECT CASE ptnmhdr->code
                   CASE DTN_DATETIMECHANGE
                       ' // Date Picker sends two DTN_DATETIMECHANGE messages.
                       '//  Check if our global SYSTIME variable is different before updating for date and time
                       CDtPicker.GetSystemtime(ptnmhdr->hwndFrom, uFromSystemDate)
                       IF (uSystemDate.wYear <> uFromSystemDate.wYear) OR (uSystemDate.wMonth <> uFromSystemDate.wMonth) OR (uSystemDate.wDay <> uFromSystemDate.wDay) THEN
                          PostMessageW hWnd, WM_USER + 99, 0, 0
                       END IF
               END SELECT
            CASE IDC_TIMEPICKER
               SELECT CASE ptnmhdr->code
                   CASE DTN_DATETIMECHANGE
                      PostMessageW hWnd, WM_USER + 99, 0, 0
               END SELECT
         END SELECT
         
      CASE WM_SIZE
         ' // Get the tab control handle
         DIM hTab AS HWND = GetDlgItem(hwnd, IDC_TABCONTROL)
         ' // Get a pointer to the tab page
         DIM pTabPage AS CTabPage PTR = AfxCTabPagePtr(hTab, -1)
         ' // Resize the tab pages
         IF pTabPage THEN pTabPage->ResizePages
         RETURN 0

      CASE WM_DESTROY
        ' // Destroy the tab pages
        DIM hTab AS HWND = GetDlgItem(hwnd, IDC_TABCONTROL)
        AfxDestroyAllTabPages(hTab)
        PostQuitMessage(0)
        EXIT FUNCTION
       
   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
#44
José Roca Software / Re: Tab Control Question
Last post by José Roca - April 26, 2026, 02:16:06 PM
The wrappers are all optional. AfxNova is 100% SDK‑compatible, so you can use the wrappers for convenience or stick to straight SDK code if you prefer.

This macro, #define CBNMTYPESET(tp, wp, lp) memcpy @tp, CAST(ANY PTR, lp), SIZEOF(tp), allows to process WM_NOTIFY messages as if Windows were sending you an NM_ structure directly instead of a pointer to it. This avoids the need to use of pointers and casting.

But again, it is optional. Therefore, instead of:

      CASE WM_NOTIFY
        ' // Notification messages
        DIM dtp AS NMDATETIMECHANGE
        CBNMTYPESET(dtp, wParam, lParam)
        IF dtp.nmhdr.idfrom = IDC_DTPICKER THEN
            IF dtp.nmhdr.code = DTN_DATETIMECHANGE THEN
              ' // Get the selected date
              DIM wszDate AS WSTRING * 260
              GetDateFormatW LOCALE_USER_DEFAULT, DATE_LONGDATE, @dtp.st, NULL, wszDate, SIZEOF(wszDate)\2
              SetWindowText(GetDlgItem(hwnd, IDC_LABEL), "Selected date: " & wszDate)
            END IF
        END IF

you can use plain SDK code.

CASE WM_NOTIFY
    ' lParam points to a NMDATETIMECHANGE structure
    DIM pDtp AS NMDATETIMECHANGE PTR
    pDtp = CAST(NMDATETIMECHANGE PTR, lParam)
    IF pDtp->nmhdr.idfrom = IDC_DTPICKER THEN
        IF pDtp->nmhdr.code = DTN_DATETIMECHANGE THEN
            DIM wszDate AS WSTRING * 260
            GetDateFormatW( _
                LOCALE_USER_DEFAULT, _
                DATE_LONGDATE, _
                @pDtp->st, _
                NULL, _
                wszDate, _
                SIZEOF(wszDate)\2)
            SetWindowText(GetDlgItem(hwnd, IDC_LABEL), _
                "Selected date: " & wszDate)
        END IF
    END IF

In short, AfxNova simplifies SDK usage, but it never forces you to use the wrappers.

#45
José Roca Software / Re: Tab Control Question
Last post by hajubu - April 26, 2026, 08:50:41 AM
HI,
getting the hint from Jose for "the correct Listview  filling in /of the page"

I also adapted the snippet of listview_01b.bas now as a fourth Tabpage inside the TabCtrl01b.bas as my exercise using CListview.inc

Thanks ,  have fun !
Hans (hajubu)


#46
José Roca Software / Re: Tab Control Question
Last post by Richard Kelly - April 26, 2026, 03:37:05 AM
Thank you Hajubu and Jose for the great assistance and support. I have the first of 4 tabs done and everything works perfectly.

#47
José Roca Software / Re: Tab Control Question
Last post by José Roca - April 26, 2026, 12:39:50 AM
QuoteNow that I can get my form built, I have a subroutine that adds all the data values. What technique would you recommend so that gets run the first time after the form is completely built? I have not yet put in any code to detect when my datepicker changes values for subsequent data refreshes.

That depends of each control. You have to read the MSDN documentation: https://learn.microsoft.com/en-us/windows/win32/controls/date-and-time-picker-control-reference

See the notification messages in that link.

For example, to detect that the date time has changed, you have to process DTN_DATETIMECHANGE.

      CASE WM_NOTIFY
        ' // Notification messages
        DIM dtp AS NMDATETIMECHANGE
        CBNMTYPESET(dtp, wParam, lParam)
        IF dtp.nmhdr.idfrom = IDC_DTPICKER THEN
            IF dtp.nmhdr.code = DTN_DATETIMECHANGE THEN
              ' // Get the selected date
              DIM wszDate AS WSTRING * 260
              GetDateFormatW LOCALE_USER_DEFAULT, DATE_LONGDATE, @dtp.st, NULL, wszDate, SIZEOF(wszDate)\2
              SetWindowText(GetDlgItem(hwnd, IDC_LABEL), "Selected date: " & wszDate)
            END IF
        END IF

Full example: https://github.com/JoseRoca/AfxNova/blob/main/Templates/SDK%20Templates/CW_DTPicker_01b.bas

The Windows API always sends notification messages. Some languages, like .NET, intercept these messages and send "events".
#48
José Roca Software / Re: Tab Control Question
Last post by José Roca - April 26, 2026, 12:23:48 AM
The static classes like CListView are to save work, so instead of

DIM lvc AS LVCOLUMNW
        lvc.mask = LVCF_FMT OR LVCF_WIDTH OR LVCF_TEXT
        lvc.fmt = LVCFMT_LEFT
        lvc.cx = 110
        DIM wszText AS WSTRING * 260 = "Name"
        lvc.pszText = @wszText
        CListView.InsertColumn(hListView, 0, @lvc)
        lvc.cx = 200
        wszText = "Date"
        lvc.pszText = @wszText
        CListView.InsertColumn(hListView, 1, @lvc)

You can simply use:

CListView.AddColumn(hListView, 0, "Name", pWindow.ScaleX(110))
CListView.AddColumn(hListView, 1, "Date", pWindow.ScaleX(200))

CListView.AddColumn does this internally:

PRIVATE FUNCTION CListView.AddColumn (BYVAL hListView AS HWND, BYVAL iCol AS LONG, BYREF wszText AS WSTRING, BYVAL nWidth AS LONG, BYVAL nFormat AS LONG = LVCFMT_LEFT) AS LONG
  DIM lvc AS LVCOLUMNW
  lvc.mask = LVCF_FMT OR LVCF_WIDTH OR LVCF_TEXT OR LVCF_SUBITEM
  lvc.fmt = nFormat
  lvc.pszText = @wszText
  lvc.cx = nWidth
  RETURN SendMessageW(hListView, LVM_INSERTCOLUMNW, iCol, CAST(LPARAM, @lvc))
END FUNCTION

The use of pWindow.ScaleX is to make the width the same relative size depending of the DPI being used.
#49
José Roca Software / Re: Tab Control Question
Last post by Richard Kelly - April 25, 2026, 10:40:46 PM
I'm sorry to waste your time. I overlooked that part of your post. Here is the updated code that works. I switched over to using your CListView class.

========================================================================================
' Tab page 1 window procedure
' ========================================================================================
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_CREATE
        PostMessageW hwnd, WM_USER + 1, 0, 0
       
    CASE WM_USER + 1
    ' Now the tab page has been inserted and has its final size

        DIM pTabPage AS CTabPage PTR = AfxCTabPagePtr(GetParent(hwnd), 0)
        DIM hListView AS HWND = pTabPage->AddControl("LISTVIEW", hwnd, IDC_LVPAGE1)
        ' // Get the width and height of the tab page
        DIM w AS LONG = pTabPage->Width
        DIM h AS LONG = pTabPage->Height
        ' // Set the listview position and visible size
        pTabPage->SetWindowPos hListView, NULL, 0, 0, w, h, SWP_NOZORDER
        ' // Anchor the ListView
        pTabPage->AnchorControl(IDC_LVPAGE1, AFX_ANCHOR_HEIGHT_WIDTH)
        DIM lvc AS LVCOLUMNW
        lvc.mask = LVCF_FMT OR LVCF_WIDTH OR LVCF_TEXT
        lvc.fmt = LVCFMT_LEFT
        lvc.cx = 110
        DIM wszText AS WSTRING * 260 = "Name"
        lvc.pszText = @wszText
        CListView.InsertColumn(hListView, 0, @lvc)
        lvc.cx = 200
        wszText = "Date"
        lvc.pszText = @wszText
        CListView.InsertColumn(hListView, 1, @lvc)
               
        EXIT FUNCTION
         
   END SELECT
   
   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION

Now that I can get my form built, I have a subroutine that adds all the data values. What technique would you recommend so that gets run the first time after the form is completely built? I have not yet put in any code to detect when my datepicker changes values for subsequent data refreshes.
#50
José Roca Software / Re: Tab Control Question
Last post by José Roca - April 25, 2026, 09:55:46 PM
1.- The name of the ListView class is "ListView" or "SYSLISTVIEW32", not "LVSupportedCalendars".

2.- You're using ListView_SetItemText twice, but yopu aren't adding any item.

3.- As you're using the ListView_xxx macros, make sure that you use #define UNICODE

4.- Haven't you read my previous post?

      CASE WM_CREATE
         PostMessageW hwnd, WM_USER + 1, 0 , 0
         RETURN 0

      CASE WM_USER + 1
        DIM pTabPage AS CTabPage PTR = AfxCTabPagePtr(GetParent(hwnd), 0)
        DIM hListView AS HWND = pTabPage->AddControl("ListView", hwnd, IDC_LVPAGE1)

        ' // Get the width and height of the tab page
        DIM w AS LONG = pTabPage->Width
        DIM h AS LONG = pTabPage->Height
        ' // Set the listview position and visible size
        pTabPage->SetWindowPos hListView, NULL, 0, 0, w, h, SWP_NOZORDER
        ' // Anchor the ListView
        pTabPage->AnchorControl(IDC_LVPAGE1, AFX_ANCHOR_HEIGHT_WIDTH)
        DIM dwsText AS DWSTRING
        dwsText = "Name"
        ListView_AddColumn(hListView, 0, dwsText, pTabPage->ScaleX(110))
        dwsText = "Date"
        ListView_AddColumn(hListView, 1, dwsText, pTabPage->ScaleX(200))

        dwsText = "Name Column"
        ListView_AddItem(hListView, 0, 0, dwsText)
        dwsText = "Date Column"
        ListView_SetItemText(hListView, 0, 1, dwsText)

        EXIT FUNCTION