【问题标题】:C++ Win32 Static Control Transparent BackgroundC++ Win32 静态控件透明背景
【发布时间】:2014-06-19 22:10:28
【问题描述】:

解决方案:如下所述,最好为文本创建自己的方法,而不是试图让控件表现异常。因此,最好为此创建一个自定义控件。我找到了一个解释这一切的教程:http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win-API-The-Basics

这已经被问过了,但没有实际的解决方案。

我正在尝试使用静态控件来显示文本,因此更新就像发送消息一样简单。我可以很容易地刮擦控件并使用普通的 DrawText() ,但这似乎是一个“草率”的解决方案。

这是所有者的绘制方法。

else if (message == WM_DRAWITEM) {  
    LPDRAWITEMSTRUCT pDIS;
    pDIS = (LPDRAWITEMSTRUCT)lParam;
    RECT rc;

    SetTextColor(pDIS->hDC, RGB(200,10,60));
    SelectObject(pDIS->hDC, (HPEN)GetStockObject(NULL_PEN));
    SelectObject(pDIS->hDC, (HBRUSH)GetStockObject(NULL_BRUSH));
    SetBkMode(pDIS->hDC, TRANSPARENT);
    // Start Drawing
    Rectangle(pDIS->hDC, 0, 0, pDIS->rcItem.right+1, pDIS->rcItem.bottom+1);
    DrawText(pDIS->hDC, "teststring", 10, &pDIS->rcItem, 0); 

    return 0;
}

我得到:

左边是我得到的,右边是我想要的。

CreateWindow("STATIC", "teststring", WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, 20, 20, 120, 40, hwnd, (HMENU)(IDC_STATIC_TEST), GetModuleHandle(NULL), NULL);   

这就是我用来创建静态的。

我花了 4 个多小时断断续续地尝试这样做,我尝试了一切

感谢任何帮助。

忘记静态控件并仅使用 DrawText() 会更好吗?

谢谢。

// create window
hwnd = CreateWindowEx (0, szClassName, "Test Transparent Static Main Window", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX , 100, 100, 300, 200, HWND_DESKTOP, NULL, hThisInstance, NULL);         
ShowWindow (hwnd, nFunsterStil);
// set globals
hWnd = hwnd;
hInstance = hThisInstance;

// main window message loop
while (GetMessage (&messages, NULL, 0, 0)) {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
}
return messages.wParam;
}






// Main Window Procedure
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
// local variables
PAINTSTRUCT ps;
HDC hdc;    


switch (message) {

    case WM_CREATE:   
        {     
        LRESULT lRes = DefWindowProc(hwnd, message, wParam, lParam);
        HWND hWndStatic = CreateWindowEx(0, "Static", NULL, WS_CHILD | WS_VISIBLE, 10, 10, 200, 100, hwnd, NULL, hInstance, NULL);
        StaticWndProc = (WNDPROC)SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)MyStaticWndProc);
        return lRes;            
        }
        break;

    case WM_PAINT: 
        hdc = BeginPaint(hwnd, &ps); 
        SetBkMode(hdc, TRANSPARENT);
        SetBkColor(hdc, RGB(110,110,110));
        EndPaint(hwnd, &ps);
        break;

   case WM_DESTROY:
        PostQuitMessage(0);       
        break;

    default:  
        return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}







LRESULT CALLBACK MyStaticWndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)     {   

if (Message == WM_PAINT) {   
    RECT rc;
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);

    GetClientRect(hwnd, &rc);
    SetBkMode(hdc, TRANSPARENT);
    SetTextColor(hdc, RGB(0,100,200));
    DrawText(hdc, "TESTTEXT", 8, &rc, DT_CENTER | DT_VCENTER | SS_LEFT);

    EndPaint(hwnd, &ps);

    return 0;
}

return StaticWndProc(hwnd, Message, wparam, lparam);
}

---------编辑-------------------------- --------------------

