Win32 API:透明度不起作用

时间:2014-01-31 03:11:49

标签: c++ winapi transparency

我写了一个简单的程序;它由一个主窗口和上面的TextBox窗口组成。 TextBox是50%透明的。当TextBox收到消息时,它会在主窗口上绘制一条蓝线。

问题是“透明”实际上根本不透明。如果蓝线穿过TextBox中的文本,则文本刚刚删除,尽管文本在上面。反之亦然:如果我开始输入,文本行中的一部分行就会消失而不是闪耀。 这是一个错误吗?或者我错过了什么?

#include <windows.h>
#include <stdio.h>

#define IDC_MAIN_EDIT 101

void DrawInWindow(HWND hWndToPaint){
    HDC hdc = GetDC(hWndToPaint);
    if(!hdc)printf("Invalid handle\n");
    HPEN hPen = CreatePen(PS_SOLID,5,RGB(0, 0, 255));
    SelectObject(hdc, hPen);
    static float x=620, y=1, tg=0.5, ctg=2;
    static int Xone = 1, Yone = 1;//depending on later recalculation this may become negative
    MoveToEx(hdc,(int)x,(int)y,NULL);
    if(tg<1){
        y+=tg;
        x+=Xone;
    }else{
        y+=Yone;
        x+=ctg;
    }
    if(!LineTo(hdc, (int)x, (int)y) )printf("There are paint problem\n");
    ReleaseDC(hWndToPaint,hdc);
    //Now recalculate direction
    RECT WndRect;
    GetClientRect(hWndToPaint,&WndRect);
    if(x>=WndRect.right){
        if(ctg>0)ctg*=-1;//make negative
        Xone=-1;
    }
    if(x<=WndRect.left){
        if(ctg<0)ctg*=-1;//make positive
        Xone=1;
    }
    if(y>=WndRect.bottom){
        if(tg>0)tg*=-1;//make negative
        Yone=-1;
    }
    if(y<=WndRect.top){
        if(tg<0)tg*=-1;//make positive
        Yone=1;
    }
}

int CALLBACK EnumWindowsFunc(HWND hWnd, LPARAM lParam){
    DrawInWindow(hWnd);
    return false;
}
void PaintInMainWnd(){
    EnumWindows(EnumWindowsFunc,0L);//Getting the handle of main window to draw
}
LRESULT __stdcall MyMainCallBckProcedure( HWND window, unsigned msg, WPARAM wp, LPARAM lp ){
    switch(msg){
        case WM_KEYDOWN:
            if(wp == VK_ESCAPE)PostQuitMessage(0);
            break;
        case WM_DESTROY:
            printf("\ndestroying window\n");
            PostQuitMessage(0);
            return 0;
        case WM_SIZE:{
            HWND hEdit;
            RECT rcClient;

            GetClientRect(window, &rcClient);
            hEdit = GetDlgItem(window, IDC_MAIN_EDIT);
            SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
            break;
        }
        default:
            return DefWindowProc( window, msg, wp, lp ) ;
    }
}

WNDPROC lpEditWndProc;

LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
    {
        PostQuitMessage(0);
        return 0;
    }
    PaintInMainWnd();
    lpEditWndProc(hWnd, uMsg, wParam, lParam);
}

