繁体   English   中英

如何在 C++ 的 win32 中创建自定义 slider 控件?

[英]How to create custom slider control in win32 in C++?

我正在学习 C/C++ 中的 WIN32 API 并且想知道如何使用作为对话框子项的自定义形状的拇指创建自定义滑块/轨迹栏控件。 一个例子对如何做到这一点很有帮助,因为互联网上关于 WIN32 编程的信息非常少,特别是对于自定义您自己的子控件。 请不要发布 MFC 示例。

这是我要完成的代码示例:

#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, reinterpret_cast<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 = reinterpret_cast<HBITMAP>(SelectObject( hDCSrc, hBitmap ));
    hDCMask = CreateCompatibleDC( hDCDest );
    hBitmapMask = CreateBitmap( nBitmapWidth, nBitmapHeight, 1, 1, 0 );
    hBitmapMaskOld = reinterpret_cast<HBITMAP>(SelectObject( hDCMask, hBitmapMask ));
    hDCMem = CreateCompatibleDC( hDCDest );
    hBitmapMem = CreateCompatibleBitmap( hDCDest, nBitmapWidth, nBitmapHeight );
    hBitmapMemOld = reinterpret_cast<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 = reinterpret_cast<LPNMHDR>(lParam);
        if (lpNmhdr->code == NM_CUSTOMDRAW)
        {
            LPNMCUSTOMDRAW lpNMCustomDraw = reinterpret_cast<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 && reinterpret_cast<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 = reinterpret_cast<WNDPROC>(SetWindowLongPtr(window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc)));

    hBitmapThumb = reinterpret_cast<HBITMAP>(LoadImage(NULL, reinterpret_cast<LPCWSTR>("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*2, 0);
    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);
}

在示例中,我试图用 bitmap 图像替换轨迹条拇指,但显然没有发生任何事情,它编译但轨迹条非常小并且没有被图像替换。 请我需要有关如何解决此问题的建议。

我复制/粘贴了您的代码并运行它,也看到了丢失的拇指。 开始追踪,发现hbitmapThumb是null....当然,因为我没有pink.bmp。 我将其更改为从绝对路径加载它..:并注意到您错过了 L :

    hBitmapThumb = reinterpret_cast<HBITMAP>(LoadImage(NULL, reinterpret_cast<LPCWSTR>(L"c:\\users\\me\\Documents\\pink.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));

您可能不需要绝对路径,具体取决于计算机上文件的位置。

但是您绝对需要在引号之前使用 L - 否则您将重新解释将窄字符串转换为宽字符串,这将是无效的文件名!

所以,是的,我认为你做了更难的部分,让自定义绘制等正确,但只是在那里犯了一个 char vs w_char 错误。 让我知道修复 L 是否也为您解决了问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM