1. 程式人生 > >windows api實現視窗、按鈕、靜態文字框透明顯示

windows api實現視窗、按鈕、靜態文字框透明顯示

1.需求

(1)實現一個無邊框的視窗,不需要視窗能夠拖動,不需要放大縮小按鈕,但是需要右上角的關閉按鈕;

(2)靜態文字框背景透明,顯示的文字能夠頻繁重新整理並且不能夠有重影;

2.實現方式

2.1無邊框視窗

實現去除邊框是在視窗過程函式的WM_SIZE訊息處理時實現的。

case WM_SIZE:
    {
        LONG_PTR Style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
        Style = Style & ~WS_CAPTION &~WS_SYSMENU &~WS_SIZEBOX;
        ::SetWindowLongPtr(hWnd, GWL_STYLE, Style);
        return 0;
    }
如果在建立視窗時直接設定去除這些屬性,會導致視窗頂部的標題欄無法徹底去除,雖然不顯示左上角的圖示和右上角的放大縮小按鈕,但是標題欄仍然存在。

2.2關閉按鈕

“關閉”按鈕沒有采用windows預設提供的,自己建立了一個按鈕,載入了帶"x"的icon實現。之前嘗試遮蔽“放大”和“縮小”按鈕來實現,但是隻能使之失效無法消失不見,所以選擇自己建立按鈕。

這一功能的實現有兩個重要步驟,一是載入icon圖片;二是對關閉訊息的響應。

(1)載入icon圖片

HANDLE close_icon = LoadImage(NULL, L"close_button.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
    if (close_icon == NULL) {
        int error_code = GetLastError();
        return;
    }
    SendMessage(close_button_, BM_SETIMAGE, IMAGE_ICON, (LPARAM)close_icon);

在除錯過程中,出現1813的錯誤碼,問題的原因是將LoadImage的最後一個引數設定為LR_DEFAULTCOLOR,改為LR_LOADFROMFILE即可正常載入。

(2)響應關閉訊息

在父視窗的視窗過程函式中,增加對如下命令的響應。

case WM_COMMAND:
        if ((HWND)lParam == close_hwnd_)
        {
            ::SendMessage(parent_hwnd_, WM_CLOSE, 0, 0);
        }
        return 0;

2.3靜態文字框背景透明

實現這個功能需要在兩處新增程式碼:一是靜態文字框建立完成的時候,需要增加一個透明的屬性;二是在視窗的過程函式中增加對WM_CTLCOLORSTATIC

訊息的處理。

(1)增加透明屬性

    LONG nRet = ::GetWindowLong(progress_handle_, GWL_EXSTYLE);
    nRet = nRet | WS_EX_TRANSPARENT;
    ::SetWindowLong(progress_handle_, GWL_EXSTYLE, nRet);

(2)處理WM_CTLCOLORSTATIC訊息

在父視窗的視窗過程函式中,增加對如下命令的響應。

case WM_CTLCOLORSTATIC:
        hDC = (HDC)wParam;
        SetTextColor(hDC, RGB(0, 0, 0));
        SetBkMode(hDC, TRANSPARENT);
        //break;
        return (LRESULT)GetStockObject(NULL_BRUSH);   
在這裡如果返回一個非空畫刷,也就是這裡break,而不是後面的return空畫刷,無法實現靜態文字控制元件透明,至少我的實踐效果是這樣。

2.4文字重新整理重影

在靜態文字框背景透明的情況下,如果重新整理靜態文字框的文字,會出現重影現象,以下程式碼在我的機器上可以解決重影問題。

void ProgressControl::OnStartButtonPressed() const
{
    ::SetWindowPos(progress_handle_, HWND_TOPMOST, 0, 0,
        0, 0, SWP_NOMOVE | SWP_NOSIZE);

    ::SendMessage(parent_handle_, WM_CTLCOLORSTATIC, 0, 0);
    SetWindowText(progress_handle_, L"1%");
    ::ShowWindow(progress_handle_, 1);
    for (int i = 1; i < 97;)
    {
        i += rand() % 4;
        wchar_t buffer[10];
        _itow_s(i, buffer, 10, 10);
        std::wstring progress(buffer);
        progress += L"%";

        SetWindowText(progress_handle_, progress.c_str());
        ::ShowWindow(progress_handle_, 1);

        ::InvalidateRect(parent_handle_, NULL, TRUE);
        ::UpdateWindow(parent_handle_);
        Sleep(100);
    }
}

注意:InvalidateRectUpdateWindow中給出的控制代碼一定是父視窗的,而不是靜態文字控制元件的,否則會出現文字重新整理顯示時的重影問題。