2014-01-31 52 views
1

我寫了一個簡單的程序;它由一個主窗口和它上面的TextBox窗口組成。 TextBox是50%透明的。當TextBox獲取消息時,它會在主窗口上繪製一條藍線。Win32 API:透明不起作用

問題是「透明」實際上根本不透明。如果藍線與文本框中的文本交叉,則文本剛剛被刪除,儘管文本位於上方。反之亦然:如果我開始打字,文本行中的一部分行將消失,而不是閃耀。 這是一個錯誤?或者我錯過了什麼?

#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下的測試與葡萄酒,因爲我的Windows由this bug搞砸了。無論如何,我希望這個問題不在Wine本身。 對於大量的代碼抱歉,我真的不知道要刪除什麼以使其更小。

+0

'WS_EX_LAYERED',從而'SetLayeredWindowAttributes()'和'UpdateLayeredWindow()'不能與孩子使用的控件之前的Windows 8 –

+0

你可以嘗試添加父窗口上的'WS_CLIPCHILDREN'樣式。另請注意,Windows 8之前不支持分層的子窗口。 –

+0

@RemyLebeau,@JonathanPotter [如MSDN所述](http://msdn.microsoft.com/zh-cn/library/ms997507.aspx),WS_EX_LAYERED '是從Windows 2000開始引入的,自此以後就支持分層的窗口。 –

回答

2

我找到了解決方法。我創建了背景頂層窗口,並使前景窗口達到了50%的透明度。我在背景窗口中畫線。如果前窗移動或調整大小,則後窗響應WM_WINDOWPOSCHANGED消息的幫助,它在每一個小動作/調整大小時發送。

不管怎樣,這種解決方法是有點髒,因爲: 的Linux /酒具體問題:1)顯示管理器不裝飾的透明窗口(但是這可以通過讓第二個窗口0%透明迴避) 2)拖動窗口搖晃,但第二直線移動。所有操作系統特定問題:第二個窗口在任務欄中可見。理論上,最後可以通過將WS_EX_TOOLWINDOW添加到無主窗口來避免。 The quote

爲了防止窗口和按鈕被放置在任務欄上,創建 與WS_EX_TOOLWINDOW擴展樣式的無主窗口。

但是,至少在葡萄酒它不起作用。嗯,我希望這是一個bug :)

#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); 
    } 
}