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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值