国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

在windows上創(chuàng)建完美的不規(guī)則窗口

2019-11-14 09:48:08
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

在windows上創(chuàng)建完美的不規(guī)則窗口

不規(guī)則窗口方法簡(jiǎn)介

windows上的窗口絕大多數(shù)是方形的,但是偶爾也會(huì)有一些其他形狀的窗口,如圓形甚至不規(guī)則形狀。這些不常見(jiàn)的窗口是如何做出來(lái)的呢? 有兩種方法可以創(chuàng)建不規(guī)則窗口 1、windows在很早的時(shí)代就支持不規(guī)則形狀的窗口了。windows提供了SetWindowRgn 函數(shù)來(lái)設(shè)置窗口的區(qū)域,還提供了一些函數(shù)來(lái)創(chuàng)建橢圓、圓角矩形區(qū)域,還可以自己繪制區(qū)域,但是這種方法有個(gè)缺陷,曲線的邊緣有嚴(yán)重的鋸齒。 2、使用windows2000以后提供的透明窗口方法來(lái)創(chuàng)建不規(guī)則形狀的窗口。當(dāng)透明窗口的透明部分的透明度為0的時(shí)候次部分就會(huì)完全透明,鼠標(biāo)也可以穿透。所以只要制造出有不規(guī)則的完全透明區(qū)域的窗口后,就可以形成不規(guī)則窗口。 而且可以通過(guò)邊緣抗鋸齒來(lái)實(shí)現(xiàn)平滑的窗口邊緣,消除鋸齒。 本文主要講的就是第二種方法。

透明窗口API詳解

之前已經(jīng)有一篇文章介紹了簡(jiǎn)單的透明窗口使用vc++創(chuàng)建windows透明窗口,一些基礎(chǔ)內(nèi)容就不在贅述,請(qǐng)自行閱讀。 此次主要用到上一篇文章中沒(méi)有詳細(xì)說(shuō)明的UpdateLayeredWindow函數(shù),UpdateLayeredWindow函數(shù)的透明和其他的透明方式不太一樣,一旦使用UpdateLayeredWindow函數(shù)就不能再使用其他的透明函數(shù), 而且窗口的繪制也完全被UpdateLayeredWindow接管,此時(shí)正常的繪圖都不再生效,必須通過(guò)UpdateLayeredWindow來(lái)刷新窗口的界面。 要使用UpdateLayeredWindow刷新窗口,首先要建立一個(gè)內(nèi)存dc,然后在dc上畫(huà)圖,在通過(guò)UpdateLayeredWindowdc上的內(nèi)容根據(jù)參數(shù)做透明處理然后刷新界面。

BOOL WINAPI UpdateLayeredWindow( _In_ HWND hwnd, _In_opt_ HDC hdcDst, _In_opt_ POINT *PPTDst, _In_opt_ SIZE *psize, _In_opt_ HDC hdcSrc, _In_opt_ POINT *pptSrc, _In_ COLORREF crKey, _In_opt_ BLENDFUNCTION *pblend, _In_ DWord dwFlags);

UpdateLayeredWindow有9個(gè)參數(shù)。 第一個(gè)參數(shù)是要刷新的窗口句柄,第二個(gè)是要刷新的窗口的 dc,這個(gè)參數(shù)通常可以傳NULL,會(huì)自動(dòng)從第一個(gè)參數(shù)的窗口句柄代表的窗口中去獲取。 第三個(gè)參數(shù)是你要刷新的區(qū)域的左上坐標(biāo)點(diǎn),如果是全屏也可以傳NULL,第四個(gè)參數(shù)是刷新區(qū)域的長(zhǎng)寬,不能傳NULL。 第五個(gè)參數(shù)就是畫(huà)好圖的內(nèi)存dc了,第六個(gè)參數(shù)是內(nèi)存dc上刷新過(guò)去的區(qū)域的左上坐標(biāo)點(diǎn)。 第七個(gè)參數(shù)和第八個(gè)參數(shù)就是控制透明處理的參數(shù),第七個(gè)參數(shù)設(shè)置透明色,也就是這種顏色的區(qū)域全部透明,第八個(gè)參數(shù)是設(shè)置整體透明度。 第九個(gè)參數(shù)控制是第七個(gè)參數(shù)還是第八個(gè)參數(shù)生效或者都生效。 此處要說(shuō)明一下第八個(gè)參數(shù)設(shè)置的整體透明度,他只是在原有的顏色上按照參數(shù)里的比例做透明處理,如果內(nèi)存dc里的一塊區(qū)域顏色本身就是全透明的,那么無(wú)論怎么設(shè)置參數(shù)這里依然是全透明的。

制造透明區(qū)域

使用透明窗口來(lái)制造不規(guī)則窗口的關(guān)鍵就在于怎樣制造出包含透明區(qū)域的內(nèi)存dc來(lái)。

外部作圖

眾所周知,png是支持透明通道的一種圖片格式,所以只要提前做好png透明圖片,然后運(yùn)行時(shí)加載到內(nèi)存dc上就行了,是不是簡(jiǎn)單爆了。

實(shí)時(shí)繪圖