【问题讨论】:

  • 只需注册自己的窗口类,自己绘制文字即可。试图将非默认行为硬塞到系统类中通常是一种挫败感,在这种特殊情况下,简单地自己动手是微不足道的。
  • WS_CLIPCHILDREN 搞砸了,因为它阻止父窗口在子控件占用的区域中绘图。这与您的目标适得其反:让父控件在透明的子控件下方绘制其背景。
  • 我同意@CodyGray,替代方案(每个孩子都需要访问并绘制主窗口背景图片的一部分)很繁琐,尤其是当您调整主窗口大小和/或移动子控件

标签: c++ winapi static controls


【解决方案1】:

无需进行Owner Draw,只需使用SetWindowText()处理WM_CTLCOLORSTATIC消息即可,参见this SO Answer中的代码

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{   MSG msg;
    WNDCLASS w;

    hInst = hInstance;
    memset(&w,0,sizeof(WNDCLASS));
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.lpfnWndProc = WndProc;
    w.hInstance = hInst;
    w.hbrBackground = CreateHatchBrush(HS_DIAGCROSS, RGB(255, 0, 0));
    w.lpszClassName = L"My Class";
    w.hCursor = LoadCursor(NULL, IDC_ARROW); 
    RegisterClass(&w);

    HWND hWndWindow = CreateWindow(L"My Class", L"My title", WS_OVERLAPPEDWINDOW, 300, 200, 800, 600, NULL, NULL, hInst, NULL);

    ShowWindow(hWndWindow, nCmdShow);
    UpdateWindow(hWndWindow);

    while(GetMessage(&msg, NULL, 0, 0))
    {   TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    DeleteObject(w.hbrBackground);

    return msg.wParam;
}

WNDPROC StaticWndProc = NULL;
TCHAR szText[] = _T("TestString");

LRESULT CALLBACK MyStaticWndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{   if (Message == WM_PAINT)
    {   RECT rc;
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rc);
        SetBkMode(hdc, TRANSPARENT);
        DrawText(hdc, szText, _tcslen(szText), &rc, DT_CENTER | DT_VCENTER);
        EndPaint(hwnd, &ps);
        return 0;
    }

      //v2 StaticWndProc(hwnd, Message, wparam, lparam);
    return CallWindowProc(StaticWndProc, hwnd, Message, wparam, lparam); //v2
}

HWND hWndStatic; //v2
LONG WINAPI WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam)
{   switch (Message)
    {   case WM_CREATE:
        {   LRESULT lRes = DefWindowProc(hwnd, Message, wparam, lparam);
            hWndStatic = CreateWindowEx(0, L"Static", NULL, WS_CHILD| WS_VISIBLE |SS_LEFT, 10, 130, 200, 40, hwnd, NULL, hInst, NULL); //v2 deleted HWND
            StaticWndProc = (WNDPROC) SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)MyStaticWndProc);
            return lRes;
        }

        case WM_DESTROY: 
            SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)StaticWndProc); //v2
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, Message, wparam, lparam);
    }

    return 0;
}

【讨论】:

  • 在 Windows 8 之前无法让子窗口真正透明。解决方案是先将底层背景图像绘制到您的子窗口中,然后再在其上渲染文本。
  • 处理WM_CTLCOLORSTATIC 就可以了。您只需返回用于绘制窗口背景的相同图案画笔。您可能还需要致电SetBrushOrgEx
  • 除此之外,@Edward,您在此处显示的用于子类化控件的代码不正确。我应该早就注意到了,但我没有仔细看。有两件事立即向我扑来。首先,您不会在控件被销毁之前删除子类。当你继承子类时,这成为你的义务:自己清理。其次,您没有使用 CallWindowProc 函数,就像文档中说的那样,您需要这样做。你不应该直接调用proc。关于子类化的文档是here
  • @CodyGray 你说的很对,感谢你的 cmets!我已经编辑了我的代码(标有//v2
  • @EvanCarslake,我还是很困惑,你现在是不是要切换到纯色背景色并使用WM_CTLCOLORSTATIC?在这种情况下,即使WS_CLIPCHILDREN 包含在父窗口样式中,答案顶部的删除链接中的代码也有效
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多