C++Builder 高手进阶
前段时间买了本书《C++ Builder深度历险》,暂且不论这本书写的如何,但其作者独特的写作角度令我折服。于是我就有了个想法,能不能将自己多年从事软件开发的经验写成一系列的文章在CSDN上与大家分享,这样不但可使自己的编程水平得到提高,同时又可与CSDN上众多的高手相互砌磋,又何乐而不为呢?在我的写作计划中,将主要包括《C++Builder 高手进阶 》、《Interbase 使用技巧》、《ODAC使用详解》等一系列内容。其中《C++Builder 高手进阶 》将主要通过实例讲解API函数的应用、用BCB编写组件、BCB在MIS系统中的应用等;《Interbase 使用技巧》(我最喜欢用的数据库Server)则主要讲述其各种使用技巧;《ODAC使用详解》(我用BCB连接ORACLE时的首选)主要是以翻译ODAC的帮助文件为主,并辅以我在实际应用中的技巧。希望我的想法能得到大家的支持!
(三)用BCB设计DBTreeView组件
一、 系统分析
现在使用BCB的以越来越多,可是你有没有意识到,你所使用的控件究竟有几个是用C++编写的?答案肯定让人无法忍受,既然无法忍受何不亲自操刀写一套属于BCB自己的组件呢?我希望从我开始,众位高手能同心协力,共同打造真正属于BCB自己的组件!我不想讲述BCB设计组件的基础知识,因为这些在《C++Builder 5开发人员指南》中有详细的介绍。
我们所设计的DBTreeView派生自TtreeView组件,因此它将具有TtreeView组件的一切特性,我们要做的就是使其具有数据感知能力,与数据直接连接进行直接通信。要构造Tree形结构,我们应使每一个节点具备如下特征:每个节点有一个唯一标识符ID和一个父标识ParentID,(最顶层节点的Parent为空)为了显示相关内容,则还需要一上显示字段FDisplayField。该组件的工作原理已经很清晰了:通过每个节点的ID与ParentID定位数据记录,然后将相关字段内容赋给FdisplayField显示。
二、 开发前沿
该组件中最重的技术莫过于数据感知了,下面就介绍一下数据感知 技术:
要使某个组件成为数据感知的,我们必须给它提供所需的数据连接以便和数据训数据成员通信,这个数据连接类是TFieldDataLink。数据感知组件有其自己的数据连接类,数据连接由组件负责创建、初始化和销毁。建立连接通常需要3步:
1. 将数据连接类(TFieldDataLink)声明为组件的成员;
2. 声明适当的读、写访问属性;
3. 初始化数据连接。
三、 设计流程
//DBTreeView头文件
/在头文件中添加以下三行,因为/数据连接类需要这三个头文件中的声明
#include <Db.hpp>
#include <DbTables.hpp>
#include <DbCtrls.hpp>
//定义事件,用来响应设置节点位图事件
typedef void __fastcall (__closure *TDBTVSetImageIndexEvent)(System::TObject* Sender, int ID, int ParentID, int Level, int& ImageIndex, int& SelectedIndex);
//定义节点结构
struct TDBTreeNodeData
{
int ID; //节点唯一标识
int ParentID; //节点父标识,它为空时表示此节点是最顶层节点
};
class PACKAGE TDBTreeView : public TTreeView
{
private:
TFieldDataLink* FDataLink; //声明数据连接成员
AnsiString FParentIDField; //父标识字段
AnsiString FPrimaryIDField; //主标识字段
AnsiString FDisplayField; //显示字段
bool FActive; //是否为活动状态
bool FAllowModifyDB; //是否允许修改
TDBTVSetImageIndexEvent FOnSetImageIndex; //声明事件
void __fastcall SetActive(bool Value); //设置状态
void __fastcall SetDataSource(Db::TDataSource* Value); //设置数据源
TDataSource* __fastcall GetDataSource(); //取得数据源
void __fastcall ClearAllNodes(); //删除所有节点
void __fastcall FillTreeNodes(int ParentID, TTreeNode* Node); //填充节点
void __fastcall FillChildTreeNodes(int ParentID, TTreeNode* Node, bool Nest = false); //填充子节点
void __fastcall AddDataToNode(TTreeNode* Node, TDBTreeNodeData& Data);//追加数据到节点
protected:
//以下以个方法用来重载TreeView的相关方法
virtual void __fastcall Loaded(void); //Load方法
virtual void __fastcall Notification(Classes::TComponent* AComponent, Classes::TOperation Operation); //事件
DYNAMIC void __fastcall Edit(const tagTVITEMA &Item);//Edit方法
DYNAMIC void __fastcall Expand(TTreeNode* Node);//Expand方法
DYNAMIC void __fastcall KeyDown(Word &Key, Classes::TShiftState Shift);//键盘事件
DYNAMIC void __fastcall Change(TTreeNode* Node);//节点改变事件
virtual bool __fastcall CustomDrawItem(TTreeNode* Node, TCustomDrawState State, TCustomDrawStage Stage, bool &PaintImages);//自绘节点事件
public:
__fastcall TDBTreeView(TComponent* Owner);//构造函数
__fastcall ~TDBTreeView();//析构函数
TDBTreeNodeData __fastcall GetNodeData(TTreeNode* Node);//取得指定节点数据
void __fastcall FullExpand(void); //展开所有节点
__property bool Active = {read = FActive, write = SetActive};//属性活动状态
__published:
//以下定义在属性编辑器中用到的几个属性
__property bool AllowModifyDB = {read = FAllowModifyDB, write = FAllowModifyDB};//是否允许编辑
__property AnsiString ParentIDField = {read = FParentIDField, write = FParentIDField};//父标识
__property AnsiString PrimaryIDField = {read = FPrimaryIDField, write = FPrimaryIDField};//主标识
__property AnsiString DisplayField = {read = FDisplayField, write = FDisplayField};//显示字段
__property TDataSource* DataSource = {read=GetDataSource, write=SetDataSource};//数据源
__property TDBTVSetImageIndexEvent OnSetImageIndex = {read=FOnSetImageIndex, write=FOnSetImageIndex};//设置节点位图事件
};
//下面的类用来填充字段列表
class TFieldNameProperty : public TStringProperty
{
public:
TPropertyAttributes __fastcall GetAttributes(void)
{
return TPropertyAttributes() << paValueList;
}
void __fastcall GetValues(Classes::TGetStrProc Proc);
};
《未完待续》
本文地址:http://com.8s8s.com/it/it29445.htm