bool CreateWindows(){
    const char* const myclass = "myclass";
    WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, MyMainCallBckProcedure,
                            0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
                            LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW+1),
                            0, myclass, LoadIcon(0,IDI_APPLICATION) };
    if(RegisterClassEx(&wndclass)<0){
        printf("ERR: in registering window class\n");
        return false;
    }
    //Creating window
    HWND window = CreateWindowEx( 0, myclass, "title",
                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                   640, 480, 0, 0, GetModuleHandle(0), 0 );
    if(!window){
        printf("ERR: in creating window\n");
        return false;
    }
    ShowWindow( window, SW_SHOWDEFAULT );
    //creating TextBox on the window
    HFONT hfDefault;
    HWND hEdit;
    hEdit = CreateWindowEx(0, "edit", "", 
        WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        window, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL);
    if(hEdit == NULL){
        MessageBox(window, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
        return false;
    }
    hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
    //Now resize TextBox to fill whole parent window
    RECT RectSize;
    GetClientRect(window,&RectSize);
    hEdit = GetDlgItem(window,IDC_MAIN_EDIT);
    SetWindowPos(hEdit, 0,0,0,RectSize.right,RectSize.bottom,SWP_NOZORDER);
    //Let's try to catch some messages in TextBox...
    lpEditWndProc = (WNDPROC)SetWindowLongPtr(hEdit, GWL_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
    //Making hEdit transparent
    SetWindowLongPtr(hEdit,GWL_EXSTYLE, WS_EX_LAYERED | GetWindowLongPtr(hEdit, GWL_EXSTYLE) );
    SetLayeredWindowAttributes(hEdit, 0, (255*50)/100, LWA_ALPHA);
    return true;
    //###
}

int main(){
    if(!CreateWindows() ){printf("Something gone wrong\n");return 1;}
    MSG msg;
    while(GetMessage(&msg,0,0,0) ){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

不知道它是否重要,但我还应该提一下,我只在Ubuntu下用Wine测试过,因为我的Windows被this bug搞砸了。无论如何,我希望问题不在于Wine本身。 抱歉代码量很多,我真的不知道要删除什么来缩小代码。

1 个答案:

答案 0 :(得分:2)

我找到了解决方法。我创建了背景顶级窗口,并使前景窗口变为50%trasparent。我在背景窗口画线。如果前窗移动或调整大小,后窗会在WM_WINDOWPOSCHANGED消息的帮助下作出相应的反应,它会在每次移动/调整大小时发送。

无论如何,这个解决方法有点脏,因为: Linux / wine 具体问题:1)显示管理器不装饰 wine 的透明窗口(但这可以通过使第二个窗口0%透明来避免)2)拖动窗口摇摆,但第二次直行。所有操作系统特定问题:第二个窗口在任务栏中可见。从理论上讲,可以通过将WS_EX_TOOLWINDOW添加到无主窗口来避免最后一次。 The quote

  

要阻止窗口按钮放在任务栏上,请创建   具有WS_EX_TOOLWINDOW扩展样式的无主窗口。

但是,至少,在 wine 中,它不起作用。好吧,我希望这是一个错误:)

#include <windows.h>
#include <stdio.h>

#define IDC_MAIN_EDIT 101

HWND hBackWnd;

void DrawInWindow(HWND hWndToPaint){
    HDC hdc = GetDC(hWndToPaint);
    if(!hdc)printf("Invalid handle\n");
    HPEN hPen = CreatePen(PS_SOLID,5,RGB(0, 0, 255));
    SelectObject(hdc, hPen);
    static float x=620, y=1, tg=0.5, ctg=2;
    static int Xone = 1, Yone = 1;//depending on later recalculation this may become negative
    MoveToEx(hdc,(int)x,(int)y,NULL);
    if(tg<1){
        y+=tg;
        x+=Xone;
    }else{
        y+=Yone;
        x+=ctg;
    }
    if(!LineTo(hdc, (int)x, (int)y) )printf("There are paint problem\n");
    ReleaseDC(hWndToPaint,hdc);
    //Now recalculate direction
    RECT WndRect;
    GetClientRect(hWndToPaint,&WndRect);
    if(x>=WndRect.right){
        if(ctg>0)ctg*=-1;//make negative
        Xone=-1;
    }
    if(x<=WndRect.left){
        if(ctg<0)ctg*=-1;//make positive
        Xone=1;
    }
    if(y>=WndRect.bottom){
        if(tg>0)tg*=-1;//make negative
        Yone=-1;
    }
    if(y<=WndRect.top){
        if(tg<0)tg*=-1;//make positive
        Yone=1;
    }
}

LRESULT __stdcall MyMainCallBckProcedure( HWND window, unsigned msg, WPARAM wp, LPARAM lp ){
    switch(msg){
        case WM_KEYDOWN:
            if(wp == VK_ESCAPE)PostQuitMessage(0);
            break;
        case WM_DESTROY:
            printf("\ndestroying window\n");
            PostQuitMessage(0);
            return 0;
        case WM_SIZE:
            HWND hEdit;
            RECT rcClient;

            GetClientRect(window, &rcClient);
            hEdit = GetDlgItem(window, IDC_MAIN_EDIT);
            SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
            break;
        case WM_WINDOWPOSCHANGED:{//LPARAM is a ptr to WINDOWPOS
            RECT BckWndRect;
            if(!GetWindowRect(hBackWnd, &BckWndRect) )printf("ERR: getting backwnd rectangle\n");
            bool IsRepaint;
            WINDOWPOS* pNewPos = (WINDOWPOS*)lp;
            if(BckWndRect.left+BckWndRect.right != pNewPos->cx
            || BckWndRect.top+BckWndRect.bottom != pNewPos->cy)IsRepaint = true;
            else IsRepaint = false;
            MoveWindow(hBackWnd, pNewPos->x, pNewPos->y, pNewPos->cx, pNewPos->cy, IsRepaint);
            break;
        }
        default:
            return DefWindowProc( window, msg, wp, lp ) ;
    }
}

WNDPROC lpEditWndProc;

LRESULT CALLBACK MyEditCallBckProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    if( (uMsg == WM_CHAR) && (wParam == VK_ESCAPE) )
    {
        PostQuitMessage(0);
        return 0;
    }
    DrawInWindow(hBackWnd);
    lpEditWndProc(hWnd, uMsg, wParam, lParam);
}

bool CreateWindows(){
    //creating back window
    const char* backwnd = "backwnd";
    WNDCLASSEX backwndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, MyMainCallBckProcedure,
                            0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
                            LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW+1),
                            0, backwnd, LoadIcon(0,IDI_APPLICATION) };
    if(RegisterClassEx(&backwndclass)<0){
        printf("ERR: in registering second window class\n");
        return false;
    }
    hBackWnd = CreateWindowEx( 0, backwnd, "title", WS_EX_TOOLWINDOW |
                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                   640, 480, 0, 0, GetModuleHandle(0), 0 );
    if(!hBackWnd){
        printf("ERR: in creating background window\n");
        return false;
    }
    ShowWindow( hBackWnd, SW_SHOWDEFAULT );
    //Creating front window
    const char* const frontwnd = "frontwnd";
    WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS, MyMainCallBckProcedure,
                            0, 0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
                            LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW+1),
                            0, frontwnd, LoadIcon(0,IDI_APPLICATION) };
    if(RegisterClassEx(&wndclass)<0){
        printf("ERR: in registering foreground window class\n");
        return false;
    }
    HWND window = CreateWindowEx( 0, frontwnd, "title",
                   WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                   640, 480, 0, 0, GetModuleHandle(0), 0 );
    if(!window){
        printf("ERR: in creating foreground window\n");
        return false;
    }
    ShowWindow( window, SW_SHOWDEFAULT );
    //creating textbox
    HWND hEdit = CreateWindowEx( 0, "edit", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL 
                                | ES_MULTILINE | ES_AUTOVSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, 640,
                                480, window, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(0), 0 );
    HFONT hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
    SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
    //Let's try to catch some messages in TextBox...
    lpEditWndProc = (WNDPROC)SetWindowLongPtr(hEdit, GWL_WNDPROC, (LONG_PTR)&MyEditCallBckProcedure);
    //Making foreground window transparent
    SetWindowLongPtr(window,GWL_EXSTYLE, WS_EX_LAYERED | GetWindowLongPtr(window, GWL_EXSTYLE) );
    SetLayeredWindowAttributes(window, 0, (255*50)/100, LWA_ALPHA);
    return true;
    //###
}

int main(){
    if(!CreateWindows() ){printf("Something gone wrong\n");return 1;}
    MSG msg;
    while(GetMessage(&msg,0,0,0) ){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}