2011-09-30 100 views
4

我試圖做一個簡單的小工具,允許用戶從正常操作切換到禁用所有應用程序消息的模式,並且可以使用鼠標執行一些徒手繪製,然後再次切換模式以在屏幕上保留其繪圖,同時執行任何他們想要的其他正常工作。如果我決定,這可以演變成一個很好的東西,你可以使用裝飾屏幕來保存你所做的裝飾並稍後加載它們。當我開始這個(這已經超過半年前,在發現Windows API之後不久),我只做了全局鼠標跟蹤,並在GetDC(NULL)hdc的任何位置繪製了一個圓。當然,問題是當它下面的任何東西被更新並且仍然會有鼠標消息通過時它會消失,所以如果我按住桌面上的按鈕,例如,它會在整個繪畫中放置矩形的東西。徒手繪製整個屏幕

今天,在6個月前的最後一次重要工作之後,我終於有了一些空閒時間,然後決定重新制作它,看看我能否實現我想要的。我做了一個透明的,最頂層的,WS_CHILD,分層的,最大化的窗口(基本上屏幕不會改變,但是有一個窗口放在消息的最前面)。接下來,我創建了它,當它處於繪畫模式時,它將alpha值設置爲1並讓用戶繪畫。在我做之前我沒有意識到的一點是,由於窗口的alpha值爲1,因此沒有任何繪畫可見。

接下來,我嘗試使用GetDC(NULL),但記得當某些更新時會被擦除。

現在我只想到使用位圖和dcs將屏幕重複存儲到另一個dc上的dc上,然後將其複製回存儲的屏幕,並顯示未繪製部分的透明度,並將其複製回屏幕,但我失去了一點心意。這是我的源代碼(mask功能取自this tutorial)。請告訴我,如果這是不必要的。我已經使用位圖來確保雙緩衝,但我並不確定我需要它們的位置。

//Global mask since it takes longer to make 
HBITMAP mask; 

//Window Procedure Start 
HDC screenDC; //hdc for entire screen 
screenDC = GetDC (NULL); //get DC for screen 

HDC memDC = CreateCompatibleDC (screenDC); //create DC for holding the screen+paint 
HBITMAP bm = CreateCompatibleBitmap (screenDC, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); //create bitmap for memDC 

HDC paintDC = CreateCompatibleDC (screenDC); //create DC to paint on 
HBITMAP paintBM = CreateCompatibleBitmap (screenDC, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN)); //create bitmap for paintDC 

SelectObject (memDC, bm); //select bitmap into memDC 
SelectObject (paintDC, paintBM); //select painting bitmap into paintDC 
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), screenDC, 0, 0, SRCCOPY); //copy screen to memDC 
SetBkColor (paintDC, RGB(0,0,0)); //set background of paintDC to black so it's all transparent to start 

//WM_CREATE 
mask = CreateBitmapMask (bm, RGB(0,0,0)); //create black mask (paint colours are limited 1-255 now) 

//painting is done into paintDC 

//at end of Window Procedure 
SelectObject (paintDC, mask); //select mask into paintDC 
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCAND); //this in combination with the next should make it bitblt with all of the black taken out I thought 
SelectObject (paintDC, paintBM); //select bitmaps into DCs 
SelectObject (memDC, bm); 
BitBlt (memDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCPAINT); //second part of transparent bitblt 
BitBlt (screenDC, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), paintDC, 0, 0, SRCCOPY); //copy memDC back to screen 

DeleteObject (paintBM); //delete stuff 
DeleteObject (mask); 
DeleteDC (memDC); 
DeleteDC (paintDC); 
ReleaseDC (hwnd, screenDC); 

//CreateBitmapMask() (taken directly from http://www.winprog.org/tutorial/transparency.html 
HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent) 
{ 
HDC hdcMem, hdcMem2; 
HBITMAP hbmMask; 
BITMAP bm; 

// Create monochrome (1 bit) mask bitmap. 

GetObject(hbmColour, sizeof(BITMAP), &bm); 
hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL); 

// Get some HDCs that are compatible with the display driver 

hdcMem = CreateCompatibleDC(0); 
hdcMem2 = CreateCompatibleDC(0); 

SelectObject(hdcMem, hbmColour); 
SelectObject(hdcMem2, hbmMask); 

