⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 20000916007.htm

📁 C++Builder教学大全
💻 HTM
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML><HEAD><TITLE>C++Builder中不规则窗体的快速显示</TITLE>

<META content="text/html; charset=gb2312" http-equiv=Content-Type>

<META content="Microsoft FrontPage 4.0" name=GENERATOR></HEAD>

<BODY aLink=#ff0000 bgColor=#ffffff leftMargin=0 link=#187800 topMargin=0 

vLink=#990099>

<DIV align=center>

<TABLE border=0 cellPadding=0 cellSpacing=0 height=76 width=744>

  <TBODY>

  <TR>

    <TD>

      <P align=center><FONT 

      size=3><BR><B>C++Builder中不规则窗体的快速显示</B></FONT><BR><SPAN class=nava><FONT 

      color=#cc9933> 陶志才·yesky</FONT></SPAN></P>

      <P><B>不规则窗体的应用增加软件的吸引力</B><BR>  传统的WINDOWS应用软件界面给人的感觉总是千篇一律的方方正正的窗体,看的时间长了难免会有些厌烦,总是希望能见到些不同一般的软件界面。如今,相当数量的商业软件在提供优秀而强大的功能的同时,软件的界面也是做得越来越漂亮,比如《超级解霸2000》中的界面插件,使用过的人一定对其华丽的外观充满好感。作为一个编程爱好者,如果自己写出的软件也拥有类似的界面,也许会吸引更多目光的注视。那么,我们现在就开始动手制作自己的漂亮界面吧。 

      <BR>技术内幕<BR>  要想在自己的程序中加入不规则窗体的应用,你首先要熟悉几个WINDOWS  

      API函数的使用,它们是:椭圆形(或圆形)区域创建函数CreateEllipticRgn 、多边形区域创建函数CreatePolygonRgn、  

      矩形区域创建函数CreateRectRgn、  

      带圆角的矩形区域创建函数CreateRoundRectRgn。你可以用这些函数创建不同类型的窗体区域,也可以用WINDOWS  

      API函数CombineRgn将几个简单区域组合成一个复杂区域。</P> 

      <P>  下一步要做的就是将已经创建好的区域显示在屏幕上,同样也是使用WINDOWS API  

      函数来实现,这次用到的是SetWindowRgn函数。</P> 

      <P>  WINDOWS API 函数在Borland C++ Builder  

      头文件中均已定义,在应用程序中使用这些API函数就象使用C++的普通库函数一样。</P> 

      <P><B>准备工作</B><BR>  为你的程序准备一幅背景图片,推荐方法是:  

      在PhotoShop中打开图片后使用磁性套索工具选取你所需要的图象轮廓——复制——新建文件(背景使用白色)——粘贴——另存文件(PSD文件)——用ACDSee等看图软件将保存的PSD文件转换为BMP文件face.bmp备用。如下图:</P> 

      <P align=center><IMG height=341 src="images/mihu090701.jpeg"  

      width=463 v:shapes="_x0000_i1025"  

      tppabs="http://www.info365.com.cn/develop/bcb/img/mihu090701.jpeg"><BR></P> 

      <P><B>程序中引用图片</B><BR>  打开Borland C++  

      Builder,在窗体上放置一个Image控件Image1,其Picture暂为空;在窗体上放置一个Popup菜单,编辑菜单项增加“Close”项(添加程序代码使得激活弹出菜单时即可关闭应用程序)。程序中做如下处理:</P> 

      <P>void __fastcall TForm1::FormCreate(TObject *Sender)</P> 

      <P>{</P> 

      <P>&lt; 。</P> 

      <P>&lt; 。</P> 

      <P>&lt; 。</P> 

      <P>Image1-&gt;Picture-&gt;LoadFromFile(".\\face.bmp");</P> 

      <P>Width=Image1-&gt;Width;</P> 

      <P>Height=Image1-&gt;Height;</P> 

      <P>Repaint();</P> 

      <P>&lt; 。</P> 

      <P>&lt; 。</P> 

      <P>&lt; 。</P> 

      <P>}</P> 

      <P>  此时,窗体的大小已能跟随所用图片的大小而改变,但仍旧是传统的WINDOWS界面,要想显示成具有图片轮廓的窗体外形,就需要使用前文介绍的WINDOWS  

      API函数将不需要显示的部分抠去。</P> 

      <P>抠像方法一<BR>  这是一种非常简单的方法,采用对图片逐行扫描的方式,将图片像素点为白色的部分抠去,使用的方法是:在像素点附近产生一个包含几个像素点的矩形,与原图片采用异或方式抠去,程序如下:</P> 

      <P>HRGN tepRgn;</P> 

      <P>for(y=0;y&lt;Image1-&gt;Height;y++)</P> 

      <P>for(x=0;x&lt;Image1-&gt;Width;x++)</P> 

      <P>if(Image1-&gt;Canvas-&gt;Pixels[x][y]==clWhite)</P> 

      <P>{</P> 

      <P>&lt; tepRgn=CreateRectRgn(x,y,x+1,y+1);</P> 

      <P>CombineRgn(WndRgn,WndRgn,tepRgn,RGN_XOR);</P> 

      <P>DeleteObject(tepRgn);</P> 

      <P>}</P> 

      <P>  这种方法的优点是处理比较简单,缺点是处理速度太慢,尤其是在处理大幅图片时,往往要4~5秒的时间才能将窗体显示出来。因此产生了通过另外的途径快速勾勒图片轮廓的想法。</P>

      <P><B>抠像方法二</B><BR>  这次我们采用另一个WINDOWS  

      API函数CreatePolygonRgn(多边形区域),使用这个函数时需为它准备图片轮廓的坐标点数组及坐标点个数,也是通过对图片逐行扫描的方式,找到白色像素点与非白色像素点的分界点,将该点的坐标存入数组中,然后用CreatePolygonRgn函数一次就可以把图片外围的不用部分抠去,从而省去大量的处理时间。程序如下:</P> 

      <P>register int x,y;</P> 

      <P>int l,r;</P> 

      <P>POINT *a;</P> 

      <P>bool lb,rb;</P> 

      <P>HRGN WndRgn,TempRgn,;</P> 

      <P>if((a=(POINT *)malloc(800*2*(sizeof(POINT))))==NULL)</P> 

      <P>{</P> 

      <P>ShowMessage("申请内存失败!");</P> 

      <P>exit(0);</P> 

      <P>}</P> 

      <P>l=0;r=Image1-&gt;Height*2-1;</P> 

      <P>WndRgn=CreateRectRgn(0,0,Image1-&gt;Width,Image1-&gt;Height);</P> 

      <P>for(y=0;y&lt;Image1-&gt;Height;y++)</P> 

      <P>{</P> 

      <P>lb=true;</P> 

      <P>for(x=0;x&lt;Image1-&gt;Width;x++)</P> 

      <P>if(Image1-&gt;Canvas-&gt;Pixels[x][y]!=clWhite)</P> 

      <P>{</P> 

      <P>a[l].x=x;</P> 

      <P>a[l].y=y;</P> 

      <P>lb=false;</P> 

      <P>break;</P> 

      <P>}</P> 

      <P>if(lb) a[l]=a[l-1];</P> 

      <P>l++;</P> 

      <P></P> 

      <P>rb=true;</P> 

      <P>for(x=Image1-&gt;Width-1;x&gt;=0;x--)</P> 

      <P>if(Image1-&gt;Canvas-&gt;Pixels[x][y]!=clWhite)</P> 

      <P>{</P> 

      <P>a[r].x=x;</P> 

      <P>a[r].y=y;</P> 

      <P>rb=false;</P> 

      <P>break;</P> 

      <P>}</P> 

      <P>if(rb) a[r]=a[r+1];</P> 

      <P>r--;</P> 

      <P>}</P> 

      <P>TempRgn=CreatePolygonRgn(a,Image1-&gt;Height*2,ALTERNATE);</P> 

      <P>CombineRgn(WndRgn,WndRgn,TempRgn,RGN_AND);</P> 

      <P>DeleteObject(TempRgn);</P> 

      <P>&lt; free(a);</P> 

      <P>  程序中对每一像素行都从左右两个方向分别扫描,找到两边的分界点存入数组。</P>

      <P>  不过这个方法也存在一些缺陷,那就是图片的内凹部分轮廓并未表现出来。从下图中可以看出:</P>

      <P align=center><IMG height=355 src="images/mihu090702.jpeg" 

      width=499 v:shapes="_x0000_i1026" 

      tppabs="http://www.info365.com.cn/develop/bcb/img/mihu090702.jpeg"><BR>最终解决方案<BR>  考虑到既不增加算法的复杂度,又可大幅度缩短不规则窗体的创建速度,因此采用综合以上两种方案,达到我们应用的目的,程序中首先应用方法二对图片双向扫描,产生轮廓坐标点数组,然后在图片轮廓内应用方法一将内凹部分抠去,最后才用多边形区域创建函数抠去图片外围部分。程序如下:</P>

      <P>void __fastcall TForm1::FormCreate(TObject *Sender)</P> 

      <P>{</P> 

      <P>register int x,y;</P> 

      <P>int l,r;</P> 

      <P>POINT *a;</P> 

      <P>bool lb,rb;</P> 

      <P>HRGN WndRgn,TempRgn,tepRgn;</P> 

      <P></P> 

      <P>Width=800;Height=600;</P> 

      <P>if((a=(POINT *)malloc(800*4*(sizeof(POINT))))==NULL)</P> 

      <P>{</P> 

      <P>ShowMessage("申请内存失败!");</P> 

      <P>exit(0);</P> 

      <P>}</P> 

      <P>Image1-&gt;Picture-&gt;LoadFromFile(".\\face.bmp");</P> 

      <P>Width=Image1-&gt;Width;</P> 

      <P>Height=Image1-&gt;Height;</P> 

      <P>Repaint();</P> 

      <P>l=0;r=Image1-&gt;Height*2-1;</P> 

      <P>WndRgn=CreateRectRgn(0,0,Image1-&gt;Width,Image1-&gt;Height);</P> 

      <P>&lt; //应用方法二产生轮廓坐标点数组</P> 

      <P>for(y=0;y&lt;Image1-&gt;Height;y++)</P> 

      <P>{</P> 

      <P>lb=true;</P> 

      <P>for(x=0;x&lt;Image1-&gt;Width;x++)</P> 

      <P>if(Image1-&gt;Canvas-&gt;Pixels[x][y]!=clWhite)</P> 

      <P>{</P> 

      <P>a[l].x=x+1;</P> 

      <P>a[l].y=y;</P> 

      <P>lb=false;</P> 

      <P>break;</P> 

      <P>}</P> 

      <P>if(lb) a[l]=a[l-1];</P> 

      <P>l++;</P> 

      <P></P> 

      <P>rb=true;</P> 

      <P>for(x=Image1-&gt;Width-1;x&gt;=0;x--)</P> 

      <P>if(Image1-&gt;Canvas-&gt;Pixels[x][y]!=clWhite)</P> 

      <P>{</P> 

      <P>a[r].x=x;</P> 

      <P>a[r].y=y;</P> 

      <P>rb=false;</P> 

      <P>break;</P> 

      <P>}</P> 

      <P>if(rb) a[r]=a[r+1];</P> 

      <P>r--;</P> 

      <P>}</P> 

      <P>//应用方法一抠去图片内凹部分</P> 

      <P>r=Image1-&gt;Height*2-1;</P> 

      <P>for(y=0;y&lt;Image1-&gt;Height;y++){</P> 

      <P>for(x=a[y].x;x&lt;a[r].x;x++)</P> 

      <P>if(Image1-&gt;Canvas-&gt;Pixels[x][y]==clWhite)</P> 

      <P>{</P> 

      <P>&lt; tepRgn=CreateRectRgn(x,y,x+1,y+1);</P> 

      <P>CombineRgn(WndRgn,WndRgn,tepRgn,RGN_XOR);</P> 

      <P>DeleteObject(tepRgn);</P> 

      <P>}</P> 

      <P>r--;</P> 

      <P>} </P> 

      <P>//将图片外围部分抠去</P> 

      <P>TempRgn=CreatePolygonRgn(a,Image1-&gt;Height*2,ALTERNATE);</P> 

      <P>CombineRgn(WndRgn,WndRgn,TempRgn,RGN_AND);</P> 

      <P>DeleteObject(TempRgn);</P> 

      <P>free(a);</P> 

      <P>//显示不规则窗体</P> 

      <P>SetWindowRgn(Handle,WndRgn,true);</P> 

      <P>SetWindowPos(Handle,HWND_TOP,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);</P> 

      <P>}</P> 

      <P></P> 

      <P>至此,一个漂亮的程序界面就出现在你的屏幕上了。见下图:</P> 

      <P align=center><IMG height=335 src="images/mihu090703.jpeg"  

      width=391 v:shapes="_x0000_i1027"  

      tppabs="http://www.info365.com.cn/develop/bcb/img/mihu090703.jpeg"></P> 

      <P><BR>  以上程序在Celeron466、WIN98SE和WIN2000、C++ Builder5.0下调试通过。</P> 

      <P>如有疑问,请致函 taozc@sina.com.cn 。</P> 

      <P></P></TD></TR></TBODY></TABLE></DIV></BODY></HTML> 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -