不規(guī)則窗體的應(yīng)用增加軟件的吸引力
發(fā)表時(shí)間:2024-02-19 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]傳統(tǒng)的WINDOWS應(yīng)用軟件界面給人的感覺總是千篇一律的方方正正的窗體,看的時(shí)間長(zhǎng) 了難免會(huì)有些厭煩,總是希望能見到些不同一般的軟件界面。如今,相當(dāng)數(shù)量的商業(yè)軟件在 提供優(yōu)秀而強(qiáng)大的功能的同時(shí),軟件的界面也是做得越來(lái)越漂亮,比如《超級(jí)解霸2000》中 的界面插件,使用過的人一定對(duì)其華麗的外觀充滿好...
傳統(tǒng)的WINDOWS應(yīng)用軟件界面給人的感覺總是千篇一律的方方正正的窗體,看的時(shí)間長(zhǎng)
了難免會(huì)有些厭煩,總是希望能見到些不同一般的軟件界面。如今,相當(dāng)數(shù)量的商業(yè)軟件在
提供優(yōu)秀而強(qiáng)大的功能的同時(shí),軟件的界面也是做得越來(lái)越漂亮,比如《超級(jí)解霸2000》中
的界面插件,使用過的人一定對(duì)其華麗的外觀充滿好感。作為一個(gè)編程愛好者,如果自己寫
出的軟件也擁有類似的界面,也許會(huì)吸引更多目光的注視。那么,我們現(xiàn)在就開始動(dòng)手制作
自己的漂亮界面吧。
技術(shù)內(nèi)幕
要想在自己的程序中加入不規(guī)則窗體的應(yīng)用,你首先要熟悉幾個(gè)WINDOWS API函數(shù)的使
用,它們是:橢圓形(或圓形)區(qū)域創(chuàng)建函數(shù)CreateEllipticRgn 、多邊形區(qū)域創(chuàng)建函數(shù)
CreatePolygonRgn、 矩形區(qū)域創(chuàng)建函數(shù)CreateRectRgn、 帶圓角的矩形區(qū)域創(chuàng)建函數(shù)
CreateRoundRectRgn。你可以用這些函數(shù)創(chuàng)建不同類型的窗體區(qū)域,也可以用WINDOWS API
函數(shù)CombineRgn將幾個(gè)簡(jiǎn)單區(qū)域組合成一個(gè)復(fù)雜區(qū)域。
下一步要做的就是將已經(jīng)創(chuàng)建好的區(qū)域顯示在屏幕上,同樣也是使用WINDOWS API 函數(shù)
來(lái)實(shí)現(xiàn),這次用到的是SetWindowRgn函數(shù)。
WINDOWS API 函數(shù)在Borland C++ Builder 頭文件中均已定義,在應(yīng)用程序中使用這些
API函數(shù)就象使用C++的普通庫(kù)函數(shù)一樣。
準(zhǔn)備工作
為你的程序準(zhǔn)備一幅背景圖片,推薦方法是: 在PhotoShop中打開圖片后使用磁性套索
工具選取你所需要的圖象輪廓--復(fù)制--新建文件(背景使用白色)--粘貼--另存文
件(PSD文件)--用ACDSee等看圖軟件將保存的PSD文件轉(zhuǎn)換為BMP文件face.bmp備用。如
下圖:
程序中引用圖片
打開Borland C++ Builder,在窗體上放置一個(gè)Image控件Image1,其Picture暫為空;
在窗體上放置一個(gè)Popup菜單,編輯菜單項(xiàng)增加“Close”項(xiàng)(添加程序代碼使得激活彈出菜
單時(shí)即可關(guān)閉應(yīng)用程序)。程序中做如下處理:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
< 。
< 。
< 。
Image1->Picture->LoadFromFile(".\\face.bmp");
Width=Image1->Width;
Height=Image1->Height;
Repaint();
< 。
< 。
< 。
}
此時(shí),窗體的大小已能跟隨所用圖片的大小而改變,但仍舊是傳統(tǒng)的WINDOWS界面,要
想顯示成具有圖片輪廓的窗體外形,就需要使用前文介紹的WINDOWS API函數(shù)將不需要顯示
的部分摳去。
摳像方法一
這是一種非常簡(jiǎn)單的方法,采用對(duì)圖片逐行掃描的方式,將圖片像素點(diǎn)為白色的部分摳
去,使用的方法是:在像素點(diǎn)附近產(chǎn)生一個(gè)包含幾個(gè)像素點(diǎn)的矩形,與原圖片采用異或方式
摳去,程序如下:
HRGN tepRgn;
for(y=0;y<Image1->Height;y++)
for(x=0;x<Image1->Width;x++)
if(Image1->Canvas->Pixels[x][y]==clWhite)
{
< tepRgn=CreateRectRgn(x,y,x+1,y+1);
CombineRgn(WndRgn,WndRgn,tepRgn,RGN_XOR);
DeleteObject(tepRgn);
}
這種方法的優(yōu)點(diǎn)是處理比較簡(jiǎn)單,缺點(diǎn)是處理速度太慢,尤其是在處理大幅圖片時(shí),往
往要4~5秒的時(shí)間才能將窗體顯示出來(lái)。因此產(chǎn)生了通過另外的途徑快速勾勒?qǐng)D片輪廓的想
法。
摳像方法二
這次我們采用另一個(gè)WINDOWS API函數(shù)CreatePolygonRgn(多邊形區(qū)域),使用這個(gè)函
數(shù)時(shí)需為它準(zhǔn)備圖片輪廓的坐標(biāo)點(diǎn)數(shù)組及坐標(biāo)點(diǎn)個(gè)數(shù),也是通過對(duì)圖片逐行掃描的方式,找
到白色像素點(diǎn)與非白色像素點(diǎn)的分界點(diǎn),將該點(diǎn)的坐標(biāo)存入數(shù)組中,然后用
CreatePolygonRgn函數(shù)一次就可以把圖片外圍的不用部分摳去,從而省去大量的處理時(shí)間。
程序如下:
register int x,y;
int l,r;
POINT *a;
bool lb,rb;
HRGN WndRgn,TempRgn,;
if((a=(POINT *)malloc(800*2*(sizeof(POINT))))==NULL)
{
ShowMessage("申請(qǐng)內(nèi)存失!");
exit(0);
}
l=0;r=Image1->Height*2-1;
WndRgn=CreateRectRgn(0,0,Image1->Width,Image1->Height);
for(y=0;y<Image1->Height;y++)
{
lb=true;
for(x=0;x<Image1->Width;x++)
if(Image1->Canvas->Pixels[x][y]!=clWhite)
{
a[l].x=x;
a[l].y=y;
lb=false;
break;
}
if(lb) a[l]=a[l-1];
l++;
rb=true;
for(x=Image1->Width-1;x>=0;x--)
if(Image1->Canvas->Pixels[x][y]!=clWhite)
{
a[r].x=x;
a[r].y=y;
rb=false;
break;
}
if(rb) a[r]=a[r+1];
r--;
}
TempRgn=CreatePolygonRgn(a,Image1->Height*2,ALTERNATE);
CombineRgn(WndRgn,WndRgn,TempRgn,RGN_AND);
DeleteObject(TempRgn);
< free(a);
程序中對(duì)每一像素行都從左右兩個(gè)方向分別掃描,找到兩邊的分界點(diǎn)存入數(shù)組。
不過這個(gè)方法也存在一些缺陷,那就是圖片的內(nèi)凹部分輪廓并未表現(xiàn)出來(lái)。從下圖中可
以看出:
最終解決方案
考慮到既不增加算法的復(fù)雜度,又可大幅度縮短不規(guī)則窗體的創(chuàng)建速度,因此采用綜合
以上兩種方案,達(dá)到我們應(yīng)用的目的,程序中首先應(yīng)用方法二對(duì)圖片雙向掃描,產(chǎn)生輪廓坐
標(biāo)點(diǎn)數(shù)組,然后在圖片輪廓內(nèi)應(yīng)用方法一將內(nèi)凹部分摳去,最后才用多邊形區(qū)域創(chuàng)建函數(shù)摳
去圖片外圍部分。程序如下:
void __fastcall TForm1::FormCreate(TObject *Sender)
{
register int x,y;
int l,r;
POINT *a;
bool lb,rb;
HRGN WndRgn,TempRgn,tepRgn;
Width=800;Height=600;
if((a=(POINT *)malloc(800*4*(sizeof(POINT))))==NULL)
{
ShowMessage("申請(qǐng)內(nèi)存失!");
exit(0);
}
Image1->Picture->LoadFromFile(".\\face.bmp");
Width=Image1->Width;
Height=Image1->Height;
Repaint();
l=0;r=Image1->Height*2-1;
WndRgn=CreateRectRgn(0,0,Image1->Width,Image1->Height);
< file://應(yīng)用方法二產(chǎn)生輪廓坐標(biāo)點(diǎn)數(shù)組
for(y=0;y<Image1->Height;y++)
{
lb=true;
for(x=0;x<Image1->Width;x++)
if(Image1->Canvas->Pixels[x][y]!=clWhite)
{
a[l].x=x+1;
a[l].y=y;
lb=false;
break;
}
if(lb) a[l]=a[l-1];
l++;
rb=true;
for(x=Image1->Width-1;x>=0;x--)
if(Image1->Canvas->Pixels[x][y]!=clWhite)
{
a[r].x=x;
a[r].y=y;
rb=false;
break;
}
if(rb) a[r]=a[r+1];
r--;
}
file://應(yīng)用方法一摳去圖片內(nèi)凹部分
r=Image1->Height*2-1;
for(y=0;y<Image1->Height;y++){
for(x=a[y].x;x<a[r].x;x++)
if(Image1->Canvas->Pixels[x][y]==clWhite)
{
< tepRgn=CreateRectRgn(x,y,x+1,y+1);
CombineRgn(WndRgn,WndRgn,tepRgn,RGN_XOR);
DeleteObject(tepRgn);
}
r--;
}
file://將圖片外圍部分摳去
TempRgn=CreatePolygonRgn(a,Image1->Height*2,ALTERNATE);
CombineRgn(WndRgn,WndRgn,TempRgn,RGN_AND);
DeleteObject(TempRgn);
free(a);
file://顯示不規(guī)則窗體
SetWindowRgn(Handle,WndRgn,true);
SetWindowPos(Handle,HWND_TOP,0,0,0,0,SWP_NOMOVE SWP_NOSIZE);
}
r--;
}
file://將圖片外圍部分摳去
TempRgn=CreatePolygonRgn(a,Image1->Height*2,ALTERNATE);
CombineRgn(WndRgn,WndRgn,TempRgn,RGN_AND);
DeleteObject(TempRgn);
free(a);
file://顯示不規(guī)則窗體
SetWindowRgn(Handle,WndRgn,true);
SetWindowPos(Handle,HWND_TOP,0,0,0,0,SWP_NOMOVE SWP_NOSIZE);
}
至此,一個(gè)漂亮的程序界面就出現(xiàn)在你的屏幕上了。