// Set the background colour of the colour image to the colour 
// you want to be transparent. 
SetBkColor(hdcMem, crTransparent); 

// Copy the bits from the colour image to the B+W mask... everything 
// with the background colour ends up white while everythig else ends up 
// black...Just what we wanted. 

BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); 

// Take our new mask and use it to turn the transparent colour in our 
// original colour image to black so the transparency effect will 
// work right. 
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT); 

// Clean up. 

DeleteDC(hdcMem); 
DeleteDC(hdcMem2); 

return hbmMask; 
} 

我知道代碼可能非常糟糕。我正在考慮所有建議,只是我對這個主題不太清楚,並沒有得到所發生的一切,這使得很難修復。這段代碼幾乎每隔一段時間就會放一個全屏黑色矩形。

我的主要問題是:有沒有什麼方法可以在屏幕上繪製,而不會在下面的窗口更新時被擦除?我現在能想到的唯一真正的事情是存儲全部用戶繪製的細小線段的位置,並保持在屏幕上重繪它們。乍一看,它看起來效率很低並且浪費記憶。

另外,我非常確定,在編寫代碼段之前,我不需要任何代碼示例。現在大部分都消失了,但這實際上更像是一個理論問題。

編輯: 我只是發現了關於這似乎完美的情況TransparentBlt功能,所以我嘗試使用,而不是SRCPAINT和SRCAND BitBlts和它產生相同的結果:一個黑色的矩形覆蓋的屏幕,有時不得不當鼠標移過東西時零件消失。

回答

3

簡單的方式,也許:

當在非繪圖模式,使用SetLayeredWindowAttributes來設置透明窗「透明度鍵」的顏色。使窗口的alpha完全不透明,但用該關鍵字填充窗口(FillRect或類似),它將全部顯示爲透明。然後,您在非關鍵顏色中繪製的任何內容都將顯示爲實體,位於透明分層窗口下方的所有窗口之上。

要進入繪圖模式,一種方法是創建一個新窗口,並在透明圖層下面立即捕獲位於桌面上的位圖。或避免位圖,並使其稍微不透明,並且都是純色 - 例如,看起來桌面是「變灰」的。關鍵是這個窗口不是完全透明的,所以它將能夠接收鼠標輸入,然後你可以使用它來在實際的透明層上繪製。

+0

乍一看,這個想法看起來簡單而精彩!我從來沒有想過使用2層窗口來達到我想要的效果,並且使桌面變灰變得容易。我使用LWA_ALPHA的唯一原因是我可以捕獲鼠標消息,因爲LWA_COLORKEY不會,但下面的另一個窗口可以解決所有問題。我可能會忙於學習幾天,但我會告訴你它是如何工作的。 – chris

0

我想你最好是通過創建屏幕快照並將其保存在位圖中(以內存DC的形式),然後顯示一個窗口,以全屏顯示內存DC的內容。這樣,您實際上可以通過自己的窗口獲取點擊等引起的消息,並像往常一樣處理它們。

  1. 捕獲屏幕內容
  2. 創建窗口(全屏),並利用捕獲的內容
  3. 做一些拉伸
  4. 保存的內容(如BMP或任何幻想)
  5. 關閉窗口,並返回到普通桌面

好主意?

+0

我看到的那個問題(除非我在想錯)除非他們切換回他們可以做其他事情的地方(即,這與分層窗口具有相同的效果)透明度爲1,除了它下面的東西在我繪製的時候實時更新,糾正我,如果這不是你的意思。當我回頭看位圖時,我想要保存/加載的是paintBM - 一個與用戶的圖紙一起使用,然後可以將其放置在屏幕圖像的「頂部」,然後將其應用到屏幕上。 – chris

+0

將圖形保存爲捕獲屏幕頂部的圖層是沒有問題的。如果我理解正確,你希望屏幕在更新的同時進行更新? – demorge

+0

有點兒,最主要的是能夠在模式切換後將繪畫粘貼到屏幕上(以及如果有人想知道環,這是通過我的窗口處理的熱鍵完成的)。我可以想到的最終解決方案似乎是不可能的,但是在背景透明的前面放置一個窗口,但是之後沒有任何其他的東西。這將導致窗戶停留在那裏,可見的油漆粘在它上面,而任何未塗漆的部分將不可見。如果可能的話,我會非常高興,但是我沒有找到類似的東西:/ – chris