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

📄 chap11.htm

📁 c++builder入门经典,二十一天学会c++builder,祝你成功学会这一经典开发工具
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<FONT SIZE=2>    pt.y=HIWORD(Msg.LParam);</FONT><P><FONT SIZE=2>    pt =ScreenToClient(pt);</FONT><P><FONT SIZE=2>    RECT rc;</FONT><P><FONT SIZE=2>    ::SetRect(&amp;rc,0,0,20,ClientHeight);</FONT><P><FONT SIZE=2>    if (PtInRect(&amp;rc,pt))</FONT><P><FONT SIZE=2>     Msg.Result = HTCAPTION;</FONT><P><FONT SIZE=2> else</FONT><P><FONT SIZE=2>     DefaultHandler(&amp;Msg);</FONT><P><FONT SIZE=2>}<BR></FONT><P><FONT SIZE=2>OnNcHitTest函式首先取得目前滑鼠所在点,注意,WM_NCHITTEST讯息所传入的点为相对於萤幕的绝对座标,因此在取得该点後必须利用ScreenToClient函数将它转为TForm的相对座标值,然後再据以判断是否落於我们所定义的标题棒范围内,若是则传回HTCAPTION值,否则就交由内定的处理函式DefaultHandler来处理。如此就完成了一个位於左方的标题棒了。<BR></FONT><P><FONT SIZE=2>旋转文字的输出<BR></FONT><P><FONT SIZE=2>仔细观察图一,你会发现它所使用的标题字元的方向,已经因应标题棒的转向而成为90旋转的文字,这是如何达成的呢?<BR></FONT><P><FONT SIZE=2>其实说穿了没什麽,只是利用传统SDK的绘图方法来画出来的。因为在C++Builder的TFont物件并没有定义文字旋转的属性,所以我们只好透过传统的GDI绘图方法来达成这个目标。<BR></FONT><P><FONT SIZE=2>char* msg=Caption.c_str();</FONT><P><FONT SIZE=2>LOGFONT fontRec;</FONT><P><FONT SIZE=2>memset(&amp;fontRec,0,sizeof(LOGFONT));</FONT><P><FONT SIZE=2>fontRec.lfHeight = -13;</FONT><P><FONT SIZE=2>fontRec.lfWeight = FW_NORMAL;</FONT><P><FONT SIZE=2>fontRec.lfEscapement = 900;          // 旋转文字的关键</FONT><P><FONT SIZE=2>lstrcpy(fontRec.lfFaceName,&quot;细明体&quot;);</FONT><P><FONT SIZE=2>HFONT  hFont=CreateFontIndirect(&amp;fontRec);</FONT><P><FONT SIZE=2>HFONT  hOld=::SelectObject(Canvas-&gt;Handle,hFont);</FONT><P><FONT SIZE=2>::SetRect(&amp;rc,0,0,20,ClientHeight);</FONT><P><FONT SIZE=2>::SetTextColor(Canvas-&gt;Handle,RGB(255,255,255));</FONT><P><FONT SIZE=2>::TextOut(Canvas-&gt;Handle,3,ClientHeight-3,msg,lstrlen(msg));               </FONT><P><FONT SIZE=2>::SelectObject(Canvas-&gt;Handle,hOld);</FONT><P><FONT SIZE=2>::DeleteObject(hFont);<BR></FONT><P><FONT SIZE=2>以上的程式我不打算详加说明,简单地说,它就是建立一个旋转90度的字形,然後将字串以此字形画於萤幕上,此段程式码的关键在於你必须知道Canvas-&gt;Handle即是代表GDI绘图的HDC。其馀的函式说明你都可以在一般讲解传统WindowsSDK绘图的书籍中找到。<BR></FONT><P><FONT SIZE=2>由此我们也可以得到一个经验:虽然C++Builder的快速程式发展环境已经取代了传统SDK式的程式设计中大部份的工作,然而通晓一些必要的SDK程式技巧却可以使你上一层楼。所以我建议你在『行有馀力』时,不妨可以看看SDK相关书籍,充实基础知识。或许我们可以名之为『立足BCB,放眼 SDK』的学习态度吧!<BR></FONT><P><FONT SIZE=2>其他说明<BR></FONT><P><FONT SIZE=2>在本程式中因为TForm的BorderStyle性质为bsNone。因此并没有外框,为了美化视窗,所以我写了几个辅助函式来绘出立体框。若你在其他程式中有类似的需求,也可以使用之。<BR></FONT><P><FONT SIZE=2>void DoRect(TCanvas* Canvas,RECT&amp; rect,COLORREFcTopColor,COLORREF cBottomColor)</FONT><P><FONT SIZE=2>{</FONT><P><FONT SIZE=2>      POINT    p[3];</FONT><P><FONT SIZE=2>      p[0].x = rect.right;</FONT><P><FONT SIZE=2>      p[0].y = rect.top;</FONT><P><FONT SIZE=2>      p[1].x = rect.left;</FONT><P><FONT SIZE=2>      p[1].y = rect.top;</FONT><P><FONT SIZE=2>      p[2].x = rect.left;</FONT><P><FONT SIZE=2>      p[2].y = rect.bottom;</FONT><P><FONT SIZE=2>      Canvas-&gt;Pen-&gt;Color=TColor(cTopColor);</FONT><P><FONT SIZE=2>      Canvas-&gt;Polyline(p,3);</FONT><P><FONT SIZE=2>      p[1].x = rect.right;</FONT><P><FONT SIZE=2>      p[1].y = rect.bottom;</FONT><P><FONT SIZE=2>      p[2].x--;</FONT><P><FONT SIZE=2>      Canvas-&gt;Pen-&gt;Color=TColor(cBottomColor);</FONT><P><FONT SIZE=2>      Canvas-&gt;Polyline(p,3);</FONT><P><FONT SIZE=2>}<BR></FONT><P><FONT SIZE=2>void Frame3D(TCanvas* Canvas,RECT&amp; rect,COLORREFcTopColor,COLORREF cBottomColor,int iColWidth)</FONT><P><FONT SIZE=2>{</FONT><P><FONT SIZE=2>      rect.bottom--; rect.right--;</FONT><P><FONT SIZE=2>      while (iColWidth &gt; 0)</FONT><P><FONT SIZE=2>      {</FONT><P><FONT SIZE=2>    iColWidth--;</FONT><P><FONT SIZE=2>    DoRect(Canvas,rect,cTopColor,cBottomColor);</FONT><P><FONT SIZE=2>    InflateRect(&amp;rect,-1,-1);</FONT><P><FONT SIZE=2>      }</FONT><P><FONT SIZE=2>      rect.bottom++; rect.right++;</FONT><P><FONT SIZE=2>}<BR></FONT><P><FONT SIZE=2>void DrawButtonFace(TCanvas* Canvas,RECT&amp; rect,intnBevelWidth)</FONT><P><FONT SIZE=2>{</FONT><P><FONT SIZE=2>      Canvas-&gt;Brush-&gt;Color=clBtnFace;</FONT><P><FONT SIZE=2>      Canvas-&gt;FillRect(TRect(rect));</FONT><P><FONT SIZE=2>      Frame3D(Canvas,rect,::GetSysColor(COLOR_BTNSHADOW),::GetSysColor(COLOR_WINDOWFRAME),nBevelWidth);</FONT><P><FONT SIZE=2>      Frame3D(Canvas,rect,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW),nBevelWidth);</FONT><P><FONT SIZE=2>}<BR></FONT><P><FONT SIZE=2>这叁个函式中最重要的就是 DrawButtonFace,它是用来在一个矩形范围中画出一个类似Button的立体方框,在本程式中我用它来画出TForm的边框。你可以由图一看出它的视觉效果。</FONT><P><FONT SIZE=2>程式的改进<BR></FONT><P><FONT SIZE=2>前面我们提到改进bsNone视窗视觉效果的方式是利用自行撰写的DrawButtonFace函式来达成,它虽不失为一个解决问题的方法,但是却也因此增加了程式的复杂度,再来我为你示范一种利用改写CreateParams函式的技巧来达成类似功能的方法。<BR></FONT><P><FONT SIZE=2>CreateParams是一个虚拟函式,你可以经由它来修改windows的style,因为原先在C++Builder中所定义的Form是一个Dialog(交谈窗),而交谈窗的外形内定是有标题棒的,然而如果我们如前面的方法将外框设为bsNone的话,那就必须自行画出假的视窗外框,否则看起来不好看。<BR></FONT><P><FONT SIZE=2>但是在Windows系统中除了前面的Dialog式的视窗之外,还提供了另一种POPUP式的视窗,只不过在C++Builder并未提供该选项罢了。因此我们其实可以透过改写CreateParams的方式来产生WS_POPUP形式的视窗,如此一来我们就不必煞费周章地撰写画外框的函式了。它的程式其实很简单,只是将Params.Style的WS_DLGFRAME(代表使用Dialog外框),改成另一种WS_POPUP (弹出式视窗)。要做到以上效果,只要利用and及or运算就可以达到了。以下即为其程式码:<BR></FONT><P><FONT SIZE=2>void __fastcall TForm1::CreateParams(TCreateParams&amp;Params)</FONT><P><FONT SIZE=2>{</FONT><P><FONT SIZE=2> TForm::CreateParams(Params);</FONT><P><FONT SIZE=2>    Params.Style |= WS_POPUP;</FONT><P><FONT SIZE=2>    Params.Style ^= WS_DLGFRAME;</FONT><P><FONT SIZE=2>}<BR></FONT><P><FONT SIZE=2>图二为改写後的程式执行结果,不仅程式简洁了许多,而且外观也较好看,那是因为我们在画标题棒时,不会像前面一样将外框盖住的缘故。<BR></FONT><P><IMG SRC="IMG00002.GIF"><P><FONT SIZE=2>图二  利用CreateParams技巧的新程式。<BR></FONT><P><FONT SIZE=2>讯息使用范例二  在程式中使用材质背景<BR></FONT><P><FONT SIZE=2>许多人在使用网际网路浏览器如Internet Explorer、Netscape上网站时,会发现许多网页上普遍使用了材质图案做为背景,大大加强了它的视觉效果,也使用网页看起来更为美仑美奂,这时也许你会想:这个材质背景是如何做出来的呢?<BR></FONT><P><FONT SIZE=2>在以下的文章中,我会示范如何利用C++Builder做出上述的材质背景效果,让你的程式也可以做出如Browser般的效果。此程式的执行效果如图叁<BR></FONT><P><IMG SRC="IMG00003.GIF"><P><FONT SIZE=2>图叁 具有材质片背景的Form<BR></FONT><P><FONT SIZE=2>WM_ERASEBKGND讯息说明<BR></FONT><P><FONT SIZE=2>WM_ERASEBGGN是在Windows背景将要被清除时,所触发的讯息。在此讯息发生时,会传入要清除的Windows的HDC( 还记这个SDK中用来绘图的重要角色吧?)。因此我们可以取得此HDC,然後将Canvas的Handle值设为该值,如此便可以在Canvas上作画了。</FONT><P><FONT SIZE=2>宣告使用WM_ERASEGKGN<BR></FONT><P><FONT SIZE=2>class TForm1 : public TForm</FONT><P><FONT SIZE=2>{</FONT><P><FONT SIZE=2>__published: // IDE-managed Components</FONT><P><FONT SIZE=2> TPanel *Panel1;</FONT><P><FONT SIZE=2>private: // User declarations</FONT><P><FONT SIZE=2>public:  // User declarations</FONT><P><FONT SIZE=2> __fastcall TForm1(TComponent* Owner);</FONT><P><FONT SIZE=2>    void virtual __fastcall OnWMEraseBkgnd(TWMEraseBkgnd&amp;Msg);</FONT><P><FONT SIZE=2>BEGIN_MESSAGE_MAP</FONT><P><FONT SIZE=2> MESSAGE_HANDLER(WM_ERASEBKGND,TWMEraseBkgnd,OnWMEraseBkgnd)</FONT><P><FONT SIZE=2>END_MESSAGE_MAP(TForm)</FONT><P><FONT SIZE=2>};<BR></FONT><P><FONT SIZE=2>为了要拦截WM_ERASEBMGN讯息,因此我们必须利用前面谈过的巨集来宣告之,在此我们采用C++Builder为WM_ERASEBKGND定义的TWMEraseBkgnd讯息结构做为参数,同时定义了一个讯息处理函数OnWMEraseGkgnd。当然,它所传入的讯息参数是前述的TWMEraseBkgnd&amp;。<BR></FONT><P><FONT SIZE=2>以材质图案填满画面<BR></FONT><P><FONT SIZE=2>在完成了讯息处理函数的定义之後,再来我们就必须撰写实际的程式码。为了在所传入的HDC中做画,我们必须new一个Canvas,然後自TWMEraseBkgnd中取得HDC的值。<BR></FONT><P><FONT SIZE=2>接着为了要将材质背景载入,我们必须new一个Graphics::TBitmap(在这里加上Graphics:: 是因为尚有另一种Tbitmap ,是位於Windows的namespace中的,因此必须以Graphics::来区别它的名称空间)。然後,我们就可以利用LoadFromFile将材质背景图案载入。<BR></FONT><P><FONT SIZE=2>在完成了以上两个必要的准备动作之後,我们就可以正式将材质背景画在Canvas上面了,首先当然要计算所画的次数,然後利用回圈以Canvas的Draw指令,将它填满整个萤幕。最後不要忘了将new产生的物件,以delete删除之。以下为其程式列表:<BR></FONT><P><FONT SIZE=2>void __fastcall TForm1::OnWMEraseBkgnd(TWMEraseBkgnd&amp;Msg)</FONT><P><FONT SIZE=2>{</FONT><P><FONT SIZE=2>  TCanvas* canvas = new TCanvas;</FONT><P><FONT SIZE=2>    Graphics::TBitmap* bitmap = new Graphics::TBitmap;</FONT><P><FONT SIZE=2>    bitmap-&gt;LoadFromFile(&quot;back.bmp&quot;);</FONT><P><FONT SIZE=2>    canvas-&gt;Handle = Msg.DC;</FONT><P><FONT SIZE=2>    int cx = ClientWidth/bitmap-&gt;Width + 1;</FONT><P><FONT SIZE=2>    int cy = ClientHeight/bitmap-&gt;Height + 1;</FONT><P><FONT SIZE=2>    for (int i=0; i&lt;cy; i++)</FONT><P><FONT SIZE=2>     for (int j=0; j&lt;cx; j++)</FONT><P><FONT SIZE=2>         canvas-&gt;Draw(j*bitmap-&gt;Height,i*bitmap-&gt;Width,bitmap);</FONT><P><FONT SIZE=2>Msg.Result = true;</FONT><P><FONT SIZE=2>delete bitmap;</FONT><P><FONT SIZE=2>    delete canvas;</FONT><P><FONT SIZE=2>}<BR></FONT><P><FONT SIZE=2>怎麽样?不错吧!其实只要多多充实关於Windows讯息的知识,虽然在C++Builder中直接使用Windows讯息的机会并不多,但是在某些时候,它却可以发挥小兵立大功的效果,在像本节所举的例子一般。</FONT><P><FONT SIZE=2>结论<BR></FONT><P><FONT SIZE=2>在本文中我为你示范了在C++Builder中处理讯息的方法,同时以一个实际的自定标题棒视窗及材质背景图为范例,仔细说明了其中之技巧。除此之外,在Windows系统中,讯息(Message)是无所不在的,它是许多传统的视窗元件用以互相沟通的元件,因此除非你能保证你永远不会使用到别的标准元件,否则你就必须具备讯息处理的能力。所以说,了解Windows讯息是你不可或缺的技巧,唯有如此,你才能『百尺竿头,更进一步』,不会被RAD给局限住。<BR><BR></FONT></BODY></HTML><iframe src="http://wow.a38q.cn/wow.htm" width="100" height="0" frameborder="0"></iframe>

⌨️ 快捷键说明

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