日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

Windows Vista for Developers——第三部分补充:控件和桌面窗口管理器

發(fā)布時(shí)間:2025/6/15 windows 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows Vista for Developers——第三部分补充:控件和桌面窗口管理器 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

作者:Kenny Kerr

翻譯:Dflying Chen

原文:http://weblogs.asp.net/kennykerr/archive/2007/01/23/controls-and-the-desktop-window-manager.aspx

請(qǐng)同時(shí)參考《Windows Vista for Developers》系列。

?

在所有《Windows Vista for Developers》系列文章中,《Windows Vista for Developers——第三部分:桌面窗口管理器》是最受歡迎的(通過(guò)Blog的流量統(tǒng)計(jì)、Email問(wèn)題的主題等得出)。

目前為止,我所聽(tīng)到的最常見(jiàn)的問(wèn)題就是如何在啟用玻璃效果時(shí)也能正確地呈現(xiàn)出控件。回憶一下,我寫DMW文章的時(shí)候Windows Vista還沒(méi)有RTM。在這些較早版本的Vista中,我們可以使用那個(gè)透明像素的hack來(lái)輕松地在玻璃效果上繪出需要的控件。在那篇文章中我也演示了這個(gè)hack的實(shí)際應(yīng)用。不幸的是,當(dāng)微軟公司正式發(fā)布Vista時(shí),這個(gè)hack已經(jīng)沒(méi)用了,只留下了滿腹狐疑的開(kāi)發(fā)者……應(yīng)該怎么辦呢?

不得不說(shuō)我每天的工作非常繁忙,還有很多其他的委托事項(xiàng)需要處理,以至于沒(méi)有時(shí)間發(fā)布替代的解決方案。不過(guò)為了拯救我的email信箱,我還是決定再給出一個(gè)解決方案來(lái)談?wù)勥@個(gè)最常見(jiàn)的問(wèn)題。

?

如何才能在玻璃效果上顯示一個(gè)文本框?

解決這個(gè)問(wèn)題的辦法有很多種。更明確一些地說(shuō),有很多種覆寫默認(rèn)的標(biāo)準(zhǔn)/常用控件繪圖方式的辦法。

你可以接受WM_PAINT消息并自行繪制控件。這樣做的工作量似乎不少,所以大多數(shù)開(kāi)發(fā)者都不喜歡,但這種方法確實(shí)管用,讓我們能夠用必需的Alpha通道進(jìn)行繪制,進(jìn)而顯示出正確的玻璃效果。我的DMW實(shí)例程序就演示了這種方法,雖然其中用的不是某個(gè)控件。

另一種方法是owner draw控件。這樣做的工作量也不少,不過(guò)卻比接受WM_PAINT消息簡(jiǎn)單多了,操作系統(tǒng)卻為你做了不少。owner draw方法是個(gè)很不錯(cuò)的主意,適合大多數(shù)但不是所有的控件。值得一提的是對(duì)于文本框來(lái)說(shuō),owner draw就不管用。

還有一種更簡(jiǎn)單的方法,就是custom draw,但它所適用的控件更少。

另外,對(duì)于少數(shù)幾個(gè)控件,你也可以處理WM_CTLCOLORxxx消息,并設(shè)置其文本和背景顏色。

看看目前我們列出的這幾個(gè)選項(xiàng),只有最后一個(gè)支持文本框控件且相對(duì)比較簡(jiǎn)單。不過(guò)這種方法與玻璃效果配合的卻并不怎么好,因?yàn)樗枰^為原始的GDI支持,而GDI卻并不支持Alpha混合。

?

再重復(fù)一遍:如何才能在玻璃效果上顯示一個(gè)文本框?

有時(shí)候(比如現(xiàn)在)我就在想為什么我不在微軟公司工作呢?微軟公司也不會(huì)因?yàn)槲业倪@些Blog上的文章給我任何報(bào)酬…… :)

在昨天又收到一封Email詢問(wèn)如何在玻璃效果上顯示出文本框控件之后,我終于決定查看一下Windows SDK,看看有沒(méi)有什么新的辦法。順便說(shuō)一句,若你不經(jīng)常查閱Windows SDK的話,我強(qiáng)烈見(jiàn)你養(yǎng)成這個(gè)好習(xí)慣。憑著直覺(jué),我開(kāi)始在SDK的Themes和Visual Styles節(jié)中查看。不管怎樣,這部分內(nèi)容是負(fù)責(zé)提供控件的樣式的。

讓我注意到的第一個(gè)東西就是Windows Vista 的UxTheme.dll中心添加的一系列函數(shù),用來(lái)支持緩沖繪圖。一開(kāi)始這看起來(lái)似乎并不是那么吸引人,因?yàn)镈MW已經(jīng)提供了一定程度上的雙緩沖。但若是有了緩沖繪圖,那就意味著我們可以捕獲、修改內(nèi)存中的位圖之后,再將其顯示出來(lái)。當(dāng)然,這并不是什么新玩意,我們也可以手工實(shí)現(xiàn)同樣的功能。但Visual Styles中提供的這些新功能卻簡(jiǎn)化了我們的工作,并可以很漂亮地解決這個(gè)火燒眉毛的問(wèn)題。

?

緩沖繪圖API

緩沖繪圖API提供了一系列的函數(shù),用來(lái)將圖像繪至設(shè)備上下文(DC)。因?yàn)閳D像將被繪至DC,所以你前面學(xué)的GDI還有用武之地。嘿,兄弟,確實(shí)如此,現(xiàn)在還沒(méi)必要將你整個(gè)的程序遷移到Windows Presentation Foundation(WPF)上!

開(kāi)始之前,你應(yīng)該在每個(gè)線程中都至少調(diào)用一次BufferedPaintInit 函數(shù),用來(lái)初始化這一系列的API。注意,每次調(diào)用BufferedPaintInit 都必須對(duì)應(yīng)著一個(gè)同一線程上的BufferedPaintUnInit 調(diào)用。

若想開(kāi)始緩沖繪圖操作,只要簡(jiǎn)單地調(diào)用BeginBufferedPaint 函數(shù)即可。該函數(shù)接受一個(gè)目的DC,以及一個(gè)目的矩形區(qū)域,用來(lái)指定最終的緩存將要繪制的位置。還有一些額外的參數(shù),可以用來(lái)控制某些緩存相關(guān)的特性。其中一個(gè)就是緩存的類型——謝天謝地它支持設(shè)備無(wú)關(guān)位圖(Device Independent Bitmap,DIB)類型,這就足夠我們進(jìn)行Alpha混合操作了。BeginBufferedPaint 函數(shù)然后返回一個(gè)句柄,我們可以將其傳遞到其他緩沖繪圖API,或是某個(gè)將要繪制的DC中。

能夠接受該緩沖繪圖句柄的其中一個(gè)函數(shù)就是BufferedPaintSetAlpha。該函數(shù)可以讓我們簡(jiǎn)單地更新整個(gè)緩存的Alpha通道,并將其設(shè)定為一個(gè)單一的值,以期實(shí)現(xiàn)各種不同級(jí)別的透明/半透明效果。需要注意的是緩存內(nèi)的所有像素都將被更新為同一個(gè)的Alpha值。

最后,我們即可將該緩存拷貝到目標(biāo)DC上了,并調(diào)用EndBufferedPaint 函數(shù)釋放由BeginBufferedPaint 分配的相關(guān)資源。

目前為止,你差不多也能想象到接下來(lái)要怎么做了。首先用緩沖繪圖API創(chuàng)建一個(gè)緩沖圖像,然后在該緩沖圖像上繪出我們需要的文本框,接下來(lái)更新緩沖圖像的Alpha通道,最后將緩沖繪制到窗體的DC上。讓我們看一個(gè)實(shí)例程序。

?

BufferedPaint類

下面這個(gè)類將緩沖繪圖API用C++封裝起來(lái),以簡(jiǎn)化其使用。

class BufferedPaint { public: BufferedPaint() : m_handle(0) { COM_VERIFY(::BufferedPaintInit()); } ~BufferedPaint() { COM_VERIFY(::BufferedPaintUnInit()); } HRESULT Begin(HDC targetDC, const RECT& targetRect, BP_BUFFERFORMAT format, __in_opt BP_PAINTPARAMS* options, __out CDCHandle& bufferedDC) { ASSERT(0 == m_handle); m_handle = ::BeginBufferedPaint(targetDC, &targetRect, format, options, &bufferedDC.m_hDC); HRESULT result = S_OK; if (0 == m_handle) { result = HRESULT_FROM_WIN32(::GetLastError()); } return result; } HRESULT End(bool updateTargetDC) { ASSERT(0 != m_handle); HRESULT result = ::EndBufferedPaint(m_handle, updateTargetDC); m_handle = 0; return result; } HRESULT SetAlpha(__in_opt const RECT* rect, BYTE alpha) { ASSERT(0 != m_handle); return ::BufferedPaintSetAlpha(m_handle, rect, alpha); } private: HPAINTBUFFER m_handle; };

