【问题标题】:DBGrid column visible widthDBGrid 列可见宽度
【发布时间】:2015-01-07 15:45:24
【问题描述】:

我一直在尝试找到一种方法来找到 非常宽的列,基于基础字段的长度。

在运行时查看网格时,通常会运行列的数据之一 屏幕右侧。为了查看数据,您必须滚动 向右。不幸的是,UI 设计不适合显示 单独的备注字段。

我所做的是使用 JEDI 项目中的 TJvBalloonHint 与 TJvDBGrid 结合使用。使用网格的 OnShowCellHint 我调用 构建提示文本的自定义方法,计算显示位置 提示并显示它。

******TJvDBGrid descendant*******
procedure TMyJvDBGrid.ShowGridCellHint(Sender: TObject; Field: TField; 
var AHint: String; var ATimeOut: Integer);
begin
FBalloonHint.HintPos(ScreenToClient(Mouse.CursorPos).X,ScreenToClient(Mouse.CursorPos).Y);
end;

********************************

function GetTextWidth(const Text: UnicodeString; AFont: TFont): Integer;
var
   bmp: Vcl.Graphics.TBitmap;
begin
   bmp := Vcl.Graphics.TBitmap.Create;
   try
     bmp.Canvas.Font := AFont;
     Result := bmp.Canvas.TextWidth(Text);
   finally
     FreeAndNil(bmp);
   end;
end;

******TJvBalloonHint descendant*******
procedure TMyJvBalloonHint.HintPos(X, Y: Integer);
var
   Cell: TGridCoord;
   ActRec: Integer;
   r: TRect;
   Grid: TMyJvDBGrid;
   sTitle: UnicodeString;
begin
   Grid := TMyJvDBGrid(Self.Owner);
   // correlates pixel location of the mouse
   // cursor to the row & column in the grid
   Cell := Grid.MouseCoord(X, Y);
   if dgIndicator in Grid.Options then
     // indicator column counts as a column
     Dec(Cell.X);
   if dgTitles in Grid.Options then
     // titles counts as a row
     Dec(Cell.Y);
   // is the grid connected to a dataset via a TDataSource object?
   if Grid.DataLink.Active and (Cell.X >= 0) and (Cell.Y >= 0) then
   begin
     // preserve the active record
     ActRec := Grid.DataLink.ActiveRecord;
     try
       // set active record to the row under the mouse cursor
       Grid.DataLink.ActiveRecord := Cell.Y;
       // set hint to the field value under the mouse cursor
       Hint := Grid.Columns[Cell.X].Field.AsString;
       // set hint title to the name of the column under the mouse cursor
       sTitle := Grid.Columns[Cell.X].Field.FieldName;
       if CellChanged(Cell.X,Cell.Y) then
         if GetTextWidth(Hint,Grid.Font) > Grid.Width then
         begin
           r.TopLeft := Point(mouse.CursorPos.X,Mouse.CursorPos.Y);
           r.BottomRight := Point(mouse.CursorPos.X,Mouse.CursorPos.Y);
           Grid.BalloonHint.ActivateHintRect(r,sTitle,Hint,0,ikNone);
         end;
     finally
       Grid.DataLink.ActiveRecord := ActRec;
     end;
   end;
end;

function TMyJvBalloonHint.CellChanged(const X, Y: Integer): Boolean;
var
   Grid: TMyJvDBGrid;
begin
   // persists cell position in order to determine if the
   // mouse cursor position has changed to another cell
   Result := False;
   if (X <> FX) or (Y <> FY) then
   begin
     Grid := TMyJvDBGrid(Self.Owner);
     if Grid.BalloonHint.Active then
       Grid.BalloonHint.CancelHint;
     Result := True;
     if Assigned(FOnShowHint) and FShowHint then
       FOnShowHint(Self);
     FX := X;
     FY := Y;
   end;
end;

procedure TMyJvBalloonHint.SetHint(AValue: UnicodeString);
var
   i,n: Integer;
   chars: TSysCharSet;
begin
   FHint := '';
   chars := [];
   if Length(TextWrapChars.Chars) > 0 then
   begin
     for i := 0 to Pred(Length(TextWrapChars.Chars)) do
       for n := 1 to Length(TextWrapChars[i]) do
         if TextWrapChars[i] <> #0 then
           Include(chars,TextWrapChars[i]);

     FHint := WrapText(AValue, #13#10, chars, TextWrapWidth);
   end
   else
     FHint := AValue;
end;

**************************************

此代码仅显示一个提示 - 将字段的文本包裹起来 它是完整可见的 - 如果字段文本长于 整个网格的显示宽度。

第一问): 我想要做的是仅当字段文本更大时才显示提示 长度大于列的显示/可见宽度。但我不能 找到一种方法来测量列的显示/可见宽度。其他 的话,如果一列比它显示的宽度宽,我想知道 列的显示/可见部分的宽度是多少。然后我 可以测量基础字段中文本的宽度并确定 如果文本在网格的右侧或左侧被截断。

第二问): 上面的代码在光标位置显示提示。我想 在单元格可见部分的底部显示提示,在 单元格可见部分的中心,无论光标在哪里 横向在单元格矩形内。

感谢您的帮助。

【问题讨论】:

    标签: delphi


    【解决方案1】:

    这并不完美,但已经相当接近回答这两个问题了。

    由于我对 TDBGrid 进行了子类化,因此我可以访问受保护的成员,包括“LeftCol”。使用网格的“ClientWidth”属性和对列的迭代,我能够粗略地计算“切掉”列的起始位置,并使用此方法显示/可见宽度:

    function ColumnIsChopped(Grid: TIniSectionDBGrid; const ColNum: Integer;
                          out ColumnDisplayWidth, ColumnLeftPos: Integer): Boolean;
    var
      i: Integer;
    begin
      if ColNum > Pred(Grid.Columns.Count) then
        Exit;
      // the whole enchilada...
      ColumnDisplayWidth := Grid.ClientWidth;
      if ColNum <> Grid.LeftCol then
      begin
        // start iteration & measurements with the left most displayed column in grid
        i := Grid.LeftCol;
        while i < ColNum do
        begin
          // subtract width of column from overall grid client (displayed) width
          ColumnDisplayWidth := ColumnDisplayWidth - Grid.Columns[i].Width;
          inc(i);
        end;
      end;
      // determine the starting position in pixels of the provided column
      ColumnLeftPos := Grid.ClientWidth - ColumnDisplayWidth;
      // if remaining display width is less than the text width of text in column,
      // assume that the column text display is chopped off on the right
      Result := ColumnDisplayWidth <= GetTextWidth(Grid.Columns[ColNum].Field.AsString,Grid.Font);
    end;
    

    在准备显示提示时,我调用 ColumnIsChopped 方法来确定以下内容:

    1. ) 鼠标光标下的列是否被截断?
    2. ) 当前列的大致左侧位置是多少?
    3. ) 光标下列的显示/可见宽度是多少?
    4. ) 列中文本的宽度是否大于列的显示/可见宽度?
    procedure TIniSectionDBGrid.TIniSectionDBGridHint.HintPos(Position: TPoint);
    var
      Cell: TGridCoord;
      ActRec,colDisplayWidth,iLeft,iLeftPos: Integer;
      r: TRect;
      Grid: TIniSectionDBGrid;
      sTitle: UnicodeString;
    begin
      Grid := TIniSectionDBGrid(Self.Owner);
      // correlates pixel location of the mouse
      // cursor to the row & column in the grid
      Cell := Grid.MouseCoord(Position.X, Position.Y);
      if dgIndicator in Grid.Options then
        // indicator column counts as a column
        Dec(Cell.X);
      if dgTitles in Grid.Options then
        // titles counts as a row
        Dec(Cell.Y);
      // is the grid connected to a dataset via a TDataSource object?
      if Grid.DataLink.Active and (Cell.X >= 0) and (Cell.Y >= 0) then
      begin
        // preserve the active record
        ActRec := Grid.DataLink.ActiveRecord;
        try
          // set active record to the row under the mouse cursor
          Grid.DataLink.ActiveRecord := Cell.Y;
          if CellChanged(Cell.X,Cell.Y) then
            if ColumnIsChopped(Grid,Cell.X,colDisplayWidth,iLeft) then
            begin
              // calc x position for hint
              iLeftPos := iLeft + Round(colDisplayWidth / 2);
              // set hint to the field value under the mouse cursor
              Hint := Grid.Columns[Cell.X].Field.AsString;
              // set hint title to the name of the column under the mouse cursor
              sTitle := Grid.Columns[Cell.X].Field.FieldName;
              r.TopLeft := Point(iLeftPos,Mouse.CursorPos.Y);
              r.BottomRight := Point(iLeftPos,Mouse.CursorPos.Y);
              Grid.BalloonHint.ActivateHintRect(r,sTitle,Hint,0,ikNone);
            end;
        finally
          Grid.DataLink.ActiveRecord := ActRec;
        end;
      end;
    end;
    

    现在剩下的就是根据单元格在网格中的垂直方向以及相对于单元格的相应提示方向(上或以下?)。

    【讨论】:

      猜你喜欢
      • 2018-04-01
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 1970-01-01
      相关资源
      最近更新 更多