VC經(jīng)典代碼 2010-04-15 15:14:59 閱讀338 評(píng)論0 字號(hào):大中小 訂閱
========轉(zhuǎn)自riklin的專欄 ---http://blog.csdn.net/Riklin/archive/2009/08/06/4417247.aspx===
========未經(jīng)允許直接“拿來(lái)主義”呵呵,對(duì)riklin表示感謝!確實(shí)不錯(cuò),眼前一亮啊==========
這兩天在研究透明窗體,總算略有小成。網(wǎng)上大部分文章都是介紹到把窗體弄透明就沒有下文。其實(shí)窗體透明并不難,難就難在透明的窗體上還要放控件。今 天我就把窗體透明一直到控件不透明怎么制作一塊給寫了吧。
先截張圖誘惑下你們,如果你沒興趣就沒必要再看下文了,有興趣的話就繼續(xù)往下看吧^_^!
看好了,這是XP系統(tǒng),未裝.net。我的Photoshop學(xué)的不太好,把玻璃片弄的太透了些,如果你們有好的美術(shù),再加上這種技術(shù),肯定會(huì)如 魚得水。下面就來(lái)詳細(xì)說(shuō)說(shuō)它的制作過程吧:
第 一步:在VC6中使用GDI+:你得從網(wǎng)上弄個(gè)GDI+ for XP的庫(kù),大約500K。如果找不到的話,找我QQ要吧,我會(huì)把這個(gè)窗口的源程序一起發(fā)給你的。把它解壓后,將所有文件還包括子目錄中的文件復(fù)制到你的項(xiàng) 目目錄。在stdafx.h中加入以下代碼:
#include "gdiplus.h" ////請(qǐng)修改為你的頭文件路徑
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib") ////請(qǐng)修改為你的.lib文件路徑
我的項(xiàng)目名為Test,所以在TestApp中加入全局變量
ULONG_PTR gdiplusToken;
在BOOL CTestApp::InitInstance()中加入這兩行:
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
記住在線程退出后要御掉GDI+,它很占資源的,在int CTestApp::ExitInstance() 中加入這行:
GdiplusShutdown(gdiplusToken);
一切準(zhǔn)備工作就緒,開始制作窗口了。
二、制作PNG圖像:這不是程序員的事,是美工的事,可是目前美術(shù)技術(shù)都是我一人,所以干脆連PNG一起教你們做了吧。
先打開Photoshop(簡(jiǎn)稱PS),打開一張背景圖,在背景圖上使用圓角矩形工具
什么?怎么個(gè)調(diào)出來(lái)的?你還真以為我什么都教你?要是我連PS的過程都寫上來(lái),那我干脆寫本書得了。體諒一下吧,寫教程是需要大量時(shí)間的,所以能 省則省。
將背景去掉,將玻璃保存成PNG圖片,不需要設(shè)置任何參數(shù),PNG是自動(dòng)使用這種與背景溶合透明的,強(qiáng)大吧^_^!
再用同樣的方法,制作綠色按鈕
按鈕不需要保存成PNG,因?yàn)槲也粶?zhǔn)備將它透明。至于這種“透明控件”的文章,你在網(wǎng)上一搜一大堆。
繼續(xù)吧!還要做其它3個(gè)按鈕,“確定”的按下效果,“取消”的拾起和按下效果,在這里我就不截圖了。
美術(shù)都搞定,開始寫代碼。
三、寫代碼之前,我先說(shuō)說(shuō)工序:先用SetWindowLong將對(duì)話框設(shè)置成層級(jí)窗體,再使用GDI+顯示圖片。顯示成功后再用 UpdateLayeredWindow函數(shù)進(jìn)行透明處理。
現(xiàn)在問題出來(lái)了,你會(huì)發(fā)現(xiàn)你原來(lái)在窗口上畫的控件一概不顯示,怎么辦呢?我是在這個(gè)窗口上再蓋上另一個(gè)對(duì)話框,設(shè)置成啟動(dòng)窗體那種樣式,所有消息 都在這個(gè)前景窗體上處理。
問題又來(lái)了,前景窗體蓋上去,后面窗口又看不見了,怎么辦呢?我又想了辦法,在前景窗體加了透明色,在這里我是用粉紅色,因?yàn)樵陔娔X中粉紅色用的 最少,因?yàn)樗艽萄?。用這個(gè)方法的缺點(diǎn)就是你的控件不能有粉紅色。
最后將兩個(gè)按鈕改成位圖按鈕即可。
現(xiàn)在來(lái)看詳細(xì)制作過程吧:
定義成員變量:在TestDlg.h中定義
BLENDFUNCTION m_Blend;
HDC m_hdcMemory;
改成層級(jí)窗體:在BOOL CTestDlg::On
//窗體樣式為0x80000為層級(jí)窗體
DWORD dwExStyle=GetWindowLong(m_hWnd,GWL_EXSTYLE);
SetWindowLong(m_hWnd,GWL_EXSTYLE,dwExStyle^0x80000);
加載PNG圖片:
//繪制內(nèi)存位圖
HDC hdcTemp=GetDC()->m_hDC;
m_hdcMemory=CreateCompatibleDC(hdcTemp);
HBITMAP hBitMap=CreateCompatibleBitmap(hdcTemp,500,500);
SelectObject(m_hdcMemory,hBitMap);
//使用GDI+載入PNG圖片
HDC hdcScreen=::GetDC (m_hWnd);
RECT rct;
GetWindowRect(&rct);
POINT ptWinPos={rct.left,rct.top};
Graphics graph(m_hdcMemory); //GDI+中的類
Image image(L"bk.png",TRUE); //GDI+中的類
graph.DrawImage(&image,0,0,267,154); //后面兩個(gè)參數(shù)要設(shè)置成跟圖片一樣大小,否則會(huì)失真
窗口透明貼圖:
//使用UpdateLayerWindow進(jìn)行窗口透明處理
HMODULE hFuncInst=LoadLibrary("User32.DLL");
typedef BOOL (WINAPI *MYFUNC)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,COLORREF,BLENDFUNCTION*,DWORD);
MYFUNC UpdateLayeredWindow;
UpdateLayeredWindow=(MYFUNC)GetProcAddress(hFuncInst,"UpdateLayeredWindow");
SIZE sizeWindow={267,154};
POINT ptSrc={0,0};
UpdateLayeredWindow( m_hWnd,hdcScreen,&ptWinPos,&sizeWindow,m_hdcMemory,&ptSrc,0,&m_Blend,2);
使用上述代碼后,運(yùn)行程序,你會(huì)發(fā)現(xiàn)你的窗口已經(jīng)是透明的了,下面進(jìn)行控件處理:
四、前景窗體
新建對(duì)話框,畫上控件,我在這里起名為COnWindow,隨便起的,不要笑我^_^。
讀者奇怪的是,這上面怎么沒有“用戶名、密碼”兩個(gè)Label控件?不好意思,因?yàn)槲业牟Aё龅奶?,這些文字在玻璃上已經(jīng)很難看清楚,所以我干 脆用PS描了下邊,直接畫到前景上去了,就成了這種效果
定義成員變量:在On
CBrush m_brush; //背景畫刷
CBitmapButton m_ok;
CBitmapButton m_cancel;
設(shè)置畫筆:在在BOOL COnWindow::On
m_brush.CreateSolidBrush(RGB(255,0,255)); //背景設(shè)置為粉紅色
改為層級(jí)窗體:
//SetWindowsLong將窗體設(shè)置為層級(jí)窗體
DWORD dwExStyle=GetWindowLong(m_hWnd,GWL_EXSTYLE);
SetWindowLong(m_hWnd,GWL_EXSTYLE,dwExStyle|0x80000);
設(shè)置透明色:
//用SetLayeredWindowAttributes設(shè)置透明色為0,它比UpdateLayeredWindow的使用要簡(jiǎn)單些
HMODULE hInst=LoadLibrary("User32.DLL");
typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
MYFUNC SetLayeredWindowAttributes = NULL;
SetLayeredWindowAttributes=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
SetLayeredWindowAttributes(this->GetSafeHwnd(),0xff00ff,0,1);
FreeLibrary(hInst);
不要忘記把窗體前景刷成粉紅色:在HBRUSH COnWindow::On
HBRUSH hbr = CDialog::On
// TODO: Change any attributes of the DC here
if(nCtlColor=CTLCOLOR_DLG)
return m_brush;
return CDialog::On
現(xiàn)在要把前景窗體和背景窗體聯(lián)動(dòng),這可是關(guān)鍵點(diǎn):
把 前景窗體設(shè)置成啟動(dòng)窗體,無(wú)標(biāo)題欄,樣式為Popup彈出式。寫到這里,我不得不說(shuō)的是:我曾想把前景窗體設(shè)置成Child,發(fā)現(xiàn)前景窗體又被“透明”掉 了,什么都看不見,郁悶呀,所以只好用On
組合窗口,并保持聯(lián)動(dòng):
在TestDlg.h中加入頭文件:#include "On
在void CTestDlg::On
CDialog::On
// TODO: Add your message handler co
CRect rcWindow; // 使用MoveWindow函數(shù)的示例
GetWindowRect(rcWindow);
rcWindow.bottom-=10;
rcWindow.left+=10;
rcWindow.right-=10;
rcWindow.top+=20;
pChildWnd->MoveWindow(&rcWindow);
創(chuàng)建窗體時(shí):在int CTestDlg::On
//創(chuàng)建子窗體
pChildWnd=new COnWindow(this);
pChildWnd->Create(IDD_ON
pChildWnd->ShowWindow(SW_SHOW);
你現(xiàn)在看到窗體上沒有標(biāo)題欄吧?你把鼠標(biāo)移到窗口頂部,還可以照樣移動(dòng)窗口,知道為什么嗎?因?yàn)榇翱陔m然透明了,但是背景窗口的任何控件都是存在 的,只是不顯示,它還能照樣響應(yīng)事件,不信你在背景窗口上放上個(gè)按鈕試試。不錯(cuò)吧?又省掉一些代碼。
五、最后,我們來(lái)處理位圖按鈕:VC6的CBitmapButton::LoadBitmaps方法不能直接貼上16位真彩按鈕,于是我將兩個(gè)真 彩色按鈕用Acdsee32轉(zhuǎn)換成256色的,就可以直接載入了,相信你們也沒看出來(lái)吧?
處理成256色后,再在BOOL COnWindow::On
//載入按鈕位圖
m_ok.LoadBitmaps(IDB_OK1,IDB_OK2);
m_cancel.LoadBitmaps(IDB_CANCEL1,IDB_CANCEL2);
m_ok.SubclassDlgItem(IDOK, this);
m_cancel.SubclassDlgItem(IDCANCEL, this);
現(xiàn)在按下按鈕只能關(guān)閉自己,給父窗口發(fā)個(gè)消息吧:在void COnWindow::On
HWND hWnd=GetParent()->m_hWnd;
::SendMessage(hWnd,WM_CLOSE,0,0);
聯(lián)系客服