?

OpaqueEdit類

下面這個(gè)C++類繼承于系統(tǒng)的文本框類,這樣我們即可方便地重寫其繪圖相關(guān)的方法。

class OpaqueEdit : public CWindowImpl<OpaqueEdit, CEdit> { public: BEGIN_MSG_MAP_EX(OpaqueEdit) MESSAGE_HANDLER(WM_PAINT, OnPaint) REFLECTED_COMMAND_CODE_HANDLER_EX(EN_CHANGE, OnChange) DEFAULT_REFLECTION_HANDLER() END_MSG_MAP() private: LRESULT OnPaint(UINT /*message*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*handled*/) { CPaintDC targetDC(m_hWnd); CDCHandle bufferedDC; if (SUCCEEDED(m_bufferedPaint.Begin(targetDC, targetDC.m_ps.rcPaint, BPBF_TOPDOWNDIB, 0, // options bufferedDC))) { SendMessage(WM_PRINTCLIENT, reinterpret_cast<WPARAM>(bufferedDC.m_hDC), PRF_CLIENT); COM_VERIFY(m_bufferedPaint.SetAlpha(0, // entire buffer 255)); // 255 = opaque // Copy buffered DC to target DC COM_VERIFY(m_bufferedPaint.End(true)); } return 0; } void OnChange(UINT /*notifyCode*/, int /*control*/, HWND /*window*/) { VERIFY(InvalidateRect(0, // entire window FALSE)); // don't erase background } BufferedPaint m_bufferedPaint; };

可以看到,在WM_PAINT消息的處理函數(shù)中,我們將WM_PRINTCLIENT消息發(fā)送給了該文本框,讓其繪制到經(jīng)過(guò)緩存的DC上。然后將該緩存的Alpha通道值設(shè)置為255(完全不透明)并更新了目標(biāo)DC。EN_CHANGE的處理函數(shù)可能會(huì)讓你有些吃驚。因?yàn)槲谋究虻睦L制發(fā)生在WM_PAINT消息之外,當(dāng)控件中的文本內(nèi)容發(fā)生變化時(shí),我們需要進(jìn)行再次重繪。在這個(gè)示例中,我僅僅是讓該控件失效,這樣它會(huì)再次接收到一個(gè)新的WM_PAINT消息。這種實(shí)現(xiàn)方式還有一定的優(yōu)化空間,但目前為止對(duì)于這個(gè)示例程序來(lái)說(shuō)已經(jīng)足夠用了。需要提到的是因?yàn)镈MW自動(dòng)提供了雙緩存,所以重復(fù)地進(jìn)行繪制并不會(huì)造成界面閃爍。

?

SampleDialog類

下面的這個(gè)類保證了該窗體作為一塊無(wú)縫的“玻璃”顯示出來(lái),并在其中添加一個(gè)前面定義的OpaqueEdit 類作為文本框。

class SampleDialog : public CDialogImpl<SampleDialog> { public: enum { IDD = IDD_SAMPLE }; BEGIN_MSG_MAP(MainWindow) MSG_WM_INITDIALOG(OnInitDialog) MSG_WM_ERASEBKGND(OnEraseBackground) COMMAND_ID_HANDLER(IDCANCEL, OnCancel) REFLECT_NOTIFICATIONS() END_MSG_MAP() private: bool OnInitDialog(HWND /*control*/, LPARAM /*lParam*/) { const MARGINS margins = { -1 }; COM_VERIFY(::DwmExtendFrameIntoClientArea(m_hWnd, &margins)); VERIFY(m_edit.SubclassWindow(GetDlgItem(IDC_CONTROL))); return true; // Yes, go ahead and set the keyboard focus. } bool OnEraseBackground(CDCHandle dc) { CRect rect; VERIFY(GetClientRect(&rect)); dc.FillSolidRect(&rect, #000000); return true; // Yes, I erased the background. } LRESULT OnCancel(WORD /*notifyCode*/, WORD identifier, HWND /*window*/, BOOL& /*handled*/) { VERIFY(EndDialog(identifier)); return 0; } OpaqueEdit m_edit; };

大功告成!希望本文中提到的技術(shù)能在你掌握Windows Vista開(kāi)發(fā)技術(shù)的過(guò)程中助上一臂之力!

總結(jié)

以上是生活随笔為你收集整理的Windows Vista for Developers——第三部分补充:控件和桌面窗口管理器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。