您的位置:首页 > 运维架构

关于TDBNavigator->VisibleButtons及TDBGrid->Options属性更新的问题

2006-06-02 01:05 369 查看
作者注:本文摘自CSDN一个FAQ,回帖人是jishiping,曾经是BCB版的版主,可现在已经辞掉了,我记得以前他在的时候,很多复杂繁琐的问题都有他的回答,而且往往是点睛之笔,很多人受过他的帮助,包括我自己,唉!现在这样的人越来越少了,BCB版的人气也大不如从前,我自己要是碰到什么问题往往都很难在CSDN上解决了,只能硬着头皮啃帮助,无奈自己英文水平又不高,往往看的成斗鸡眼也不能解决问题!苦恼,还好现在学了点点Object Pascal语法,有时看看VCL的源码收获还颇多,虽然才看到冰山一角而已,可已经发觉得VCL的高深之处,真不明白那些人都投奔.net了,其实.net只不过是VCL的另一个版本,因为它们都是同一个人设计的嘛(好像叫Anders Hejlsberg,Borland的创始人之一,Delphi产品和.net的Architect,传奇人物),不知道这些人怎么想的,嗯!有盲目崇拜之嫌疑!说的都是玩笑话,谁叫Microsoft是老大呢,不能引领潮流,那就随波逐流吧,说不定那天我也得转了。
//--------------------FAQ------------------------------

BCB里面的属性,改变它们的值时,大多数情况下都需要调用相关的函数。比如这儿:
__property TButtonSet VisibleButtons = {read=FVisibleButtons, write=SetVisible, default=1023};
当你读取属性VisibleButtons时,它直接访问变量FVisibleButtons,给他赋值时就调用函数SetVisible。如果你直接写成 DBNavigator1->VisibleButtons >> nbPost; 的话,就是直接修改class中的变量FVisibleButtons,因为没有赋值符号,因而没有调用SetVisible这个函数。所以属性的值发生变化了,但是它没有调用相关的函数来真正显示/隐藏那些按钮。所以必须写成
DBNavigator1->VisibleButtons = DBNavigator1->VisibleButtons >> nbPost;
这样才会调用SetVisible这个函数。
但是需要注意,对于其他的控件的一些属性,即使是上面的写法,虽然会发生函数调用,
但是可能还是无法看到效果。比如TDBGrid的Options属性,如果还是使用:
DBGrid1->Options = DBGrid1->Options >> dgEditing;
你就会发现根本不起作用。原因是什么呢?首先我们来看看他的定义:
__property TDBGridOptions Options = {read=FOptions, write=SetOptions, default=3325};
这样一看,你会发现它的定义,和上面的VisibleButtons一样啊,怎么就不行了呢?这个还需要看看源程序中TDBGrid的SetOptions的代码:
procedure TCustomDBGrid.SetOptions(Value: TDBGridOptions);
const
LayoutOptions = [dgEditing, dgAlwaysShowEditor, dgTitles, dgIndicator,
dgColLines, dgRowLines, dgRowSelect, dgAlwaysShowSelection];
var
NewGridOptions: TGridOptions;
ChangedOptions: TDBGridOptions;
begin
if FOptions <> Value then
begin
NewGridOptions := [];
if dgColLines in Value then
NewGridOptions := NewGridOptions + [goFixedVertLine, goVertLine];
if dgRowLines in Value then
NewGridOptions := NewGridOptions + [goFixedHorzLine, goHorzLine];
if dgColumnResize in Value then
NewGridOptions := NewGridOptions + [goColSizing, goColMoving];
if dgTabs in Value then Include(NewGridOptions, goTabs);
if dgRowSelect in Value then
begin
Include(NewGridOptions, goRowSelect);
Exclude(Value, dgAlwaysShowEditor);
Exclude(Value, dgEditing);
end;
if dgEditing in Value then Include(NewGridOptions, goEditing);
if dgAlwaysShowEditor in Value then Include(NewGridOptions, goAlwaysShowEditor);
inherited Options := NewGridOptions;
if dgMultiSelect in (FOptions - Value) then FBookmarks.Clear;
ChangedOptions := (FOptions + Value) - (FOptions * Value);
FOptions := Value;
if ChangedOptions * LayoutOptions <> [] then LayoutChanged;
end;
end;

注意,上面的代码,首先是一个判断语句 if FOptions <> Value then,就是说参数Value 的值和原来的 FOptions 不同时才会执行下面的代码。但是如果你使用下面的写法时:

DBGrid1->Options = DBGrid1->Options >> dgEditing;
编译器实际上将它扩展为:

DBGrid1->SetOptions(DBGrid1->FOptions >> dgEditing);
实际上首先执行 DBGrid1->FOptions >> dgEditing,此时它改变的就是 DBGrid1->FOptions 的值,然后将 DBGrid1->FOptions 作为参数,去执行函数 SetOptions 的代码。这样在这个函数 SetOptions 中,参数Value的值就等于原来的FOptions,所以就会不执行后面的代码,造成了属性Options的值改变了,但是真正的效果却没有实现。此时就一定要使用一个临时变量才可以,比如:
TDBGridOptions Options = DBGrid1->Options;
DBGrid1->Options = Options >> dgEditing;

下面再看看TDBNavigator的函数SetVisible的源代码:
procedure TDBNavigator.SetVisible(Value: TButtonSet);
var
I: TNavigateBtn;
W,H: Integer;
begin
W := Width;
H := Height;
FVisibleButtons := Value;
for I := Low(Buttons) to High(Buttons) do
Buttons[I].Visible := I in FVisibleButtons;
SetSize(W, H);
if (W <> Width) or (H <> Height) then
inherited SetBounds (Left, Top, W, H);
Invalidate;
end;
这儿,程序没有检查参数Value的值是否和原来的值FVisibleButtons是否相同,所以上面的回复中的写法就没有问题。所以在BCB里,给属性赋值时,有时是需要小心的。使用临时变量的写法,总是可以的。而上面一个回复中的写法,有时可以有时却不可以。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: