Delphi自定义DBGrid派生组件遇问题:无法实现自动换行
解决TDBGrid派生组件无法实现自动换行的问题
问题背景
受限于特殊情况无法使用EhLib、DevExpress QuantumGrid等第三方表格组件,只能基于标准DBGrid开发自定义派生组件。参考Marco Cantu《Mastering Delphi》中的示例实现后,组件始终表现为标准DBGrid的样式,无法实现文本自动换行效果。
排查过程
调试中发现,通过Canvas绘制的内容被界面元素覆盖,代码执行了绘制逻辑但最终不可见。甚至注释掉文本绘制代码、只保留Canvas.FillRect(Rect)清空单元格的操作,界面上仍显示原有数据,说明DBGrid的默认绘制流程覆盖了自定义绘制内容。
解决步骤
- 关闭默认绘制:将组件的
DefaultDrawing属性设为False,彻底禁用DBGrid自带的单元格绘制逻辑,确保自定义DrawColumnCell方法的绘制内容能正常显示。 - 扩展字段类型支持:原示例仅处理了
TMemoField,新增对TWideStringField、TWideMemoField类型的判断,确保宽字符串类型字段也能触发自动换行绘制。
最终完整组件代码
unit MdDbGrid; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, DB, StdCtrls, ExtCtrls, Grids, DBGrids; type TMdDbGrid = class(TDBGrid) private { Private declarations } FLinesPerRow: Integer; procedure SetLinesPerRow (Value: Integer); protected { Protected declarations } procedure DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); override; procedure LayoutChanged; override; public { Public declarations } constructor Create (AOwner: TComponent); override; published { Published declarations } property LinesPerRow: Integer read FLinesPerRow write SetLinesPerRow default 1; // 显式发布DefaultDrawing属性,方便设计时修改 property DefaultDrawing; end; procedure Register; implementation procedure Register; begin RegisterComponents('MyComponents', [TMdDbGrid]); end; constructor TMdDbGrid.Create(AOwner: TComponent); begin inherited Create(AOwner); FLinesPerRow:=1; DefaultDrawing := False; // 创建时默认关闭默认绘制 end; procedure TMdDbGrid.SetLinesPerRow(Value: Integer); begin if Value <> FLinesPerRow then begin FLinesPerRow := Value; LayoutChanged; end; end; procedure TMdDbGrid.LayOutChanged; var PixelsPerRow, PixelsTitle, I: Integer; begin inherited LayOutChanged; Canvas.Font := Font; PixelsPerRow := Canvas.TextHeight('Wg') + 3; if dgRowLines in Options then Inc (PixelsPerRow, GridLineWidth); Canvas.Font := TitleFont; PixelsTitle := Canvas.TextHeight('Wg') + 4; if dgRowLines in Options then Inc (PixelsTitle, GridLineWidth); // 设置行数 RowCount := 1 + (Height - PixelsTitle) div (PixelsPerRow * FLinesPerRow); // 设置每行高度 DefaultRowHeight := PixelsPerRow * FLinesPerRow; RowHeights [0] := PixelsTitle; for I := 1 to RowCount - 1 do RowHeights [I] := PixelsPerRow * FLinesPerRow; // 发送WM_SIZE消息,让基类重新计算可见行数 PostMessage (Handle, WM_SIZE, 0, MakeLong(Width, Height)); end; procedure TMdDbGrid.DrawColumnCell (const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); var Bmp: TBitmap; OutRect: TRect; begin if FLinesPerRow = 1 then inherited DrawColumnCell(Rect, DataCol, Column, State) else begin // 清空单元格区域 Self.Canvas.FillRect (Rect); // 调整绘制区域,留出边距 OutRect := Rect; InflateRect (OutRect, -2, -2); // 根据字段类型绘制内容 if Column.Field is TGraphicField then begin Bmp := TBitmap.Create; try Bmp.Assign (Column.Field); Canvas.StretchDraw (OutRect, Bmp); finally Bmp.Free; end; end else if (Column.Field is TMemoField) or (Column.Field is TWideStringField) or (Column.Field is TWideMemoField) then begin DrawText (Canvas.Handle, PChar (Column.Field.AsString), Length (Column.Field.AsString), OutRect, dt_WordBreak or dt_NoPrefix) end else // 非多行字段垂直居中单行显示 DrawText (Canvas.Handle, PChar (Column.Field.DisplayText), Length (Column.Field.DisplayText), OutRect, dt_vcenter or dt_SingleLine or dt_NoPrefix); end; end; end.
补充说明
- 在组件的published段显式添加了
DefaultDrawing属性,方便在设计时直接修改 - 在构造函数中默认将
DefaultDrawing设为False,避免遗漏配置
内容的提问来源于stack exchange,提问作者Obsydian_ring Winds_of_hellhei
相关产品推荐
相关产品推荐

