完善Borland C++ Builder可视化控件功能三例
王光红
笔者在编程中积累了点滴经验,与各位交流,共同提高。
一. 让PageControl的TabSheet“弹出来”
弹出来的效果
用过PageControl的人知道,PageControl之ActivePage的标头较“平坦”,没有“弹出”的立体效果,笔者经过改进达到了“弹出”的效果。
在OnDrawTab事件中加入以下代码:
void __fastcall TSqlBuilderForm::PageControl1DrawTab(
TCustomTabControl *Control, int TabIndex, const TRect &Rect,
bool Active)
{
Byte Red0,Red1,Green0,Green1,Blue0,Blue1;
if(Active)
{
Red0 = 0;
Red1 = 15;
Green0 = 55;
Green1 = 200;
Blue0 = 135;
Blue1 = 240;
}
else
{
Red0 = 51;
Red1 = 101;
Green0 = 91;
Green1 = 200;
Blue0 = 91;
Blue1 = 200;
}
int h;
h = Rect.Bottom - Rect.Top - 2;
Byte clr,clg,clb;
int clTmp;
int i = 0;
float c=0.4; //亮的位置
SetBkMode(Control->Canvas->Handle,TRANSPARENT);
for(; i< h * c; ++i)
{
clTmp = Red0 + floor((double)i / double( h ) * (double)(Red1 - Red0) + 0.5) / c;
if(clTmp < 0 ) clTmp = 0 ;
else if(clTmp > 255) clTmp = 255;
clr = Byte(clTmp);
clTmp = Green0 + floor((double)i / double( h ) * (double)(Green1 - Green0) + 0.5) / c;
if(clTmp < 0 ) clTmp = 0 ;
else if(clTmp > 255) clTmp = 255;
clg = Byte(clTmp);
clTmp = Blue0 + floor((double)i / double( h ) * (double)(Blue1 - Blue0) + 0.5) / c;
if(clTmp < 0 ) clTmp = 0 ;
else if(clTmp > 255) clTmp = 255;
clb = Byte(clTmp);
Control->Canvas->Pen->Color = TColor(RGB(clr,clg,clb));
Control->Canvas->MoveTo(Rect.Left + 1,Rect.Top + i + 1 );
Control->Canvas->LineTo(Rect.Right - 2,Rect.Top + i + 1 );
}
for( ; i< h ; ++i)
{
clTmp = Red0 + floor((double)(h-i) / double( h ) * (double)(Red1 - Red0) + 0.5);
if(clTmp < 0 ) clTmp = 0 ;
else if(clTmp > 255) clTmp = 255;
clr = Byte(clTmp);
clTmp = Green0 + floor((double)(h-i) / double( h ) * (double)(Green1 - Green0) + 0.5);
if(clTmp < 0 ) clTmp = 0 ;
else if(clTmp > 255) clTmp = 255;
clg = Byte(clTmp);
clTmp = Blue0 + floor((double)(h-i) / double( h ) * (double)(Blue1 - Blue0) + 0.5);
if(clTmp < 0 ) clTmp = 0 ;
else if(clTmp > 255) clTmp = 255;
clb = Byte(clTmp);
Control->Canvas->Pen->Color = TColor(RGB(clr,clg,clb));
Control->Canvas->MoveTo(Rect.Left + 1,Rect.Top + i + 1 );
Control->Canvas->LineTo(Rect.Right - 2,Rect.Top + i + 1 );
}
AnsiString str = PageControl1->Pages[TabIndex]->Caption;
int offset=0;
if(PageControl1->Images!=NULL && ! Active ){
Graphics::TBitmap * bmp = new Graphics::TBitmap;
TImageList * img =dynamic_cast<TImageList*>( PageControl1->Images);
img->GetBitmap(PageControl1->Pages[TabIndex]->ImageIndex,bmp); Control->Canvas->Draw(Rect.Left+2,Rect.Top+1,bmp);
offset= bmp->Width-10;
delete bmp; bmp = NULL;
}
Control->Canvas->TextOut( Rect.Left +offset + (Rect.Right - Rect.Left - Control->Canvas->TextWidth(str)) / 2,
Rect.Top + (Rect.Bottom - Rect.Top - Control->Canvas->TextHeight(str)) / 2,
str);
}
二. 让StringGrid“画出”斑马线:
不同的颜色
StringGrid的每一行都是一样的颜色,Cell多了容易看错位,我们可以在OnDrawCell事件中把相邻的Row之间“画出”不同的色彩,让人一目了然,不再会看花了眼。
void __fastcall TForm::StringGridDrawCell(TObject *Sender,
int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid * SG = dynamic_cast<TStringGrid *>(Sender);
if(SG){
try
{
if(ARow>=SG->FixedRows && ACol>=SG->FixedCols)
{
if(ARow%2 == 0)
{
SG->Canvas->Brush->Color=(TColor) 0x00E6FADC;
}
else
{
SG->Canvas->Brush->Color=(TColor)0x00FBEFD5;
}
}
else{
SG->Canvas->Font->Color = clBlack;
SG->Canvas->Brush->Color=(TColor)0x00DDDDDD;
}
SG->Canvas->FillRect(Rect);
DrawText(SG->Canvas->Handle, SG->Cells[ACol][ARow].c_str(), -1, (RECT*)&Rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
}
catch(Exception &exception)
{
Application->ShowException(&exception);
return ;
}
}
}
三. 让ComboBox自动拉开菜单
使用ComboBox 时,您必须点击它的
,下拉菜单才会打开,有点不方便。笔者继承ComboBox,制作了一个命名Autocombobox的控件,当鼠标进入Autocombobox区域,它会自动打开下拉菜单。代码如下:
.h
//---------------------------------------------------------------------------
#ifndef AutoComboBoxH
#define AutoComboBoxH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
//---------------------------------------------------------------------------
class PACKAGE TAutoComboBox : public TComboBox
{
private:
TTimer *Timer;
RECT r;
void __fastcall NewComboBoxWP(TMessage &Msg);
void __fastcall TimerTimer(TObject *Sender);
void __fastcall (__closure *OldComboBoxWP)(TMessage &Message);
protected:
public:
__fastcall TAutoComboBox(TComponent* Owner);
__fastcall ~TAutoComboBox(void);
__published:
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
.cpp
#include <vcl.h>
#pragma hdrstop
#include "AutoComboBox.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TAutoComboBox *)
{
new TAutoComboBox(NULL);
}
//---------------------------------------------------------------------------
__fastcall TAutoComboBox::TAutoComboBox(TComponent* Owner)
: TComboBox(Owner)
{
Timer = new TTimer(this);
Timer->Enabled=false;
Timer->Interval=200;
Timer->OnTimer=TimerTimer;
OldComboBoxWP = this->WindowProc;
this->WindowProc = NewComboBoxWP;
}
__fastcall TAutoComboBox::~TAutoComboBox(void)
{
delete Timer;
}
//---------------------------------------------------------------------------
namespace Autocombobox
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TAutoComboBox)};
RegisterComponents("WghSoft", classes, 0);
}
}
//---------------------------------------------------------------------------
void __fastcall TAutoComboBox::TimerTimer(TObject *Sender)
{
POINT pos;
GetCursorPos(&pos);
if(!(pos.x>r.left && pos.x<r.right && pos.y >r.top && pos.y < r.bottom)){
this->DroppedDown=false;
Timer->Enabled=false;
}
}
//---------------------------------------------------------------------------
void __fastcall TAutoComboBox::NewComboBoxWP(TMessage& msg)
{
switch (msg.Msg)
{
case CM_MOUSEENTER:
{
this->DroppedDown=true;
msg.Result = true;
break;
}
case CM_MOUSELEAVE:
{
POINT pos;
Timer->Enabled=true;
GetCursorPos(&pos);
this->Perform(CB_GETDROPPEDCONTROLRECT,0,LPARAM(&r));
if(!(pos.x>r.left && pos.x<r.right && pos.y >r.top && pos.y < r.bottom)){
this->DroppedDown=false;
Timer->Enabled=false;
}
msg.Result = true;
break;
}
case WM_DESTROY:
{
break;
}
}
OldComboBoxWP(msg);
}