如果能用圖片那是最好啦,但是有時(shí)候如果窗口的形狀要經(jīng)常變化而且形態(tài)非常多的話,就不能通過(guò)外部圖片了。只能在內(nèi)存中畫(huà)出dc的圖來(lái)。 gdi+中的顏色支持了透明色,但是這種透明色指的是畫(huà)刷畫(huà)圖的時(shí)候和背景色做透明,最終畫(huà)在dc上還是不透明的,并不能達(dá)到我們要的效果。那么怎么辦呢?只能使出終極辦法: 直接修改內(nèi)存中的顏色數(shù)據(jù)。也就是將要透明的區(qū)域先用一種特別的顏色填充好,然后遍歷內(nèi)存中的顏色數(shù)據(jù),將這個(gè)顏色的內(nèi)存數(shù)據(jù)強(qiáng)行修改為完全透明-——將ARGB的代表A通道的字節(jié)置零。 由于內(nèi)存dc并不支持遍歷內(nèi)存數(shù)據(jù),所以一般是建立一個(gè)位圖,然后在這個(gè)位圖上畫(huà)圖標(biāo)記處需要透明的位置,最后遍歷位圖內(nèi)存,將需要透明的位置全部摳掉。托cpu進(jìn)步的福,我摳一副1080p的圖瞬間就可以完成。然后把位圖畫(huà)到dc上去。 這里有一個(gè)小問(wèn)題,因?yàn)槲粓D中有透明顏色,上次在dc畫(huà)圖的時(shí)候這部分會(huì)遺留下來(lái)干擾到下次繪圖,所以要每次重畫(huà)之前把dc內(nèi)容用其他顏色給填掉。 最后就是鋸齒的問(wèn)題了。如果要抗鋸齒的話就要再做一個(gè)特殊處理,首先得明白抗鋸齒的原理,可以Jan之前我寫(xiě)過(guò)的gdi+的畫(huà)圖抗鋸齒原理。 用gdi+畫(huà)出抗鋸齒的圖后,然后在遍歷的時(shí)候?qū)ふ夷切┯蓛煞N顏色混合成的顏色,然后根據(jù)混合的比例相應(yīng)的轉(zhuǎn)換成半透明度設(shè)置到這個(gè)像素點(diǎn)。通常我用白色和黑色做前景色和背景色,這樣混合變成灰色,灰色的rgb值除以白色rgb值的比例就是半透明度。 最后將這樣一幅位圖畫(huà)到dc上,用UpdateLayeredWindow函數(shù)刷新到窗口上就會(huì)形成不規(guī)則的窗口了。

代碼示例

畫(huà)出要被扣掉的關(guān)鍵色區(qū)域位圖的代碼:

void SpotlightWindow::DrawMaskImage(Bitmap * pImage){ Graphics graphics(pImage); graphics.FillRectangle(m_pBlackBrush, 0, 0, m_windowRect.Width(), m_windowRect.Height()); graphics.SetSmoothingMode(Gdiplus::SmoothingMode::SmoothingModeAntiAlias); graphics.FillEllipse(m_pKeyBrush, m_ellipseRect.left, m_ellipseRect.top, m_ellipseRect.Width(), m_ellipseRect.Height()); graphics.Flush(Gdiplus::FlushIntentionSync);}

遍歷摳掉透明區(qū)域并對(duì)邊緣做半透明處理的代碼:

void SpotlightWindow::MakeTransparentImage(Bitmap * pImage){ Gdiplus::Rect rect(0, 0, pImage->GetWidth(), pImage->GetHeight()); Gdiplus::BitmapData bmpData; pImage->LockBits(&rect, Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, &bmpData); int width = pImage->GetWidth(); int height = pImage->GetHeight(); int stride = bmpData.Stride; unsigned int *pData = reinterPRet_cast<unsigned int *>(bmpData.Scan0); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { unsigned int color = *pData; if (color == WHITE_COLOR) { *pData = TRANSPARENCY_WHITE_COLOR;//設(shè)為透明色 } else if (color != BLACK_COLOR) { *pData = TransportTransparentColor(color);//根據(jù)計(jì)算結(jié)果設(shè)為把半透明顏色 } ++pData; } } pImage->UnlockBits(&bmpData);}

計(jì)算半透明的代碼:

unsigned int SpotlightWindow::TransportTransparentColor(unsigned int color){ //像素顏色數(shù)據(jù) unsigned char * pArgb = reinterpret_cast<unsigned char *>(&color); //換算出的透明度 unsigned char transparency = MAX_COLOR-*pArgb; //新的像素顏色 unsigned int transparencyColor = BLACK_COLOR; pArgb = reinterpret_cast<unsigned char *>(&transparencyColor); //設(shè)置新的像素顏色的透明度 pArgb[TRANSPARENCY_INDEX] = transparency; return transparencyColor;}

將透明圖片畫(huà)到dc上并刷新到窗口上的代碼:

void SpotlightWindow::Paint(Gdiplus::Bitmap * pImage){ HBITMAP old = SelectBitmap(m_memoryDC, m_memoryBitmap); FillRect(m_memoryDC, m_windowRect, m_backgroundBrush); Graphics graphics(m_memoryDC); graphics.DrawImage(pImage, 0, 0, m_windowRect.Width(), m_windowRect.Height()); CSize size(m_windowRect.Width(), m_windowRect.Height()); CPoint point(0, 0); UpdateLayeredWindow(m_mainWindow, NULL, NULL,&size, m_memoryDC, &point, 0, &m_blendFunc32bpp, ULW_ALPHA); SelectBitmap(m_memoryDC, old);}
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 彭阳县| 五河县| 黄浦区| 孟津县| 南漳县| 天门市| 通山县| 宁夏| 枣阳市| 莆田市| 平山县| 武强县| 鄂州市| 老河口市| 梅河口市| 萨嘎县| 鹿邑县| 万山特区| 吉木萨尔县| 灵台县| 大连市| 滦平县| 新野县| 伊川县| 盐山县| 汉川市| 栾川县| 嘉禾县| 绥芬河市| 富民县| 星座| 东辽县| 陈巴尔虎旗| 科尔| 鸡东县| 柘荣县| 垦利县| 日土县| 云南省| 新建县| 高碑店市|