CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 2 of 2
  1. #1
    Join Date
    Sep 2022
    Posts
    3

    How to create custom trackbar control appearance(channel,thumb) using Custom Draw?

    Hello,

    I will state that I am a beginner in WIN32 programming and want to make custom drawing trackbar channel and thumb but without using MFC library, i.e. only with pure WIN32 in C/C++.

    According to Customizing the Appearance of CSliderCtrl Using Custom Draw found on CodeProject:
    https://www.codeproject.com/Articles...rCtrl-Using-Cu

    which unfortunately is using MFC besides the fact it is very well documented. I have searched everywhere and must admit did not find any other solution to this problem. Therefore, I am asking for your willingness to post a simple code example on how to custom draw a trackbar thumb with a dialog and the trackbar would be enough just to understand on how it is done in pure WIN32 by not using MFC.

    Just to state that I have done this by using a bitmap as a resource for only changing the appearance of the thumb of the trackbar, and have no idea on how to custom draw it:

    Code:
    #pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
    
    #include <string>
    #include <Windows.h>
    #include <CommCtrl.h>
    
    using namespace std;
    
    HWND window = nullptr;
    HWND trackBar = nullptr;
    HWND progressBar = nullptr;
    HWND staticText = nullptr;
    WNDPROC defWndProc = nullptr;
    
    static HBITMAP hBitmapThumb, hBitmapBar;
    static BITMAP bm;
    
    LRESULT OnWindowClose(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    	PostQuitMessage(0);
    	return CallWindowProc(defWndProc, hwnd, message, wParam, lParam);
    }
    
    LRESULT OnTrackBarChanged(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    	LRESULT value = SendMessage(trackBar, TBM_GETPOS, 0, 0);
    	SendMessage(progressBar, PBM_SETPOS, value, 0);
    	SendMessage(staticText, WM_SETTEXT, 0, (LPARAM)to_wstring(value).c_str());
    	return CallWindowProc(defWndProc, hwnd, message, wParam, lParam);
    }
    
    void DrawBitmapTransparent(HDC hDCDest, int nXDest, int nYDest, int nBitmapWidth, int nBitmapHeight, HBITMAP hBitmap, int nXSrc, int nYSrc, int nTransparentColor)
    {
    	HDC hDCSrc;
    	HBITMAP hBitmapOld;
    	HDC hDCMask;
    	HBITMAP hBitmapMask;
    	HBITMAP hBitmapMaskOld;
    	HDC hDCMem;
    	HBITMAP hBitmapMem;
    	HBITMAP hBitmapMemOld;
    	int nBkColorOld;
    	int nTextColorOld;
    	BITMAP bm;
    
    	GetObject( hBitmap, sizeof( BITMAP ), &bm );
    
    	if (!nBitmapWidth) {
    		nBitmapWidth = bm.bmWidth;
    	}
    
    	if (!nBitmapHeight) {
    		nBitmapHeight = bm.bmHeight;
    	}
    
    	hDCSrc = CreateCompatibleDC( hDCDest );
    	hBitmapOld = (HBITMAP)SelectObject( hDCSrc, hBitmap );
    	hDCMask = CreateCompatibleDC( hDCDest );
    	hBitmapMask = CreateBitmap( nBitmapWidth, nBitmapHeight, 1, 1, 0 );
    	hBitmapMaskOld = (HBITMAP)SelectObject( hDCMask, hBitmapMask );
    	hDCMem = CreateCompatibleDC( hDCDest );
    	hBitmapMem = CreateCompatibleBitmap( hDCDest, nBitmapWidth,	nBitmapHeight );
    	hBitmapMemOld = (HBITMAP)SelectObject( hDCMem, hBitmapMem );
    	nBkColorOld = SetBkColor( hDCSrc, nTransparentColor );
    	BitBlt( hDCMask, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCCOPY );
    	SetBkColor( hDCSrc, nBkColorOld );
    	nBkColorOld = SetBkColor( hDCDest, RGB(255,255,255) );
    	nTextColorOld = SetTextColor( hDCDest, RGB(0,0,0) );
    	BitBlt( hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCDest, nXDest, nYDest, SRCCOPY );
    	BitBlt( hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCINVERT );
    	BitBlt( hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCMask, 0, 0, SRCAND );
    	BitBlt( hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCINVERT );
    	BitBlt( hDCDest, nXDest, nYDest, nBitmapWidth, nBitmapHeight, hDCMem, 0, 0, SRCCOPY );
    	SetBkColor( hDCDest, nBkColorOld );
    	SetTextColor( hDCDest, nTextColorOld );
    	SelectObject( hDCMem, hBitmapMemOld );
    	DeleteDC( hDCMem );
    	DeleteObject( hBitmapMem );
    	SelectObject( hDCMask, hBitmapMaskOld );
    	DeleteDC( hDCMask );
    	DeleteObject( hBitmapMask );
    	SelectObject( hDCSrc, hBitmapOld );
    	DeleteDC( hDCSrc );
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    	switch(message) {
    		case WM_NOTIFY:
    		{
    			LPNMHDR lpNmhdr = (LPNMHDR)lParam;
    			if (lpNmhdr->code == NM_CUSTOMDRAW)
    			{
    				LPNMCUSTOMDRAW lpNMCustomDraw = (LPNMCUSTOMDRAW)lParam;
    
    				if (lpNMCustomDraw->dwDrawStage == CDDS_PREPAINT) {
    					return CDRF_NOTIFYITEMDRAW;
    				}
    
    				else if (lpNMCustomDraw->dwDrawStage == CDDS_ITEMPREPAINT)
    				{
    					long nLeft = lpNMCustomDraw->rc.left;
    					long nTop = lpNMCustomDraw->rc.top;
    					long nRight = lpNMCustomDraw->rc.right;
    					long nBottom = lpNMCustomDraw->rc.bottom;
    
    					if (lpNMCustomDraw->dwItemSpec == TBCD_THUMB && hBitmapThumb)
    					{
    						long nWidth = nRight - nLeft;
    						long nHeight = nBottom - nTop;
    
    						if (nWidth - bm.bmWidth > 0)
    						{
    							nLeft += (nWidth - bm.bmWidth)/2;
    							nWidth = bm.bmWidth;
    						}
    
    						if (nHeight - bm.bmHeight > 0)
    						{
    							nTop += (nHeight - bm.bmHeight)/2;
    							nHeight = bm.bmHeight;
    						}
    
    						DrawBitmapTransparent(lpNMCustomDraw->hdc , nLeft, nTop, nWidth, nHeight, hBitmapThumb, 0, 0, RGB( 255, 0, 255 ));
    
    						return CDRF_SKIPDEFAULT;
    					}
    				}
    			}
    		}
    		break;
    	}
    	if (message == WM_CLOSE && hwnd == window) return OnWindowClose(hwnd, message, wParam, lParam);
    	if (message == WM_HSCROLL && hwnd == window && (HWND)lParam == trackBar) return OnTrackBarChanged(hwnd, message, wParam, lParam);
    	return CallWindowProc(defWndProc, hwnd, message, wParam, lParam);
    }
    
    int main() {
    	window = CreateWindowEx(0, WC_DIALOG, L"TrackBar example", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, nullptr, nullptr, nullptr, nullptr);
    	trackBar = CreateWindowEx(0, TRACKBAR_CLASS, nullptr, WS_CHILD | TBS_HORZ | TBS_BOTTOM | WS_VISIBLE | TBS_FIXEDLENGTH, 150, 10, 250, 70, window, nullptr, nullptr, nullptr);
    	progressBar = CreateWindowEx(0, PROGRESS_CLASS, nullptr, WS_CHILD | PBS_SMOOTH | WS_VISIBLE, 20, 100, 200, 23, window, nullptr, nullptr, nullptr);
    	staticText = CreateWindowEx(0, WC_STATIC, L"100", WS_CHILD | WS_VISIBLE, 20, 150, 100, 23, window, nullptr, nullptr, nullptr);
    
    	defWndProc = (WNDPROC)SetWindowLongPtr(window, GWLP_WNDPROC, (LONG_PTR)WndProc);
    
    	// hBitmapThumb = reinterpret_cast<HBITMAP>(LoadImage(NULL, reinterpret_cast<LPCWSTR>("pink.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
    	hBitmapThumb = (HBITMAP)LoadImage(NULL, (LPCWSTR)L"c:\\Temp\\pink.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    	GetObject( hBitmapThumb, sizeof( BITMAP ), &bm );
    
    	SendMessage(trackBar, TBM_SETRANGEMIN, 1, 0);
    	SendMessage(trackBar, TBM_SETRANGEMAX, 1, 200);
    	SendMessage(trackBar, TBM_SETTHUMBLENGTH, bm.bmWidth/7, 100);
    	SendMessage(progressBar, PBM_SETRANGE32, 0, 200);
    	SendMessage(progressBar, PBM_SETPOS, 100, 0);
    
    	ShowWindow(window, SW_SHOW);
    
    	MSG message = { 0 };
    	while (GetMessage(&message, nullptr, 0, 0))
    	DispatchMessage(&message);
    }
    I am very thankful to anyone who participates towards solving my problem.

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: How to create custom trackbar control appearance(channel,thumb) using Custom Draw

    Well, MFC is just a wrapper around the plain Win32 API. So you could slightly modify the code from https://www.codeproject.com/Articles...rCtrl-Using-Cu removing the MFC parts and/or change it to raw Win32.
    For instance the code in
    Code:
     void CCustomDrawSliderCtrl::OnReflectedCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
    after some changes you could place in your CALLBACK WndProc under the case of
    Code:
    if (lpNmhdr->code == NM_CUSTOMDRAW)
    Victor Nijegorodov

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured