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

来源:互联网 发布:linux 复制粘贴文件夹 编辑:程序博客网 时间:2024/05/24 00:55

  作者注:本文摘自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里,给属性赋值时,有时是需要小心的。使用临时变量的写法,总是可以的。而上面一个回复中的写法,有时可以有时却不可以。

原创粉丝点击