DBGrid停止当前行移动 [英] DBGrid stop current Row moving

查看:118
本文介绍了DBGrid停止当前行移动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用d5,TDBGrid,SQLite3和ZEOS.数据库有2000个项目,一个列是布尔值的"Active",第二个列是文本的"ItemName",而IndexFiledNames是"ItemName"

Using d5, TDBGrid, SQLite3 and ZEOS. Database has 2000 items, one Column is an "Active" as Boolean, a second Column is "ItemName" as Text, and IndexFiledNames is "ItemName'

OnDblclick会切换活动"打开/关闭,并且所有操作均可针对数据进行.有效更改从True更改为False,然后再次更改.

OnDblclick toggles "Active" On/Off and all works as expected for the Data. Active changes from True to False and back again.

但是,如果我双击DBGrid的最后一个可见行,以切换到活动状态-在切换之后,DBGrid将该项目Row移到网格的垂直中心Row-位置.这对使用双击双击的Row的用户来说非常混乱.

But, if I double-click on the last visible Row of the DBGrid, to toggle the Active state -- after the toggle, the DBGrid moves that item Row to the vertical center Row-position of the grid. This is very confusing to a user with the Row they just double-clicked jumping around.

如何阻止网格将该行移动到中间? DGBGrid的最后可见行上的所有项目都会发生这种情况.

How can I stop the grid from moving that Row to the middle? This happens with all items that are on the last visible Row of the DGBGrid.

{EDIT}删除的项目是为减少问题而进行的尝试-无效.

{EDIT} The remmed out items are attempts at reducing the issue - didn't work.

procedure TfrmMain.dbgridItemsDblClick(Sender: TObject);
begin
  puItemsSelectedClick(Self);
end;

procedure TfrmMain.puItemsSelectedClick(Sender: TObject);
//var
//  CurrItem : String;
//  CurrIndx : String;
begin
  if dm.tblItems.RecordCount = 0 then
  begin
    myShowMsg('There are no Items in the Items List');
    Exit;
  end;
//  CurrItem:=dm.tblItems.FieldByName(fldItemGroupShop).AsString;
//  CurrIndx:=dm.tblItems.IndexFieldNames;
  dm.tblItems.DisableControls;
  try
//    dm.tblItems.IndexFieldNames:='';
    dm.tblItems.Edit;
    dm.tblItems.FieldByName(fldSelected).AsBoolean:=
      not(dm.tblItems.FieldByName(fldSelected).AsBoolean);
    dm.tblItems.Post;
//    dm.tblItems.IndexFieldNames:=CurrIndx;
//    dm.tblItems.Locate(fldItemGroupShop,CurrItem,[]);
  finally
    dm.tblItems.EnableControls;
  end;
end;

推荐答案

DBGrid的当前行号和显示行数是受保护的属性, 因此您需要在代码中使用类破解器"类型声明,如下所示:

The current row number and number of display rows of a DBGrid are protected properties, so you need a "class cracker" type declaration in your code, like so:

type
  TMyDBGrid = Class(TDBGrid);

function TForm1.GetGridRow: Integer;
begin
  Result := TmyDBGrid(DBGrid1).Row;
end;

function TForm1.GridRowCount : Integer;
begin
  Result := TmyDBGrid(DBGrid1).RowCount;
end;

完成此操作后,在窗体上放置一个TEdit和TButton,以输入一个小于当前网格行号的新网格行号.然后尝试以下例程:

Having done that, place a TEdit and TButton on your form to input a new grid row number that's less than the current one. Then try out the following routine:

procedure TForm1.SetGridRow(NewRow : Integer);
var
  GridRows,
  OldRow,
  MoveDataSetBy,
  MovedBy : Integer;
  DataSet : TDataSet;
  Possible : Boolean;
  ScrollUp : Boolean;
begin
  OldRow := GetGridRow;
  if NewRow = OldRow then
    Exit;

  ScrollUp := NewRow < OldRow;

  DataSet := dBGrid1.DataSource.DataSet;

  GridRows := TmyDBGrid(DBGrid1).RowCount;
  { TODO : Test the case where the DataSet doesn't have enough rows to fill the grid}
  { TODO : Check why grid reports one more row than it displays.
   Meanwhile ... }
  GridRows := GridRows - 1;

  // First check whether the NewRow value is sensible
  Possible := (NewRow >= 1) and (NewRow <= GridRows);
  if not Possible then exit;

  try
    if ScrollUp then begin

    //  First scroll the dataset forwards enough to bring
    //  a number of new records into view
    MoveDataSetBy := GridRows - NewRow;
    MovedBy := DataSet.MoveBy(MoveDataSetBy);
    Shortfall := MoveDataSetBy - MovedBy;
    if Shortfall = 0 then begin
      //  Now scroll the dataset backwards to get back
      //  to the record we were on
      MoveDataSetBy := -GridRows + NewRow;
      MovedBy := DataSet.MoveBy(MoveDataSetBy);
    end
    else
      MovedBy := DataSet.MoveBy(-MovedBy);
  end
  else begin
    MoveDataSetBy :=  -(NewRow - 1);
    MovedBy := DataSet.MoveBy(MoveDataSetBy);
    //  We need to know if the DS cursor was able to move far enough
    //  back as we've asked or was prevented by reaching BOF
    Shortfall := MoveDataSetBy - MovedBy;
    if Shortfall = 0 then begin
      // The DS cursor succeeded on moving the requested distance
      MoveDataSetBy := NewRow - 1;
      MovedBy := DataSet.MoveBy(MoveDataSetBy);
    end
    else
      //  it failed, so we need to return to the record we started on
      //  but this won't necessarily return us the same grid row number
      MovedBy := DataSet.MoveBy(-MovedBy);
    finally
      DBGrid1.Invalidate;
    end;

我先前的建议是通过"TmyDBGrid(DBGrid1).Row:= NewRow;"直接分配给网格行.是基于错误的回忆,因为实际上这似乎没有什么用处.

My earlier suggestion, to do a direct assignment to the grid row by "TmyDBGrid(DBGrid1).Row := NewRow;" was based on a mis-recollection, because in fact that seems to do nothing very useful.

由于我们不依赖有意义的RecNo,因此"if ScrollUp"之后的算法变得复杂.这涉及检查数据集光标是否可以沿我们要向其移动网格行的方向相反移动足够的量,以相对于网格中的行滚动DS光标,而无需点击EOF或BOF-如果发生硫键中的任何一个,我们只需将DS光标移回原来的位置,然后放弃尝试滚动网格.

The algorithm following "if ScrollUp" is made complicated by the fact that we're not depending on a meaningful RecNo. What this involves is checking whether the dataset cursor can be moved by a sufficient amount in the direction opposite the one we want to move the grid row in, to scroll the DS cursor relative to the rows in the grid, without hitting EOF or BOF - if either of thiose happens, we just move the DS cursor back to where it was and give up trying to scroll the grid.

对于ScrollUp,逻辑为:

For ScrollUp, the logic is:

  • 首先将数据集光标移动到网格的最后一行
  • 然后通过新旧Row值之间的差异将其向前移动一些.
  • 然后将其移回等于网格中的行数减去新行值的量.

如果所有操作都成功,则当前行将移动到NewRow值请求的网格位置. 当然,代码将这些步骤的前两个步骤结合在一起.起初,我认为这段代码是胡说八道,因为用于DataSet.MoveBy()s的值的代数和为零.实际上, 这不是胡说八道,只是有点违反直觉.当然,距离的总和为零,因为我们想回到记录中,我们是一;完全执行DataSet.MoveBy()的目的是,将网格在当前记录上的控制权放开,然后返回到该记录.顺便说一下,这就是为什么在移走当前记录然后返回到当前记录(即DataSet.GetBookmark/GotBookmark/FreeBookmark)并实际上使用它们将破坏代码的预期效果时,我通常没有任何意义的原因.

If all that succeeds, the current row will move to the grid position requested by the NewRow value. Of course, the code combines the first two of these steps. At first, I thought this code was nonsense, because the algebraic sum of the values used for the DataSet.MoveBy()s is zero. In fact, it's not nonsense, just a bit counter-intuitive. Of course the distances add up do zero, because we want to get back to the record we were one; the point of doing the DataSet.MoveBy()s at all is to shake loose, as it were, the grid's grip on the current record and then return to it. This is incidentally why there's no point in doing what I usually when moving off the current record and then returning to it, namely DataSet.GetBookmark/GotBookmark/FreeBookmark and indeed using those will defeat the code's intended effect.

我使用的是ClientDataSet,顺便说一句,而不是ZEOS,但这没什么区别.

I'm using a ClientDataSet, btw, not a ZEOS one, but that shouldn't make any difference.

顺便说一句,本地DataSet变量用于访问网格的数据集,而无需使用Delphi的地狱式"With ..."构造.

Btw, the local DataSet variable is to access the grid's dataset without using Delphi's infernal "With ..." construct.

顺便说一句,您对"Rows div 2"的评论提醒我:我不认为是网格告诉数据集,而ISTR不是与网格关联的数据链接告诉数据集应为其分配缓冲区的记录数.然后,在TDataSet.Resync中,您会注意到

Incidentally, your comment about "Rows div 2" reminded me: I don't think it's the grid that tells the dataset, ISTR it's the Datalink associated with the grid which tells the dataset how many records it should allocate buffers for. Then, in TDataSet.Resync, you'll notice

if rmCenter in Mode then
  Count := (FBufferCount - 1) div 2 else
  Count := FActiveRecord;

,然后看一下例程中稍后如何使用Count;您的理论可能会被接受.也许在"if cmCenter in Mode"上放置一个断点,看看是否从网格运行的地方调用它.

and then take a look how Count is used later in the routine; your theory may be spot on. Maybe put a breakpoint on "if cmCenter in Mode" and see if it gets called from where your grid acts up.

Btw#2,即使该代码没有帮助,本文也可能 http://delphi.about.com/od/usedbvcl/l/aa011004a.htm

Btw#2, even if this code hasn't helped, this article might http://delphi.about.com/od/usedbvcl/l/aa011004a.htm

这篇关于DBGrid停止当前行移动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