Pelles C forum

C language => Beginner questions => Topic started by: WiiLF23 on October 16, 2023, 02:47:28 AM

Title: ListView Progressbar
Post by: WiiLF23 on October 16, 2023, 02:47:28 AM
Hey everyone.

I am having issues with implementing progress bars using the following code *in Pelles C*

ListViewProgress.cpp
http://www.rohitab.com/discuss/topic/36617-listview-with-progress-bar/#entry10078425 (http://www.rohitab.com/discuss/topic/36617-listview-with-progress-bar/#entry10078425)

Pelles C version:
Code: [Select]
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <wchar.h>

#pragma comment(lib, "uxtheme.lib")
#pragma comment(lib, "comctl32.lib")
#include <uxtheme.h>
#include <tmschema.h>

#include "main.h"

#define NELEMS(a)  (sizeof(a) / sizeof((a)[0]))

static INT_PTR CALLBACK MainDlgProc(HWND, UINT, WPARAM, LPARAM);

typedef struct {
INT  iSubItem;
INT  iProgress;
BOOL bSmooth;
} LISTVIEWPROGRESS;

static HANDLE ghInstance;

HFONT MakeFont(LPTSTR szFont, INT nPointSize, INT nWeight, BOOL bItalic, BOOL bUnderline, BOOL bStrikeOut, DWORD dwCharSet) // by Napalm
{
HDC hDC = GetDC(HWND_DESKTOP);
nPointSize = -MulDiv(nPointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
ReleaseDC(HWND_DESKTOP, hDC);
return CreateFont(nPointSize, 0, 0, 0, nWeight, bItalic, bUnderline, bStrikeOut,
dwCharSet, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, szFont);
}

VOID DrawProgressBar(HTHEME hTheme, HDC hdc, LPRECT rcBar, BOOL bSmooth, INT iProgress) // by Napalm
{
RECT rcContent, rcChunk;

// Find the content area inside the progress bar area.
GetThemeBackgroundContentRect(hTheme, hdc, PP_BAR, 0, rcBar, &rcContent);

// Work out the how much of the content area is for our progress-bar percentage.
iProgress = rcContent.left + (int)((rcContent.right - rcContent.left) *
((float)max(min(iProgress, 100), 0) / 100.0f));

// Draw the progress-bar background with transparent corners.
HRGN hRgn = CreateRoundRectRgn(rcBar->left, rcBar->top, rcBar->right + 1, rcBar->bottom + 1, 4, 4);
SelectClipRgn(hdc, hRgn);
DrawThemeBackground(hTheme, hdc, PP_BAR, 0, rcBar, NULL);
SelectClipRgn(hdc, NULL);
DeleteObject(hRgn);

if(bSmooth){
// Draw the smooth progress-bar percentage.
rcChunk = rcContent;
rcChunk.right = iProgress;
DrawThemeBackground(hTheme, hdc, PP_CHUNK, 0, &rcChunk, NULL);
}else{
// Draw the chunked progress-bar percentage.
int nChunkSize = 6, nSpaceSize = 2;
GetThemeMetric(hTheme, hdc, PP_BAR, 0, TMT_PROGRESSCHUNKSIZE, &nChunkSize);
GetThemeMetric(hTheme, hdc, PP_BAR, 0, TMT_PROGRESSSPACESIZE, &nSpaceSize);
rcChunk = rcContent;
rcChunk.right = rcChunk.left;
while(rcChunk.left < iProgress){
rcChunk.right = min(rcChunk.left  + nChunkSize, rcContent.right);
DrawThemeBackground(hTheme, hdc, PP_CHUNK, 0, &rcChunk, NULL);
rcChunk.left  = min(rcChunk.right + nSpaceSize, rcContent.right);
}
}
}

int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR *pszCmdLine, int nCmdShow)
{
    INITCOMMONCONTROLSEX icc;
    WNDCLASSEX wcx;

    ghInstance = hInstance;

    icc.dwSize = sizeof(icc);
    icc.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&icc);

    wcx.cbSize = sizeof(wcx);
    if (!GetClassInfoEx(NULL, MAKEINTRESOURCE(32770), &wcx))
        return 0;

    wcx.hInstance = hInstance;
    wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDR_ICO_MAIN));
    wcx.lpszClassName = L"ListViewClass";
    if (!RegisterClassEx(&wcx))
        return 0;

    return DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)MainDlgProc);
}

static HWND hWndListView;
static HWND hTestListView;

static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HANDLE hThemeProgress = NULL;
static HFONT hfArial = NULL;
static LISTVIEWPROGRESS lvProgress[11];

    switch (uMsg)
    {
case WM_CREATE:
{
// Dummy message. So we initialize our hThemeProgress handle.
SendMessage(hwndDlg, WM_THEMECHANGED, 0, 0);

// Create a List-View with some funky styles.
hWndListView = GetDlgItem(hwndDlg, LISTVIEW_CONTROL);

ListView_SetExtendedListViewStyle(hWndListView, LVS_EX_FULLROWSELECT);

// Set our List-View options.
hfArial = MakeFont(L"Arial", 11, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET);
SendMessage(hWndListView, WM_SETFONT, (WPARAM)hfArial, FALSE);
ListView_SetTextColor(hWndListView, RGB(10, 10, 160));

// Populate our list view with test data and assign the progress bars.
WCHAR szText[32] = { 0 };
LVCOLUMN lvColumn = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 150, szText };

LVITEM lvItem = { 0 };
lvItem.pszText  = szText;
for(lvItem.iItem = 0; lvItem.iItem < 11; lvItem.iItem++){
lvProgress[lvItem.iItem].iSubItem  = 2;
lvProgress[lvItem.iItem].iProgress = lvItem.iItem * 10;
lvProgress[lvItem.iItem].bSmooth   = TRUE;
lvItem.lParam = (LPARAM)&lvProgress[lvItem.iItem];
for(lvItem.iSubItem = 0; lvItem.iSubItem < 4; lvItem.iSubItem++){
lvItem.mask = LVIF_TEXT | ((lvItem.iSubItem == 0) ? LVIF_PARAM : 0);
wsprintf(szText, L"Item %c%d", L'A' + lvItem.iSubItem, lvItem.iItem);
if(lvItem.iSubItem == 0)
ListView_InsertItem(hWndListView, &lvItem);
else if(lvItem.iSubItem != 2)
ListView_SetItem(hWndListView, &lvItem);
}
}
lvProgress[2].bSmooth = FALSE;
lvProgress[7].bSmooth = FALSE;
lvProgress[8].bSmooth = FALSE;

// Timer for test updates.
SetTimer(hwndDlg, 0, 75, 0);
}
return 0;

case WM_INITDIALOG:
{
// I dont want to create a new control - I want to use the ListView control already added by visual designer (2nd line below)
hWndListView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | LVS_REPORT | LVS_NOSORTHEADER, 0, 0, 0, 0, hwndDlg, (HMENU)LISTVIEW_CONTROL, ghInstance, NULL);
//hWndListView = GetDlgItem(hwndDlg, LISTVIEW_CONTROL);

// Set our List-View options.
hfArial = MakeFont(L"Arial", 11, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET);
SendMessage(hWndListView, WM_SETFONT, (WPARAM)hfArial, FALSE);
ListView_SetTextColor(hWndListView, RGB(10, 10, 160));

WCHAR szText[32] = { 0 };
LVCOLUMN lvColumn = { LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 150, szText };

    lvColumn.mask = LVCF_TEXT | LVCF_WIDTH;
    lvColumn.cx = 100;
    lvColumn.pszText = L"Column A";
    ListView_InsertColumn(hWndListView, 0, &lvColumn);

    lvColumn.cx = 100;
    lvColumn.pszText = L"Column B";
    ListView_InsertColumn(hWndListView, 1, &lvColumn);

lvColumn.cx = 200;
    lvColumn.pszText = L"Column C";
    ListView_InsertColumn(hWndListView, 2, &lvColumn);

lvColumn.cx = 100;
    lvColumn.pszText = L"Column D";
    ListView_InsertColumn(hWndListView, 3, &lvColumn);
           
LVITEM lvItem = { 0 };
lvItem.pszText  = szText;
for(lvItem.iItem = 0; lvItem.iItem < 11; lvItem.iItem++){
lvProgress[lvItem.iItem].iSubItem  = 2;
lvProgress[lvItem.iItem].iProgress = lvItem.iItem * 10;
lvProgress[lvItem.iItem].bSmooth   = TRUE;
lvItem.lParam = (LPARAM)&lvProgress[lvItem.iItem];
for(lvItem.iSubItem = 0; lvItem.iSubItem < 4; lvItem.iSubItem++){
lvItem.mask = LVIF_TEXT | ((lvItem.iSubItem == 0) ? LVIF_PARAM : 0);
wsprintf(szText, L"Item %c%d", L'A' + lvItem.iSubItem, lvItem.iItem);
if(lvItem.iSubItem == 0)
ListView_InsertItem(hWndListView, &lvItem);
else if(lvItem.iSubItem != 2)
ListView_SetItem(hWndListView, &lvItem);
}
}
lvProgress[2].bSmooth = FALSE;
lvProgress[7].bSmooth = FALSE;
lvProgress[8].bSmooth = FALSE;

