2017-06-22 24 views
2

作爲我正在研究的項目的一部分,我想強調桌面的區域。現在我用一個半透明的紅色頂級窗口來實現這個,即I什麼可能導致兩個相等的後續SetWindowPos()調用來設置不同的窗口大小?

  1. 用紅色背景畫筆創建一個自定義窗口類。
  2. 創建一個我的自定義類的窗口,它具有WS_EX_LAYERED樣式集。
  3. 致電SetLayeredWindowAttributes使窗口50%半透明。

它主要工作的很好,但是我發現我的疊加窗口和SetWindowPos功能之間相當奇特的互動:通過寬度或高度時SetWindowPos這是小於32 RESP。 39像素,第一次調用SetWindowPos實際上會使窗口大於請求的大小,但隨後的調用按預期工作。下面是一個小例子程序,演示了這個問題 - 它在桌面左上角創建了覆蓋窗口,然後以一秒的延遲時間撥打兩次電話號碼爲SetWindowPos。注意紅色矩形首先是關於方形,然後垂直縮小。

#include <windows.h> 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{ 
    // Register custom class for overlay window, forcing red background 
    WNDCLASSW overlayClassDef = { 
     0, 
     DefWindowProcW, 
     0, 
     0, 
     hInstance, 
     NULL, 
     NULL, 
     ::CreateSolidBrush(RGB(255, 0, 0)), 
     NULL, 
     L"Overlay_Window" 
    }; 

    ATOM overlayClass = ::RegisterClassW(&overlayClassDef); 

    // Create overlay window using 'layered' flag to enable making it 
    // translucent 
    HWND m_overlay = ::CreateWindowExW(
     WS_EX_LAYERED | WS_EX_NOACTIVATE, 
     (LPCWSTR)overlayClass, 
     NULL, 
     0, 
     0, 
     0, 
     0, 
     0, 
     NULL, 
     NULL, 
     hInstance, 
     NULL 
    ); 

    // Strip WS_BORDER and WS_DLGFRAME styles to get perfectly flat window; these 
    // styles appear to get added by default for toplevel windows. 
    int windowStyle = ::GetWindowLongPtr(m_overlay, GWL_STYLE); 
    windowStyle &= ~WS_BORDER; 
    windowStyle &= ~WS_DLGFRAME; 
    ::SetWindowLongPtr(m_overlay, GWL_STYLE, windowStyle); 

    // Show the window and make it 50% translucent 
    ::ShowWindow(m_overlay, SW_SHOWNA); 
    ::SetLayeredWindowAttributes(m_overlay, 0, 127, LWA_ALPHA); 

    // Set the position to 100/100 (50x20 pixels); the window on 
    // screen becomes higher than 20 pixels though! 
    ::SetWindowPos(m_overlay, HWND_TOPMOST, 100, 100, 50, 20, SWP_NOACTIVATE); 
    ::Sleep(1000); 

    // Set the position once more -- this time, the window shrinks 
    // to 20 pixels vertically. 
    ::SetWindowPos(m_overlay, HWND_TOPMOST, 100, 100, 50, 20, SWP_NOACTIVATE); 
    ::Sleep(1000); 

    // Releasing resources omitted for brevity 
    return 0; 
} 

關於這種行爲的一些看法:

  1. 如果任WS_BORDERWS_DLGFRAME窗口標誌設置的效果不會發生;不過,我想清除兩個標誌以獲得完全平坦的窗口。
  2. 的影響似乎並不水平發生使用寬度> = 32個像素
  3. 時,效果似乎不使用高度> = 39個像素
  4. 當不使用自定義窗口時,這也可以再現垂直地發生而是實例化內置的STATIC類。

是否有一個神奇的最小窗口大小接近32像素,必須特別對待?

+0

看來'CreateWindow'分配如果'0'傳遞了'dwStyle'默認的窗口樣式;在這裏傳遞'WS_POPUP'避免觸發奇怪的'SetWindowPos'行爲,並且也減輕了清除'WS_BORDER'和'WS_DLGFRAME'的需要。 –

+0

'WS_OVERLAPPED' [窗口樣式](https://msdn.microsoft.com/en-us/library/windows/desktop/ms632600.aspx)被定義爲'0x0'。 *「重疊的窗口有標題欄和邊框。」*這可能解釋了您觀察的一部分。 – IInspectable

+0

@IInspectable啊,這很有趣 - 這讓我想知道'WS_OVERLAPPED'是否適合用在我的案例中..也許我應該去了'WS_POPUP'? –

回答

3

更新窗口樣式後,您需要確保重新計算窗口大小和框架度量。爲了做到這一點,你需要手動調用SetWindowPosSWP_FRAMECHANGED標誌更新的視覺風格之後:

::SetWindowLongPtr(m_overlay, GWL_STYLE, windowStyle); 
::SetWindowPos(m_overlay, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOREDRAW); 
+0

這看起來不錯!對於它的價值,['SetWindowPos'](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633545(v = vs.85).aspx)文檔指出'SWP_NOOWNERZORDER'和'SWP_NOREPOSITION'是同義詞,所以可以放棄其中的一個。 –

+0

進一步的證據支持這是正確的答案:['SetWindowLong'](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v = vs.85).aspx)文檔狀態在備註部分中:「某些窗口數據被緩存,所以使用SetWindowLong所做的更改在您調用SetWindowPos函數之前不會生效。特別是,如果更改任何框架樣式,則必須使用SWP_FRAMECHANGED標誌調用SetWindowPos爲了緩存被正確更新。「 –

相關問題