使用分层窗口实现界面皮肤
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
使⽤分层窗⼝实现界⾯⽪肤
使⽤分层界⾯来实现界⾯⽪肤的好处是:可以保证图⽚边缘处理不失真,且能⽤于异形窗⼝上,如⼀些不规则的窗⼝,你很难⽤SetWindowRgn来达到理想效果。
在很多情况下,界⾯的漂亮与否,取决于PS的制作及创意,⽽界⾯编程所需要做的就是将图⽚完整⽆缺的展⽰给⽤户。
分层窗⼝的好处就是:⽤⼀层窗⼝来描绘窗⼝背景,以确保背景图⽚不会失真,⽽另⼀层窗⼝⽤来放置控件,除控件之外的区域全是透明的。
为什么要这么⿇烦呢?因为我们将要⽤到UpdateLayeredWindow来实现窗⼝背景描绘,⼀旦执⾏这个函数后,窗⼝的控件将会被覆盖,不会再显⽰。
所以我们要再加⼀层透明窗⼝,来放置控件,以确保控件不会受到UpdateLayeredWindow的影响。
这样⼀来,窗⼝绘图将不会影响到控件,并且可以达到窗⼝透明,控件不透明的效果。
当然这个只是个别的窗⼝实现效果需求,这⾥不做重点讨论。
这⾥我⽤了两个窗⼝类来完成此项⼯作,CThemedLayerWnd和CThemedAlphaWnd。
CThemedLayerWnd负责截取正常窗⼝的创建消息,并在正常窗⼝创建之前,创建CThemedAlphaWnd; CThemedAlphaWnd主要负责窗⼝的描绘,也就是使⽤UpdateLayeredWindow来让Windows⾃⼰描绘窗⼝⽪肤。
正常窗⼝只需要继承模板类 CThemedLayerWnd,并将 CThemedLayerWnd加⼊到⾃⼰的窗⼝消息链中即可:
class CMainDlg : public CThemedLayerWnd<CMainDlg>,
public CUpdateUI<CMainDlg>,
public CMessageFilter,
public CIdleHandler
{
BEGIN_MSG_MAP(CMainDlg)
CHAIN_MSG_MAP(CThemedLayerWnd<CMainDlg>)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
};
在正常窗⼝执⾏Create函数时,提前创建CThemedAlphaWnd,这样⼀
来,CThemedAlphaWnd就是CThemedLayerWnd的⽗窗⼝,CThemedLayerWnd理所当然成为⼦窗⼝,并⾃动将窗⼝位置置于CThemedAlphaWnd之上,这也正是我们想要的效果。
// Create normal dialog and alpha window.
HWND Create(const HWND wndParent, const int nImageID)
{
// Create alpha window before normal dialog created.
// Do not use WS_CHILD style, we need separated alpha window.
m_wndAlpha = new CThemedAlphaWnd;
m_wndAlpha->Create(wndParent, CRect(0, 0, 100, 100), NULL, WS_VISIBLE);
ATLASSERT(m_wndAlpha->m_hWnd != NULL);
SetBackgroundImage(nImageID);
// Create normal dialog.
HWND hwnd = CDialogImpl<T>::Create(m_wndAlpha->m_hWnd);
// Pass normal window handle.
m_wndAlpha->SetNormalWnd(m_hWnd);
// Set normal dialog style.
UpdateWindowStyle();
return hwnd;
}
这⾥还有个关键的问题,窗⼝上⾯是有控件的,如果控件要获取⽗窗⼝的背景画刷该怎么办?⽽ CThemedLayerWnd是透明的,你是没办法获取到透明背景的。
所以需要截取CThemedLayerWnd的WM_PAINT消息,当控件想要通过WM_PAINT来获取窗⼝背景时,将窗⼝⽪肤图⽚传递给控件。
// Only for control get background image.
void DoPaint(CDCHandle dc)
{
if (m_bmpBack.m_hBitmap != NULL)
{
HBITMAP hBmp = dc.SelectBitmap(m_bmpBack.m_hBitmap);
ATLASSERT(hBmp != NULL);
}
}
分层窗⼝带来的不便之处就是:你对窗⼝的操作都是介于两个窗⼝之间的,所以你需要在此上⾯多花费⼀些功夫,⽐如移动窗⼝,实际是移动两个窗⼝。
再⽐如正常窗⼝调⽤CenterWindow,实际是让 CThemedLayerWnd来移动窗⼝,你不得不重写CenterWindow来先移动 CThemedAlphaWnd然后再来移动 CThemedLayerWnd。
凡事皆有取舍,⼀切都根据实际需求做出取舍。
正如分层窗⼝⼀样,丧失了⼀些正常窗⼝的普通函数操作能⼒,但换来了界⾯⽪肤的完美显⽰。