// Timer for test updates.
SetTimer(hwndDlg, 0, 75, 0);

return TRUE;
}

case WM_TIMER:
    {
        //hWndListView = GetDlgItem(hwndDlg, LISTVIEW_CONTROL);
        int itemCount = ListView_GetItemCount(hWndListView);

        // Increment and loop each progress bar.
        // We also build an update rectangle as we go to reduce flicker when we finally repaint.
        RECT rcItem, rcUpdate;
        SetRectEmpty(&rcUpdate);
        for (int iItem = 0; iItem < itemCount; iItem++) {
            if (++lvProgress[iItem].iProgress > 100)
lvProgress[iItem].iProgress = 0;

            ListView_GetSubItemRect(hWndListView, iItem, lvProgress[iItem].iSubItem, LVIR_BOUNDS, &rcItem);
            UnionRect(&rcUpdate, &rcUpdate, &rcItem);
        }
        RedrawWindow(hWndListView, &rcUpdate, NULL, RDW_INVALIDATE | RDW_NOERASE | RDW_UPDATENOW);
    }
    return 0;

case WM_THEMECHANGED:
{
if(hThemeProgress){
CloseThemeData(hThemeProgress);
hThemeProgress = NULL;
}
hThemeProgress = OpenThemeData(hwndDlg, L"Progress");
}
return 0;

case WM_SIZE:
{
hWndListView = GetDlgItem(hwndDlg, LISTVIEW_CONTROL);
// Resize the ListView when our test window gets resized.
RECT rcClient;
GetClientRect(hwndDlg, &rcClient);
InflateRect(&rcClient, -10, -10);
SetWindowPos(hWndListView, NULL,
rcClient.left,    rcClient.top,
rcClient.right  - rcClient.left,
rcClient.bottom - rcClient.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
return 0;

case WM_NOTIFY:
{
LPNMHDR lpNMHdr = (LPNMHDR)lParam;
// We received a Custom Draw notification message. Was it for our ListView?
if(lpNMHdr->idFrom == LISTVIEW_CONTROL && lpNMHdr->code == NM_CUSTOMDRAW){
LPNMLVCUSTOMDRAW pCustomDraw = (LPNMLVCUSTOMDRAW)lParam;
// Is this part of the drawing state for each sub-item?
if(pCustomDraw->nmcd.dwDrawStage == (CDDS_ITEMPOSTPAINT | CDDS_SUBITEM)){
LISTVIEWPROGRESS *lvp = (LISTVIEWPROGRESS *)pCustomDraw->nmcd.lItemlParam;
// Does the current sub-item match the progress-bar sub-item?
if(pCustomDraw->iSubItem == lvp->iSubItem){
RECT rcBar;
// Get the sub-item rectangle.
ListView_GetSubItemRect(lpNMHdr->hwndFrom, pCustomDraw->nmcd.dwItemSpec,
pCustomDraw->iSubItem, LVIR_BOUNDS, &rcBar);
// Get a little extra room.
InflateRect(&rcBar, -2, -2);
// Draw the progress bar to the sub-item location.
DrawProgressBar(hThemeProgress, pCustomDraw->nmcd.hdc, &rcBar, lvp->bSmooth, lvp->iProgress);
// Skip the default drawing action since we've done this stages drawing.
return CDRF_SKIPDEFAULT;
}
}
// Else do the default drawing action and request we get post-subitem drawing notification.
return CDRF_DODEFAULT | CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYSUBITEMDRAW;
}
}
break;

case WM_DESTROY:
if(hThemeProgress)
CloseThemeData(hThemeProgress);
if(hfArial)
DeleteObject(hfArial);
PostQuitMessage(0);
return 0;

        case WM_COMMAND:
            switch (GET_WM_COMMAND_ID(wParam, lParam))
            {
                case IDOK:
                    EndDialog(hwndDlg, TRUE);
                    return TRUE;
            }
            break;

        case WM_CLOSE:
            EndDialog(hwndDlg, 0);
            return TRUE;
    }

    return DefWindowProc(hwndDlg, uMsg, wParam, lParam);
}

main.h
Code: [Select]
#define DLG_MAIN  1001
#define IDR_ICO_MAIN  8001
#define LISTVIEW_CONTROL 100

What is happening at this point after launching application:

(https://i.ibb.co/RjJBrKN/progwindows.jpg)

Left: Pelles C
Right: (from here - http://www.rohitab.com/discuss/topic/36617-listview-with-progress-bar/#entry10078425 (http://www.rohitab.com/discuss/topic/36617-listview-with-progress-bar/#entry10078425))

Can someone tell me what is going on? Additionally, I dont want to "Create a control programmatically", as I have a ListView control added though the resource editor (dialog design mode).

3 days at this now and I am  just burning hours and hours at this silly issue. Can someone point out what the problem is so I can finally continue developing this application?

I need the code from the link (aka ListViewProgress.cpp).
This still does not provide me a method to update specific progress rows in the listview based on the index of subitem0, but that is outside the scope of my question

Any help is greatly appreciated. Thank you.
Title: Re: ListView Progressbar
Post by: Pelle on October 16, 2023, 01:15:53 PM
The original code from http://www.rohitab.com works fine with Pelles C.

The difference to the code posted here starts in WinMain():
- The original code creates a traditional application window, where one of the first messages will be WM_CREATE.
- The code posted here uses the trick of creating the application window as a dialog, where one of the first messages will be WM_INITDIALOG and not WM_CREATE (so some needed code will never be executed).

I'm pretty sure the code can be rewritten to work with the application window as a dialog, but I leave the exact details for someone else...
Title: Re: ListView Progressbar
Post by: WiiLF23 on October 16, 2023, 05:16:30 PM
Thank you Pelle, I appreciate the response. I will follow that link and consult the resource provided.
Title: Re: ListView Progressbar
Post by: frankie on October 16, 2023, 05:31:32 PM
I confirm that the original code works well.
I can't find the problem, but I suspect that using the dialog the notification messages aren't sent to the dialog procedure.
Probably it requires the subclassing of the ListView to work.
I'll check when I'll have time.
Title: Re: ListView Progressbar
Post by: WiiLF23 on October 16, 2023, 06:04:07 PM
Thank you frankie. It is solid code, but I agree the notification is incorrect in respect to Pelles C.

Sub-classing has brought me great things outside of this criteria (UI updates from another thread etc) so this just may be the way.
This will certainly help out others as well.

EDIT
Dropping source file as a generic Win32 program compiles successful producing the exact result I was after as shown in the right side screenshot. This is interesting. I have a lot to learn about this.

WindowProcedure  => DialogProcedure etc. I should be able to get this working within the hour. Thanks for all the help guys.
Title: Re: ListView Progressbar
Post by: frankie on October 17, 2023, 11:25:51 PM
As I supposed the problem is the filtering to notification messages from the dialog window procedure.
Subclassing the dialog window solves the problem.  8)
Title: Re: ListView Progressbar
Post by: Robert on October 18, 2023, 02:55:37 AM
As I supposed the problem is the filtering to notification messages from the dialog window procedure.
Subclassing the dialog window solves the problem.  8)

Thanks, frankie, for this very informative example.

In should be noted that the example uses ComCtl32.dll version 6.

Quote
ComCtl32.dll version 6 is Unicode only. The common controls supported by ComCtl32.dll version 6 should not be subclassed (or superclassed) with ANSI window procedures.
More details here:

https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview
 (https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview)

Also, frankie, in your code I see functions have a preamble like, for example, this

Code: [Select]
/*+@@fnc@@----------------------------------------------------------------*//*!
   \brief DialogSubclassedProcedure
   \date Created  on Tue Oct 17 23:00:57 2023
   \date Modified on Tue Oct 17 23:00:57 2023
\*//*-@@fnc@@----------------------------------------------------------------*/

Could you give us a brief explanation of the functionality of these comments and, if not of your invention, a reference?

Thanks again.
Title: Re: ListView Progressbar
Post by: Stefan Pendl on October 18, 2023, 09:21:55 AM
Also, frankie, in your code I see functions have a preamble like, for example, this

Code: [Select]
/*+@@fnc@@----------------------------------------------------------------*//*!
   \brief DialogSubclassedProcedure
   \date Created  on Tue Oct 17 23:00:57 2023
   \date Modified on Tue Oct 17 23:00:57 2023
\*//*-@@fnc@@----------------------------------------------------------------*/

Could you give us a brief explanation of the functionality of these comments and, if not of your invention, a reference?

This seems to be related to automatic documenting the source by doxygen (https://www.doxygen.nl/).
Title: Re: ListView Progressbar
Post by: frankie on October 18, 2023, 03:24:36 PM
As I supposed the problem is the filtering to notification messages from the dialog window procedure.
Subclassing the dialog window solves the problem.  8)

Thanks, frankie, for this very informative example.

In should be noted that the example uses ComCtl32.dll version 6.

Quote
ComCtl32.dll version 6 is Unicode only. The common controls supported by ComCtl32.dll version 6 should not be subclassed (or superclassed) with ANSI window procedures.
More details here:

https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview
 (https://learn.microsoft.com/en-us/windows/win32/controls/subclassing-overview)
Robert you're right, but in this case there aren't text strings involved, I just handle graphic functions in the subclass code, so it should be safe enough.
Also in the link to MS docs that you provided few lines down, there is a deeper description:
Quote
All strings passed to the procedure are Unicode strings even if Unicode is not specified as a preprocessor definition.
Anyway for the sake of safety you can change the code to UNICODE.

Also, frankie, in your code I see functions have a preamble like, for example, this

Code: [Select]
/*+@@fnc@@----------------------------------------------------------------*//*!
   \brief DialogSubclassedProcedure
   \date Created  on Tue Oct 17 23:00:57 2023
   \date Modified on Tue Oct 17 23:00:57 2023
\*//*-@@fnc@@----------------------------------------------------------------*/

Could you give us a brief explanation of the functionality of these comments and, if not of your invention, a reference?

Thanks again.
As Stefan supposed this is an utility to insert DoxyGen comments.
Right clicking inside a function you get a menu entry to edit comments for the function or the module (see 'menu' image).
Then will appear a dialog to entry data as in the 'Dialog' image. If you fill the Dialog with the data in the image you will get in the editor:
Code: [Select]
/*+@@fnc@@----------------------------------------------------------------*//*!
 \brief InitListView
 \details Initialize the list view control
 \param [in] hWnd Dialog window handle
 \param [in] hWndListView list view control window handle
 \return None
 \exception None
 \pre To be called on Dialog entry
 \bug None known
 \author frankie
 \version 1.0.1
 \date Created  on Tue Oct 17 22:36:33 2023
 \date Modified on Wed Oct 18 15:15:15 2023
 \warning Call before to show Dialog
\*//*-@@fnc@@----------------------------------------------------------------*/
void InitListView(HWND hWnd, HWND hWndListView)
{
// Dummy message. So we initialize our hThemeProgress handle.
SendMessage(hWnd, WM_THEMECHANGED, 0, 0);

ListView_SetExtendedListViewStyle(hWndListView, LVS_EX_FULLROWSELECT);

It is in an old Addin of mine (https://forum.pellesc.de/index.php?topic=779.msg3612#msg3612), and with some modification in a dropped project of mine (https://forum.pellesc.de/index.php?topic=5241.msg20156#msg20156).
The actual version is a patched one too messed up to publish. When I'll have time to fix it maybe I'll republish it.
Title: Re: ListView Progressbar
Post by: WiiLF23 on October 19, 2023, 07:27:02 PM
The primary motivation behind this was to avoid GUI frameworks (QT4 for example), and to rely on native win32 controls.

All input has been more than appreciated!

(https://i.ibb.co/Y2bpBv6/Progress-LV.jpg)

Additionally - Draw the progress percentage (wide string):

Code: [Select]
void DrawProgressBar(HTHEME hTheme, HDC hdc, LPRECT rcBar, BOOL bSmooth, INT iProgress)
{
RECT rcContent, rcChunk;

int trackprog = iProgress;
GetThemeBackgroundContentRect(hTheme, hdc, PP_BAR, 0, rcBar, &rcContent);
iProgress = rcContent.left + (int)((rcContent.right - rcContent.left) * ((float)max(min(iProgress, 100), 0) / 100.0f));

int ellipse_width_height = 0, ellipse_height = 0;
HRGN hRgn = CreateRoundRectRgn(rcBar->left, rcBar->top, rcBar->right + 1, rcBar->bottom + 1, ellipse_width_height, ellipse_height);
SelectClipRgn(hdc, hRgn);
DrawThemeBackground(hTheme, hdc, PP_BAR, 0, rcBar, NULL);
SelectClipRgn(hdc, NULL);
DeleteObject(hRgn);

if (bSmooth)
{
rcChunk = rcContent;
rcChunk.right = iProgress;
DrawThemeBackground(hTheme, hdc, PP_CHUNK, 0, &rcChunk, NULL);

int progressPercentage = (trackprog > 100) ? 100 : ((trackprog < 0) ? 0 : trackprog);

WCHAR szProgressText[5];
wsprintf(szProgressText, L"%d%%", progressPercentage);

SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0, 0, 0)); // Set text color to black
DrawText(hdc, szProgressText, -1, rcBar, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

}
else
{
int nChunkSize = 6, nSpaceSize = 2;
GetThemeMetric(hTheme, hdc, PP_BAR, 0, TMT_PROGRESSCHUNKSIZE, &nChunkSize);
GetThemeMetric(hTheme, hdc, PP_BAR, 0, TMT_PROGRESSSPACESIZE, &nSpaceSize);
rcChunk = rcContent;
rcChunk.right = rcChunk.left;
while (rcChunk.left < iProgress)
{
rcChunk.right = min(rcChunk.left + nChunkSize, rcContent.right);
DrawThemeBackground(hTheme, hdc, PP_CHUNK, 0, &rcChunk, NULL);
rcChunk.left = min(rcChunk.right + nSpaceSize, rcContent.right);
}
}
}

(https://i.ibb.co/BZS3p9x/drawpercentage.jpg)
Title: Re: ListView Progressbar
Post by: frankie on October 20, 2023, 11:10:25 AM
To use the modified code, with progress percentage, in an ANSI project simply change the functions wsprintf to wsprintfW, and DrawText to DrawTextW, as in the amended following code:
Code: [Select]
void DrawProgressBar(HTHEME hTheme, HDC hdc, LPRECT rcBar, BOOL bSmooth, INT iProgress)
{
RECT rcContent, rcChunk;

int trackprog = iProgress;
GetThemeBackgroundContentRect(hTheme, hdc, PP_BAR, 0, rcBar, &rcContent);
iProgress = rcContent.left + (int)((rcContent.right - rcContent.left) * ((float)max(min(iProgress, 100), 0) / 100.0f));

int ellipse_width_height = 0, ellipse_height = 0;
HRGN hRgn = CreateRoundRectRgn(rcBar->left, rcBar->top, rcBar->right + 1, rcBar->bottom + 1, ellipse_width_height, ellipse_height);
SelectClipRgn(hdc, hRgn);
DrawThemeBackground(hTheme, hdc, PP_BAR, 0, rcBar, NULL);
SelectClipRgn(hdc, NULL);
DeleteObject(hRgn);

int progressPercentage = (trackprog > 100) ? 100 : ((trackprog < 0) ? 0 : trackprog);
WCHAR szProgressText[5];
wsprintfW(szProgressText, L"%d%%", progressPercentage);
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0, 0, 0));  // Set text color to black

if (bSmooth)
{
rcChunk       = rcContent;
rcChunk.right = iProgress;
DrawThemeBackground(hTheme, hdc, PP_CHUNK, 0, &rcChunk, NULL);
}
else
{
int nChunkSize = 6, nSpaceSize = 2;
GetThemeMetric(hTheme, hdc, PP_BAR, 0, TMT_PROGRESSCHUNKSIZE, &nChunkSize);
GetThemeMetric(hTheme, hdc, PP_BAR, 0, TMT_PROGRESSSPACESIZE, &nSpaceSize);
rcChunk       = rcContent;
rcChunk.right = rcChunk.left;
while (rcChunk.left < iProgress)
{
rcChunk.right = min(rcChunk.left + nChunkSize, rcContent.right);
DrawThemeBackground(hTheme, hdc, PP_CHUNK, 0, &rcChunk, NULL);
rcChunk.left  = min(rcChunk.right + nSpaceSize, rcContent.right);
}
}

DrawTextW(hdc, szProgressText, -1, rcBar, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}

EDIT: Modified code to write percentage for both styles (smoothed or not).
Title: Re: ListView Progressbar
Post by: John Z on October 20, 2023, 12:14:19 PM
As I supposed the problem is the filtering to notification messages from the dialog window procedure.
Subclassing the dialog window solves the problem.  8)

Thank you frankie!  Great example in subclassing and code style as well.  :)

John Z
Title: Re: ListView Progressbar
Post by: WiiLF23 on October 20, 2023, 09:04:07 PM
Good work guys! I am now working on 2 functions to add item / update row progressbar by index.
Title: Re: ListView Progressbar
Post by: frankie on October 22, 2023, 09:45:12 PM
I made a general list view progress bar control here (https://forum.pellesc.de/index.php?topic=11012.msg38485#msg38485).
Title: Re: ListView Progressbar
Post by: WiiLF23 on October 23, 2023, 12:47:24 AM
Looks good thanks! I have a full complete implementation allowing me to add row with custom subitem strings (6 col), and another to update progress on the fly (like a download progress counter) by index. Works flawlessly.

Its on to treeview from here ;) - I will be contributing all my learning from this separately
Title: Re: ListView Progressbar
Post by: WiiLF23 on November 29, 2023, 07:33:43 AM
If anyone wants to play with another way, which in my project this paints directly and allows a lot more to customize.

Taken from:
https://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization

Title: Re: ListView Progressbar
Post by: John Z on November 29, 2023, 10:52:26 AM
Good work, nice visual.

John Z

P.S. When you come back to this code in 10 years having at least a few comments might be appreciated  :)
just a suggestion ......  ;)
Title: Re: ListView Progressbar
Post by: John Z on November 29, 2023, 01:45:08 PM
Hi WiiLF23,

