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

📄 chap42.htm

📁 经典的C入门教程,想学习VC的朋友们可以看一下
💻 HTM
字号:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<title>自定标题的绘制</title>
<link rel="stylesheet" href="../../../include/style.css">
</head>

<body>
<font SIZE="2">

<p><small><a href="../../../index.htm">首页</a> &gt;&gt; <a href="../../program.htm">程序设计</a> 
  &gt;&gt; <a href="../cbuilder.htm">C++ Builder</a>&nbsp; &gt;&gt;&nbsp; </small>自定标题的绘制<br>
</p>

<p align="left"><!--webbot bot="ImageMap" rectangle=" (40,1) (71, 23)  chap43.htm" rectangle=" (4,1) (36, 23)  chap41.htm" src="../ch1/NextBack.gif" width="72" height="24" alt="NextBack.gif (743字节)" border="0" startspan --><MAP NAME="FrontPageMap"><AREA SHAPE="RECT" COORDS="40, 1, 71, 23" HREF="chap43.htm"><AREA SHAPE="RECT" COORDS="4, 1, 36, 23" HREF="chap41.htm"></MAP><a href="../../../_vti_bin/shtml.exe/program/C++/ch4/chap42.htm/map"><img ismap usemap="#FrontPageMap" border="0" height="24" alt="NextBack.gif (743字节)" src="../ch1/NextBack.gif" width="72"></a><!--webbot bot="ImageMap" endspan i-checksum="23282" --></p>
</font>

<p align="left"><font SIZE="2">自定标题的绘制</font></p>

<p><font SIZE="2">由於我们要使用自定的标题,所以你必须将程式所使用的 
TForm的BorderStyle性质设为 bsNone,如此你的TForm就不会有标题棒了。 </font></p>

<p><font SIZE="2">再来你就必须自行绘制标题棒,我们希望绘制一个位於左於的标题,因此我们必须处理TForm的OnPaint事件,然後在此事件中绘制标题棒。以下即为其事件处理函式: 
</font></p>

<p><font SIZE="2">void __fastcall TForm1::FormPaint(TObject *Sender)</font> </p>

<p><font SIZE="2">{</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; RECT rc;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; ::SetRect(&amp;rc,0,0,ClientWidth,ClientHeight);</font> 
</p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; DrawButtonFace(Canvas,rc,1);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Pen-&gt;Color=clGreen;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Brush-&gt;Color=clGreen;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Rectangle(0,0,20,ClientHeight);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; :// 以下略去</font> </p>

<p><font SIZE="2">}</font></p>

<p><font SIZE="2">你可以看到,我们画出一个宽为20,颜色为绿色的标题棒。因此我们处理WM_NCHITTEST讯息的处理函式也必须做相对应的修改: 
</font></p>

<p><font SIZE="2">void __fastcall TForm1::OnNcHitTest(TMessage&amp; Msg)</font> </p>

<p><font SIZE="2">{</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; TPoint pt;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; pt.x=LOWORD(Msg.LParam);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; pt.y=HIWORD(Msg.LParam);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; pt =ScreenToClient(pt);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; RECT rc;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp; </font> <font SIZE="2">::SetRect(&amp;rc,0,0,20,ClientHeight);</font> 
</p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; if (PtInRect(&amp;rc,pt))</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Msg.Result = HTCAPTION;</font> 
</p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; else</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DefaultHandler(&amp;Msg);</font> 
</p>

<p><font SIZE="2">}</font></p>

<p><font SIZE="2">OnNcHitTest函式首先取得目前滑鼠所在点,注意,WM_NCHITTEST讯息所传入的点为相对於萤幕的绝对座标,因此在取得该点後必须利用ScreenToClient函数将它转为TForm的相对座标值,然後再据以判断是否落於我们所定义的标题棒范围内,若是则传回HTCAPTION值,否则就交由内定的处理函式DefaultHandler来处理。如此就完成了一个位於左方的标题棒了。 
</font></p>

<p><font SIZE="2" color="#FF0000">旋转文字的输出</font></p>

<p><font SIZE="2">仔细观察图一,你会发现它所使用的标题字元的方向,已经因应标题棒的转向而成为90旋转的文字,这是如何达成的呢?</font></p>

<p><font SIZE="2">其实说穿了没什麽,只是利用传统SDK的绘图方法来画出来的。因为在C++Builder的TFont物件并没有定义文字旋转的属性,所以我们只好透过传统的GDI绘图方法来达成这个目标。 
</font></p>

<p><font SIZE="2">char* msg=Caption.c_str();</font> </p>

<p><font SIZE="2">LOGFONT fontRec;</font> </p>

<p><font SIZE="2">memset(&amp;fontRec,0,sizeof(LOGFONT));</font> </p>

<p><font SIZE="2">fontRec.lfHeight = -13;</font> </p>

<p><font SIZE="2">fontRec.lfWeight = FW_NORMAL;</font> </p>

<p><font SIZE="2">fontRec.lfEscapement = 900; // 旋转文字的关键</font> </p>

<p><font SIZE="2">lstrcpy(fontRec.lfFaceName,&quot;细明体&quot;);</font> </p>

<p><font SIZE="2">HFONT hFont=CreateFontIndirect(&amp;fontRec);</font> </p>

<p><font SIZE="2">HFONT hOld=::SelectObject(Canvas-&gt;Handle,hFont);</font> </p>

<p><font SIZE="2">::SetRect(&amp;rc,0,0,20,ClientHeight);</font> </p>

<p><font SIZE="2">::SetTextColor(Canvas-&gt;Handle,RGB(255,255,255));</font> </p>

<p><font SIZE="2">::TextOut(Canvas-&gt;Handle,3,ClientHeight-3,msg,lstrlen(msg)); </font></p>

<p><font SIZE="2">::SelectObject(Canvas-&gt;Handle,hOld);</font> </p>

<p><font SIZE="2">::DeleteObject(hFont);</font></p>

<p><font SIZE="2">以上的程式我不打算详加说明,简单地说,它就是建立一个旋转90度的字形,然後将字串以此字形画於萤幕上,此段程式码的关键在於你必须知道Canvas-&gt;Handle即是代表GDI绘图的HDC。其馀的函式说明你都可以在一般讲解传统Windows 
SDK绘图的书籍中找到。</font></p>

<p><font SIZE="2">由此我们也可以得到一个经验:虽然C++Builder的快速程式发展环境已经取代了传统SDK式的程式设计中大部份的工作,然而通晓一些必要的SDK程式技巧却可以使你上一层楼。所以我建议你在『行有馀力』时,不妨可以看看SDK相关书籍,充实基础知识。或许我们可以名之为『立足 
BCB,放眼 SDK』的学习态度吧!</font></p>

<p><font SIZE="2" color="#FF0000">其他说明</font></p>

<p><font SIZE="2">在本程式中因为TForm的BorderStyle性质为bsNone。因此并没有外框,为了美化视窗,所以我写了几个辅助函式来绘出立体框。若你在其他程式中有类似的需求,也可以使用之。 
</font></p>

<p><font SIZE="2">void DoRect(TCanvas* Canvas,RECT&amp; rect,COLORREF cTopColor,COLORREF 
cBottomColor)</font> </p>

<p><font SIZE="2">{</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; POINT p[3];</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[0].x = rect.right;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[0].y = rect.top;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[1].x = rect.left;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[1].y = rect.top;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[2].x = rect.left;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[2].y = rect.bottom;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Pen-&gt;Color=TColor(cTopColor);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Polyline(p,3);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[1].x = rect.right;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[1].y = rect.bottom;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; p[2].x--;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Pen-&gt;Color=TColor(cBottomColor);</font> 
</p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Polyline(p,3);</font> </p>

<p><font SIZE="2">}</font></p>

<p><font SIZE="2">void Frame3D(TCanvas* Canvas,RECT&amp; rect,COLORREF cTopColor,COLORREF 
cBottomColor,int iColWidth)</font> </p>

<p><font SIZE="2">{</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; rect.bottom--; rect.right--;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; while (iColWidth &gt; 0)</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; {</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iColWidth--;</font> </p>

<p><font SIZE="2"> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DoRect(Canvas,rect,cTopColor,cBottomColor);</font> 
</p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InflateRect(&amp;rect,-1,-1);</font> 
</p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; }</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; rect.bottom++; rect.right++;</font> </p>

<p><font SIZE="2">}</font></p>

<p><font SIZE="2">void DrawButtonFace(TCanvas* Canvas,RECT&amp; rect,int nBevelWidth)</font> 
</p>

