📄 00000003.htm
字号:
RECT rc; <BR>∶<I>:SetRect(&rc,0,0,ClientWidth,ClientHeight); </I><BR>DrawButtonFace(Canvas,rc,1); <BR>Canvas->Pen->Color=clGreen; <BR>Canvas->Brush->Color=clGreen; <BR>Canvas->Rectangle(0,0,20,ClientHeight); <BR>∶<I>// 以下略去 </I><BR>∶<I> </I><BR>} <BR> <BR>你可以看到,我们画出一个宽为20,颜色为绿色的标题棒。因此我们 <BR>处理WM_NCHITTEST讯息的处理函式也必须做相对应的修改: <BR> <BR>void __fastcall TForm1::OnNcHitTest(TMessage& Msg) <BR>{ <BR>TPoint pt; <BR>pt.x=LOWORD(Msg.LParam); <BR>pt.y=HIWORD(Msg.LParam); <BR>pt =ScreenToClient(pt); <BR>RECT rc; <BR>∶<I>:SetRect(&rc,0,0,20,ClientHeight); </I><BR>if (PtInRect(&rc,pt)) <BR>Msg.Result = HTCAPTION; <BR>else <BR>DefaultHandler(&Msg); <BR>} <BR> <BR>OnNcHitTest函式首先取得目前滑鼠所在点,注意,WM_NCHITTEST讯 <BR>息所传入的点为相对於萤幕的绝对座标,因此在取得该点後必须利用 <BR>ScreenToClient函数将它转为TForm的相对座标值,然後再据以判断 <BR>是否落於我们所定义的标题棒范围内,若是则传回HTCAPTION值,否 <BR>则就交由内定的处理函式DefaultHandler来处理。如此就完成了一个 <BR>位於左方的标题棒了。 <BR> <BR> <BR>旋转文字的输出 <BR> <BR>仔细观察图一,你会发现它所使用的标题字元的方向,已经因应标题 <BR>棒的转向而成为90旋转的文字,这是如何达成的呢? <BR> <BR>其实说穿了没什麽,只是利用传统SDK的绘图方法来画出来的。因为 <BR>在C++Builder的TFont物件并没有定义文字旋转的属性,所以我们只 <BR>好透过传统的GDI绘图方法来达成这个目标。 <BR> <BR> <BR>char* msg=Caption.c_str(); <BR>LOGFONT fontRec; <BR>memset(&fontRec,0,sizeof(LOGFONT)); <BR>fontRec.lfHeight = -13; <BR>fontRec.lfWeight = FW_NORMAL; <BR>fontRec.lfEscapement = 900; // 旋转文字的关键 <BR>lstrcpy(fontRec.lfFaceName,"细明体"); <BR>HFONT hFont=CreateFontIndirect(&fontRec); <BR>HFONT hOld=::SelectObject(Canvas->Handle,hFont); <BR>∶<I>:SetRect(&rc,0,0,20,ClientHeight); </I><BR>∶<I>:SetTextColor(Canvas->Handle,RGB(255,255,255)); </I><BR>∶<I>:TextOut(Canvas->Handle,3,ClientHeight-3,msg,lstrlen(msg)); </I><BR>∶<I>:SelectObject(Canvas->Handle,hOld); </I><BR>∶<I>:DeleteObject(hFont); </I><BR> <BR>以上的程式我不打算详加说明,简单地说,它就是建立一个旋转90度 <BR>的字形,然後将字串以此字形画於萤幕上,此段程式码的关键在於你 <BR>必须知道Canvas->Handle即是代表GDI绘图的HDC。其馀的函式说明 <BR>你都可以在一般讲解传统Windows <BR>SDK绘图的书籍中找到。 <BR> <BR>由此我们也可以得到一个经验:虽然C++Builder的快速程式发展环境 <BR>已经取代了传统SDK式的程式设计中大部份的工作,然而通晓一些必 <BR>要的SDK程式技巧却可以使你上一层楼。所以我建议你在『行有馀力』 <BR>时,不妨可以看看SDK相关书籍,充实基础知识。或许我们可以名之 <BR>为『立足 <BR>BCB,放眼 SDK』的学习态度吧! <BR> <BR>其他说明 <BR> <BR>在本程式中因为TForm的BorderStyle性质为bsNone。因此并没有外 <BR>框,为了美化视窗,所以我写了几个辅助函式来绘出立体框。若你在 <BR>其他程式中有类似的需求,也可以使用之。 <BR> <BR> <BR>void DoRect(TCanvas* Canvas,RECT& rect,COLORREF <BR>cTopColor,COLORREF cBottomColor) <BR> <BR>{ <BR>POINT p[3]; <BR>p[0].x = rect.right; <BR>p[0].y = rect.top; <BR>p[1].x = rect.left; <BR>p[1].y = rect.top; <BR>p[2].x = rect.left; <BR>p[2].y = rect.bottom; <BR>Canvas->Pen->Color=TColor(cTopColor); <BR>Canvas->Polyline(p,3); <BR>p[1].x = rect.right; <BR>p[1].y = rect.bottom; <BR>p[2].x--; <BR>Canvas->Pen->Color=TColor(cBottomColor); <BR>Canvas->Polyline(p,3); <BR>} <BR> <BR>void Frame3D(TCanvas* Canvas,RECT& rect,COLORREF <BR>cTopColor,COLORREF <BR>cBottomColor,int iColWidth) <BR>{ <BR>rect.bottom--; rect.right--; <BR>while (iColWidth > 0) <BR>{ <BR>iColWidth--; <BR>DoRect(Canvas,rect,cTopColor,cBottomColor); <BR>InflateRect(&rect,-1,-1); <BR>} <BR>rect.bottom++; rect.right++; <BR>} <BR> <BR>void DrawButtonFace(TCanvas* Canvas,RECT& rect,int nBevelWidth) <BR>{ <BR>Canvas->Brush->Color=clBtnFace; <BR>Canvas->FillRect(TRect(rect)); <BR>Frame3D(Canvas,rect,::GetSysColor(COLOR_BTNSHADOW),::GetSysCo <BR>lor(COLOR_WINDOWFRAME),nBevelWidth); <BR> <BR>Frame3D(Canvas,rect,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSy <BR>sColor(COLOR_BTNSHADOW),nBevelWidth); <BR> <BR>} <BR> <BR>这三个函式中最重要的就是 <BR>DrawButtonFace,它是用来在一个矩形范围中画出一个类似Button的 <BR>立体方框,在本程式中我用它来画出TForm的边框。你可以由图一看 <BR>出它的视觉效果。 <BR> <BR>程式的改进 <BR> <BR>前面我们提到改进bsNone视窗视觉效果的方式是利用自行撰写的 <BR>DrawButtonFace函式来达成,它虽不失为一个解决问题的方法,但是 <BR>却也因此增加了程式的复杂度,再来我为你示范一种利用改写 <BR>CreateParams函式的技巧来达成类似功能的方法。 <BR> <BR> <BR>CreateParams是一个虚拟函式,你可以经由它来修改windows的 <BR>style,因为原先在C++Builder中所定义的Form是一个Dialog(交谈 <BR>窗),而交谈窗的外形内定是有标题棒的,然而如果我们如前面的方法 <BR>将外框设为bsNone <BR>的话,那就必须自行画出假的视窗外框,否则看起来不好看。 <BR> <BR>但是在Windows系统中除了前面的Dialog式的视窗之外,还提供了另 <BR>一种POPUP式的视窗,只不过在C++Builder并未提供该选项罢了。因 <BR>此我们其实可以透过改写CreateParams的方式来产生WS_POPUP形式 <BR>的视窗,如此一来我们就不必煞费周章地撰写画外框的函式了。它的 <BR>程式其实很简单,只是将Params.Style的WS_DLGFRAME <BR>(代表使用Dialog外框),改成另一种WS_POPUP (弹出式视窗)。要 <BR>做到以上效果,只要利用and及or运算就可以达到了。以下即为其程 <BR>式码: <BR> <BR>void __fastcall TForm1::CreateParams(TCreateParams& Params) <BR>{ <BR>TForm::CreateParams(Params); <BR>Params.Style |= WS_POPUP; <BR>Params.Style ^= WS_DLGFRAME; <BR>} <BR> <BR>图二为改写後的程式执行结果,不仅程式简洁了许多,而且外观也较 <BR>好看,那是因为我们在画标题棒时,不会像前面一样将外框盖住的缘 <BR>故。 <BR> <BR> <BR>图二 利用CreateParams技巧的新程式。 <BR> <BR>讯息使用范例二 在程式中使用材质背景 <BR> <BR>许多人在使用网际网路浏览器如Internet <BR>Explorer、Netscape上网站时,会发现许多网页上普遍使用了材质图 <BR>案做为背景,大大加强了它的视觉效果,也使用网页看起来更为美仑 <BR>美奂,这时也许你会想:这个材质背景是如何做出来的呢? <BR> <BR> <BR>在以下的文章中,我会示范如何利用C++Builder做出上述的材质背景 <BR>效果,让你的程式也可以做出如Browser般的效果。此程式的执行效 <BR>果如图三 <BR> <BR> <BR>图三 具有材质片背景的Form <BR> <BR>WM_ERASEBKGND讯息说明 <BR> <BR>WM_ERASEBGGN是在Windows背景将要被清除时,所触发的讯息。在此 <BR>讯息发生时,会传入要清除的Windows的HDC ( <BR>还记这个SDK中用来绘图的重要角色吧?)。因此我们可以取得此HDC, <BR>然後将Canvas的Handle值设为该值,如此便可以在Canvas上作画了。 <BR>宣告使用WM_ERASEGKGN <BR> <BR>class TForm1 : public TForm <BR>{ <BR>__published: // IDE-managed Components <BR>TPanel *Panel1; <BR>private: // User declarations <BR>public: // User declarations <BR>__fastcall TForm1(TComponent* Owner); <BR>void virtual __fastcall OnWMEraseBkgnd(TWMEraseBkgnd& Msg); <BR>BEGIN_MESSAGE_MAP <BR>MESSAGE_HANDLER(WM_ERASEBKGND,TWMEraseBkgnd,OnWMEraseBkgnd) <BR>END_MESSAGE_MAP(TForm) <BR>}; <BR> <BR>为了要拦截WM_ERASEBMGN讯息,因此我们必须利用前面谈过的巨集来 <BR>宣告之,在此我们采用C++Builder为WM_ERASEBKGND定义的 <BR>TWMEraseBkgnd讯息结构做为叁数,同时定义了一个讯息处理函数 <BR>OnWMEraseGkgnd。当然,它所传入的讯息叁数是前述的 <BR>TWMEraseBkgnd&。 <BR> <BR>以材质图案填满画面 <BR> <BR>在完成了讯息处理函数的定义之後,再来我们就必须撰写实际的程式 <BR>码。为了在所传入的HDC中做画,我们必须new一个 <BR>Canvas,然後自TWMEraseBkgnd中取得HDC的值。 <BR> <BR>接着为了要将材质背景载入,我们必须new一个Graphics::TBitmap (在 <BR>这里加上Graphics:: 是因为尚有另一种Tbitmap <BR>,是位於Windows的namespace中的,因此必须以Graphics:: <BR>来区别它的名称空间)。然後,我们就可以利用LoadFromFile将材质 <BR>背景图案载入。 <BR> <BR>在完成了以上两个必要的准备动作之後,我们就可以正式将材质背景 <BR>画在Canvas上面了,首先当然要计算所画的次数,然後利用
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -