DBGrid 列可见宽度
DBGrid column visible width
我一直在寻找一种方法来找到 visible/viewable 的宽度
非常宽的列,基于基础字段的长度。
在运行时查看网格时,其中一个列的数据经常运行
离开屏幕向右。要查看数据,您必须滚动
向右。不幸的是 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;
**************************************
此代码仅显示提示 - 字段文本被包裹起来
它是完整可见的 - 如果字段文本长于
整个网格的显示宽度。
第一个问题):
我想做的是仅当字段文本更大时才显示提示
长度大于列的 displayed/visible 宽度。但我不能
找到一种方法来测量列的 displayed/visible 宽度。其他
换句话说,如果一列比它的显示宽度更宽,我想知道
列的 displayed/visible 部分的宽度是多少。然后我
可以测量基础字段中文本的宽度并确定
如果文本在网格的右侧或左侧被截断。
第二问):
上面的代码在光标位置显示提示。我想
在单元格可见部分的底部显示提示,在
单元格可见部分的中心,无论光标在哪里
在单元格矩形内横向。
感谢您的帮助。
这并不完美,但已经很接近回答这两个问题了。
自从我将 TDBGrid 子类化后,我就可以访问受保护的成员,包括 'LeftCol'。使用网格的 'ClientWidth' 属性 和对列的迭代我能够粗略地计算出 'chopped off' 列的起始位置和它的 displayed/visible 宽度使用这种方法:
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 方法来确定以下内容:
- ) 鼠标光标下的列是否被截断?
- ) 当前列的大约左侧位置(以像素为单位)是多少?
- ) 光标所在列的 displayed/visible 宽度是多少?
- ) 列中文字的宽度是否大于displayed/visible列的宽度?
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;
现在剩下的就是弄清楚如何根据单元格在网格中的垂直方向以及相对于单元格的相应提示方向,将提示定位在单元格底部或单元格顶部(高于还是低于?)。
我一直在寻找一种方法来找到 visible/viewable 的宽度 非常宽的列,基于基础字段的长度。
在运行时查看网格时,其中一个列的数据经常运行 离开屏幕向右。要查看数据,您必须滚动 向右。不幸的是 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;
**************************************
此代码仅显示提示 - 字段文本被包裹起来 它是完整可见的 - 如果字段文本长于 整个网格的显示宽度。
第一个问题): 我想做的是仅当字段文本更大时才显示提示 长度大于列的 displayed/visible 宽度。但我不能 找到一种方法来测量列的 displayed/visible 宽度。其他 换句话说,如果一列比它的显示宽度更宽,我想知道 列的 displayed/visible 部分的宽度是多少。然后我 可以测量基础字段中文本的宽度并确定 如果文本在网格的右侧或左侧被截断。
第二问): 上面的代码在光标位置显示提示。我想 在单元格可见部分的底部显示提示,在 单元格可见部分的中心,无论光标在哪里 在单元格矩形内横向。
感谢您的帮助。
这并不完美,但已经很接近回答这两个问题了。
自从我将 TDBGrid 子类化后,我就可以访问受保护的成员,包括 'LeftCol'。使用网格的 'ClientWidth' 属性 和对列的迭代我能够粗略地计算出 'chopped off' 列的起始位置和它的 displayed/visible 宽度使用这种方法:
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 方法来确定以下内容:
- ) 鼠标光标下的列是否被截断?
- ) 当前列的大约左侧位置(以像素为单位)是多少?
- ) 光标所在列的 displayed/visible 宽度是多少?
- ) 列中文字的宽度是否大于displayed/visible列的宽度?
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;
现在剩下的就是弄清楚如何根据单元格在网格中的垂直方向以及相对于单元格的相应提示方向,将提示定位在单元格底部或单元格顶部(高于还是低于?)。