You did such a good job with your ListView ProgressBar I could not help myself but to tweak it a bit - sorry...

It was ready to be UNICODE with all the work that you did so I 'finished' it with minor changes to be UNICODE when:
#define UNICODE
#define _UNICODE
are included.

Without the two defines then it is in the original ANSI :)


Also add a bit of flexibility to color the 4 defined states text easier without changing the base routine.

Could also be interesting to color the progress bar the same as the text (but I've not done that  ;))

John Z

Title: Re: ListView Progressbar
Post by: WiiLF23 on December 03, 2023, 06:40:22 AM
You would be shocked what I have done with Pelles C. I cant thank this compiler/IDE enough! I completely removed the entire Visual Studio stack just days ago, this is a dedicated C dev machine now. WinAPI and we are clear sailing! Boy am I glad I put a torch to the .NET installations, never again.

Just so some of you see what can be done with attached progress code (I'm using the same code).

(https://i.postimg.cc/NFc70DKV/Fall-Update.jpg)

@John Z

"Without the two defines then it is in the original ANSI" - that makes complete sense! While im dealing a fair bit of narrow/wide conversion between server DLL and the application itself. That is very helpful, thank you.

"Could also be interesting to color the progress bar the same as the text" - I was at this for about 15 minutes going through different color ranges for visual appeal (I've been building complete websites for 21 years) so its easy for me and I get very anal on even a pixel out in my presentation. It came down to

100: RGB(255, 255, 255)
<100: RGB(36, 36, 36)

It was a tough call as I would prefer white progress text the entire time, but it just doesnt look good (I'm on a 2003 19" widescreen TFT). High resolution pictures of the app on the iPad looks amazing (deep pixel density), so I just go off of that after a day of UI updates so I know it looks good.

Realistically, I have plans to draw within the progressbar and inherit the design pattern of Windows8+ file copy dialog. I wish the GDI control on that was open source, but the drawing procedures are likely buried deep in the operating system, if not entirely unavailable. I see it on Task Manager too, so its clearly in the operating system.

So that within the progress (measuring speeds within) would be a heck of an accomplishment. If I can pull it off, I'll put it on here and you guys can review the code.


Title: Re: ListView Progressbar
Post by: Vortex on December 03, 2023, 10:51:23 AM
Hi WiiLF23,

Quote
I completely removed the entire Visual Studio stack just days ago.

You did well. The VS IDE is a monster consuming a lot of resources.
Title: Re: ListView Progressbar
Post by: John Z on December 03, 2023, 03:20:32 PM
Hi WiiLF23,

Looks nice, good aesthetics,

It was a tough call as I would prefer white progress text the entire time, ....
  Yup, I find a white font color really limits the background color range. Personally I prefer a dark grey background (128,128,128) when using a white font.

John Z