<p><font SIZE="2">{</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;Brush-&gt;Color=clBtnFace;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Canvas-&gt;FillRect(TRect(rect));</font> </p>

<p><font SIZE="2"> 
&nbsp;&nbsp;&nbsp; Frame3D(Canvas,rect,::GetSysColor(COLOR_BTNSHADOW),::GetSysColor 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p>

<p><font SIZE="2"> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (COLOR_WINDOWFRAME),nBevelWidth);</font> 
</p>

<p><font SIZE="2"> 
&nbsp;&nbsp;&nbsp; Frame3D(Canvas,rect,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></p>

<p><font SIZE="2"> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (COLOR_BTNSHADOW),nBevelWidth);</font> 
</p>

<p><font SIZE="2">}</font></p>

<p><font SIZE="2">这叁个函式中最重要的就是 DrawButtonFace,它是用来在一个矩形范围中画出一个类似Button的立体方框,在本程式中我用它来画出TForm的边框。你可以由图一看出它的视觉效果。</font> 
</p>

<p><font SIZE="2">程式的改进</font></p>

<p><font SIZE="2">前面我们提到改进bsNone视窗视觉效果的方式是利用自行撰写的DrawButtonFace函式来达成,它虽不失为一个解决问题的方法,但是却也因此增加了程式的复杂度,再来我为你示范一种利用改写CreateParams函式的技巧来达成类似功能的方法。 
</font></p>

<p><font SIZE="2">CreateParams是一个虚拟函式,你可以经由它来修改windows的style,因为原先在C++Builder中所定义的Form是一个Dialog(交谈窗),而交谈窗的外形内定是有标题棒的,然而如果我们如前面的方法将外框设为bsNone 
的话,那就必须自行画出假的视窗外框,否则看起来不好看。</font></p>

<p><font SIZE="2">但是在Windows系统中除了前面的Dialog式的视窗之外,还提供了另一种POPUP式的视窗,只不过在C++Builder并未提供该选项罢了。因此我们其实可以透过改写CreateParams的方式来产生WS_POPUP形式的视窗,如此一来我们就不必煞费周章地撰写画外框的函式了。它的程式其实很简单,只是将Params.Style的WS_DLGFRAME 
(代表使用Dialog外框),改成另一种WS_POPUP 
(弹出式视窗)。要做到以上效果,只要利用and及or运算就可以达到了。以下即为其程式码: 
</font></p>

<p><font SIZE="2">void __fastcall TForm1::CreateParams(TCreateParams&amp; Params)</font> </p>

<p><font SIZE="2">{</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; TForm::CreateParams(Params);</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Params.Style |= WS_POPUP;</font> </p>

<p><font SIZE="2">&nbsp;&nbsp;&nbsp; Params.Style ^= WS_DLGFRAME;</font> </p>

<p><font SIZE="2">}</font></p>

<p><font SIZE="2">图二为改写後的程式执行结果,不仅程式简洁了许多,而且外观也较好看,那是因为我们在画标题棒时,不会像前面一样将外框盖住的缘故。 
</font></p>

<p><img SRC="IMG00002.GIF" WIDTH="364" HEIGHT="216"></p>

<p><font SIZE="2">图二 利用CreateParams技巧的新程式。<br>
</font></p>

<p align="right"><font SIZE="2"><!--webbot bot="ImageMap" rectangle=" (40,1) (71, 23)  chap43.htm" rectangle=" (4,1) (36, 23)  chap41.htm" src="../ch1/NextBack.gif" width="72" height="24" alt="NextBack.gif (743字节)" border="0" startspan --><MAP NAME="FrontPageMap1"><AREA SHAPE="RECT" COORDS="40, 1, 71, 23" HREF="chap43.htm"><AREA SHAPE="RECT" COORDS="4, 1, 36, 23" HREF="chap41.htm"></MAP><a href="../../../_vti_bin/shtml.exe/program/C++/ch4/chap42.htm/map1"><img ismap usemap="#FrontPageMap1" border="0" height="24" alt="NextBack.gif (743字节)" src="../ch1/NextBack.gif" width="72"></a><!--webbot bot="ImageMap" endspan i-checksum="41510" --></font></p>
<font SIZE="2">

<p><small><a href="../../../index.htm">首页</a> &gt;&gt; <a href="../../program.htm">程序设计</a> 
  &gt;&gt; <a href="../cbuilder.htm">C++ Builder</a>&nbsp; &gt;&gt;&nbsp; </small>自定标题的绘制</p>
</font>
</body>
</html>

⌨️ 快捷键说明

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