分页(查询)是客户端开发经常面临的问题.
经常性或者带有普遍性的问题, 好的对策是用抽象,而不是重复。
重复行为没有价值,而且有害,浪费资源(开发者资源,发布,运行时资源),代码臃肿,增加阅读和维护困难,弄不好牵一发而动全身。
程序的原始目的之一是把重复的事情交给系统自动完成,重复开发的结果是程序员在程序级别的同样行为。
当产生重复的冲动,需要ctrl+c/ctrl+v时,通常意味着结构性的提升机会出现,应该停下来去思考了,而不是去堆砌代码。
这种情况说明有被设计师忽略的事实,实际上对于一个非完全模式化有可因循的案例的系统,很难预见到一切.
通过实现分页处理器,可以简化客户端分页功能的开发。
在简化开发方面有以下参考原则:
.问自己能够再简化吗?
.通用不等于万能:清楚地认识能力和缺陷,不要强求
客户端在实现分页功能的场景如下:
在查询较大的数据量时,无法(也没有必要)一次全部获取结果,用户需要分次从服务器获取,浏览所关心的信息。
有价值的分页信息包括:总记录数,页数,当前页记录数.
用户可以通过界面控件在这些页之间导航,常用的有"下一页",下一页",到"首页",到"尾页",直接跳转到某页"Goto".
分页结果有几十页已经算是上限了,超过这个范围已经没有实际操作意义了,应该审视应用规划是否存在问题,如统计角度不实用。
使用分页处理器的步骤:
1.创建一个分页处理器
2.把分页处理器与控件绑定,设置页处理函数(页处理函数负责业务逻辑)
3.实现页处理函数
todo:
.按钮支持TLabel
.Goto支持:TEdit,TSpinEdit(TUpdown+TEdit)
.内部创建界面控件
.VCL组件化
*构造大型设备也是从零件入手,不要做成铁板一块的系统.
系统构造的几个要素是:组件,接口,活动机制(组件间协调)
头文件中声明分页处理器对象
#include "page_op.h"
//---------------------------------------------------------------------------
class TfrmGoodsResult : public TfrmBase1 {
///....
private:
CPageOp<TSpeedButton> page_op_; ///< 分页操作对象
int Query(unsigned int page_no);
};
实现文件中绑定控件,设置页处理函数
//---------------------------------------------------------------------------
void __fastcall TfrmGoodsResult::FormCreate(TObject *Sender)
{
page_op_.SetControl(btFirst,btBack,btNext,btLast,cbPageNo);
page_op_.SetAction(new CPageAction<TfrmGoodsResult>(this,&TfrmGoodsResult::Query));
}
//---------------------------------------------------------------------------
///< 页处理函数
///< 如:构造请求包向服务器请求
int TfrmGoodsResult::Query(unsigned int page_no) {
CMsg *pMsg = new CMsg;
pMsg->SetMsgType(umxns::MT_REQUEST);
pMsg->SetMsgID(11127);
/// 构造请求消息内容
/// ...
qry_cond_.page_no_ = page_no;
CPagizeHelper::PutPageCond(pMsg,&qry_cond_);
int result = 0;
CMsg* pAns = 0;
int ret = CBasePluginModule::sc_->call(pMsg, result,&pAns);
if (ret||result)
return -1;
if (!CMsgHelper::CheckResult(pAns,0,1)) {
pAns->Release();
return -1;
}
///< 处理返回消息
///....
pAns->Release();
return 0;
}
分页处理器定义如下:
文件:page_op.h
//---------------------------------------------------------------------------
class CPageActionBase {
public:
virtual int Do(unsigned int page_no) = 0;
};
//---------------------------------------------------------------------------
///< 页活动类
///< 分页操作的活动内容
template <class T> class CPageAction : public CPageActionBase {
typedef int (T::*PageActionFunc)(unsigned int page);
T *obj_;
PageActionFunc func_;
public:
CPageAction(T *obj,PageActionFunc func):obj_(obj),func_(func) {
}
int Do(unsigned int page_no) {
return (obj_->*func_)(page_no);
}
};
//---------------------------------------------------------------------------
///< 分页操作类
template <class T> class CPageOp {
unsigned int cur_page_; ///< 当前页号(页号从1开始)
unsigned int page_count_; ///< 总页数
T *first_;
T *prev_;
T *next_;
T *last_;
TComboBox *cbList_;
unsigned int page_no_; ///< 输入的页号
CVarValidator<unsigned int> page_no_validator_; ///< 输入页号校验器
CIntValidator iv_; ///< 页号校验器
CPageActionBase *action_;
void UIControl_i();
public:
CPageOp():page_count_(0),cur_page_(0),action_(0) {
first_ = prev_ = next_ = last_ = 0;
page_no_ = 0;
}
~CPageOp() {
if (action_) delete action_;
}
///< 设置控件
void SetControl(T *first,T *prev,T *next,T *last,TComboBox *cbList);
void SetAction(CPageActionBase *action) {
action_ = action;
}
void SetPageCount(unsigned int page_count);
unsigned long GetPageCount() const { return page_count_; }
void First(); ///< 第一页
void Prev(); ///< 上一页
void Next(); ///< 下一页
void Last(); ///< 最后一页
void GoTo(unsigned int page_no); ///< 转到page_no页
private:
void __fastcall OnFirst(TObject *Sender);
void __fastcall OnPrev(TObject *Sender);
void __fastcall OnNext(TObject *Sender);
void __fastcall OnLast(TObject *Sender);
void __fastcall OnGoto(TObject *Sender);
};
#include "page_op.cpp"
page_op.cpp
//---------------------------------------------------------------------------
///< 设置控件
template <class T> void CPageOp<T>::SetControl(T *first,T *prev,T *next,T *last,TComboBox *cbList) {
first_ = first;
prev_ = prev;
next_ = next;
last_ = last;
cbList_ = cbList;
first_->OnClick = OnFirst;
prev_->OnClick = OnPrev;
next_->OnClick = OnNext;
last_->OnClick = OnLast;
cbList_->OnChange = OnGoto;
first_->Enabled = false;
prev_->Enabled = false;
next_->Enabled = false;
last_->Enabled = false;
// cbList_->Style = csDropDownList;
page_no_validator_.SetVar(&page_no_,ORM_FIELD_TYPE_INT,"页号");
page_no_validator_.SetValidator(&iv_);
page_no_validator_.BindControl(new CComboBox(cbList_));
}
//---------------------------------------------------------------------------
template <class T> void __fastcall CPageOp<T>::OnFirst(TObject *Sender) {
First();
}
//---------------------------------------------------------------------------
template <class T> void __fastcall CPageOp<T>::OnPrev(TObject *Sender) {
Prev();
}
//---------------------------------------------------------------------------
template <class T> void __fastcall CPageOp<T>::OnNext(TObject *Sender) {
Next();
}
//---------------------------------------------------------------------------
template <class T> void __fastcall CPageOp<T>::OnLast(TObject *Sender) {
Last();
}
//---------------------------------------------------------------------------
template <class T> void __fastcall CPageOp<T>::OnGoto(TObject *Sender) {
int index = cbList_->ItemIndex;
if (index!=-1) {
GoTo(index+1);
}
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::SetPageCount(unsigned int page_count) {
page_count_ = page_count;
if (page_count==0) {
first_->Enabled = false;
prev_->Enabled = false;
next_->Enabled = false;
last_->Enabled = false;
cbList_->Clear();
return;
}
for(int i=1;i<=page_count;i++)
cbList_->Items->Add(String(i));
iv_.SetMinValue(1);
iv_.SetMaxValue(page_count_);
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::First() {
if (action_->Do(1)) {
return;
}
cur_page_ = 1;
UIControl_i();
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::Prev() {
if (action_->Do(cur_page_-1)) {
return;
}
cur_page_--;
UIControl_i();
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::Next() {
if (action_->Do(cur_page_+1)) {
return;
}
cur_page_++;
UIControl_i();
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::Last() {
if (action_->Do(page_count_)) {
return;
}
cur_page_ = page_count_;
UIControl_i();
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::UIControl_i() {
cbList_->ItemIndex = cur_page_-1;
first_->Enabled = cur_page_!=1;
prev_->Enabled = cur_page_!=1;
next_->Enabled = cur_page_!=page_count_;
last_->Enabled = cur_page_!=page_count_;
}
//---------------------------------------------------------------------------
template <class T> void CPageOp<T>::GoTo(unsigned int page_no) {
if (action_->Do(page_no)) {
return;
}
cur_page_ = page_no;
UIControl_i();
}