1.1.64版本已发布,有兴趣请到 http://blog.youkuaiyun.com/boythl/archive/2008/11/25/3372110.aspx 下载。
因为项目中有需求需要在TStringGrid的单元格中生成内置的下拉列表,如同TDBGrid里面的一样;貌似有个什么东西能做,但是是收费的, 本人口袋空空,只好自己实现该组件, 开源所有实现代码.
1. 组件化,支持可视化设计;
2. 支持列设置,包括字体,颜色,居中,列宽,visible,readonly, 内置下拉列表, 右键菜单等;
3. 增加一系列事件,如CellClick等.
4. 对单元格的个性化设置的支持尚在开发中.
不好意思的说,因为头次写delphi组件, 所以所有代码都是从TCustDBGrid扒拉过来的, 简单嘛, 改吧改吧就能用了; 但TStringGrid的父类和TCustDBGrid做过部分类似的工作, ,所以有部分代码可能是冗余的, 不过应该不碍事.
鉴于首次写组件的技术不成熟性,组件里肯定会有bug; 若发现bug,欢迎及时反馈,本人有时间会及时更新!
本组件可自由转载,复制,使用,但请保留作者和版权信息! 若有源代码修改, 希望方便时能回增本人一份,boythl#163.com 谢谢!
RAR格式的 完整的组件安装包下载链接请点这儿( B4 优快云,都不提供博客上传附件功能.)
( https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/boythl/EntryImages/20081007/TXStringGridV1.0.38.jpg 这是随文章上传的完整组件安装包, 请用右键另存为下载并将jpg扩展名改成rar, 就可以解压缩了.)
核心的 TXStringGrid.pas 完整代码如下:
- {*******************************************************}
- { }
- { Lonefox Visual Component Library }
- { }
- { Copyright (c) 2008 All Rights Reserved }
- { }
- { http://lonefox.blogcn.com }
- { http://blog.youkuaiyun.com/boythl }
- { }
- {*******************************************************}
- unit TXStringGrid;
- interface
- uses
- SysUtils, Classes, Windows, Controls, Grids, Graphics, Menus, Messages,
- Types, stdCtrls;
- type
- TTXColButtonStyle = (tcbsNone, tcbsAutoSelect, tcbsEllipse);//列类型:普通,下拉菜单,按钮
- TTXColumnValue = (cvColor, cvWidth, cvFont, cvAlignment, cvReadOnly, cvTitleColor,
- cvTitleCaption, cvTitleAlignment, cvTitleFont);
- TTXColumnValues = set of TTXColumnValue;
- const
- ColumnTitleValues = [cvTitleColor..cvTitleFont];
- cm_DeferLayout = WM_USER + 100;
- type
- TTXStringGrid = class;
- TTXColumn = class;
- TTXColumnClass = class of TTXColumn;
- TTXColumnTitle = class(TPersistent)
- private
- FColumn: TTXColumn;
- FCaption: string;
- FFont: TFont;
- FColor: TColor;
- FAlignment: TAlignment;
- procedure FontChanged(Sender: TObject);
- function GetAlignment: TAlignment;
- function GetColor: TColor;
- function GetCaption: string;
- function GetFont: TFont;
- function IsAlignmentStored: Boolean;
- function IsColorStored: Boolean;
- function IsFontStored: Boolean;
- function IsCaptionStored: Boolean;
- procedure SetAlignment(Value: TAlignment);
- procedure SetColor(Value: TColor);
- procedure SetFont(Value: TFont);
- procedure SetCaption(const Value: string); virtual;
- protected
- procedure RefreshDefaultFont;
- public
- constructor Create(Column: TTXColumn);
- destructor Destroy; override;
- function DefaultAlignment: TAlignment;
- function DefaultColor: TColor;
- function DefaultFont: TFont;
- procedure RestoreDefaults; virtual;
- property Column: TTXColumn read FColumn;
- published
- property Alignment: TAlignment read GetAlignment write SetAlignment
- stored IsAlignmentStored;
- property Caption: string read GetCaption write SetCaption stored IsCaptionStored;
- property Color: TColor read GetColor write SetColor stored IsColorStored;
- property Font: TFont read GetFont write SetFont stored IsFontStored;
- end;
- TTXColumn = class(TCollectionItem)
- private
- FAssignedValues: TTXColumnValues;
- FColor: TColor;
- FTitle: TTXColumnTitle;
- FFont: TFont;
- FPickList: TStrings;
- FPopupMenu: TPopupMenu;
- FDropDownRows: Cardinal;
- FButtonStyle: TTXColButtonStyle;
- FAlignment: TAlignment;
- FReadonly: Boolean;
- FVisible: Boolean;
- FStored: Boolean;
- FWidth: Integer;
- procedure FontChanged(Sender: TObject);
- function GetAlignment: TAlignment;
- function GetColor: TColor;
- function GetFont: TFont;
- function GetPickList: TStrings;
- function GetReadOnly: Boolean;
- function IsAlignmentStored: Boolean;
- function IsColorStored: Boolean;
- function IsFontStored: Boolean;
- function IsReadOnlyStored: Boolean;
- procedure SetAlignment(Value: TAlignment); virtual;
- procedure SetButtonStyle(Value: TTXColButtonStyle);
- procedure SetColor(Value: TColor);
- procedure SetFont(Value: TFont);
- procedure SetPickList(Value: TStrings);
- procedure SetPopupMenu(Value: TPopupMenu);
- procedure SetReadOnly(Value: Boolean); virtual;
- procedure SetTitle(Value: TTXColumnTitle);
- procedure SetVisible(const Value: Boolean);
- function GetWidth: Integer;
- function IsWidthStored: Boolean;
- procedure SetWidth(const Value: Integer);
- protected
- function CreateTitle: TTXColumnTitle; virtual;
- function GetGrid: TTXStringGrid;
- procedure RefreshDefaultFont;
- property IsStored: Boolean read FStored write FStored default True;
- function DefaultWidth: integer;
- public
- constructor Create(Collection: TCollection); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- function DefaultAlignment: TAlignment;
- function DefaultColor: TColor;
- function DefaultFont: TFont;
- procedure RestoreDefaults; virtual;
- property Grid: TTXStringGrid read GetGrid;
- property AssignedValues: TTXColumnValues read FAssignedValues;
- published
- property Alignment: TAlignment read GetAlignment write SetAlignment
- stored IsAlignmentStored;
- property ButtonStyle: TTXColButtonStyle read FButtonStyle write SetButtonStyle
- default tcbsNone;
- property Color: TColor read GetColor write SetColor stored IsColorStored;
- property DropDownRows: Cardinal read FDropDownRows write FDropDownRows default 7;
- property Font: TFont read GetFont write SetFont stored IsFontStored;
- property PickList: TStrings read GetPickList write SetPickList;
- property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
- property ReadOnly: Boolean read GetReadOnly write SetReadOnly
- stored IsReadOnlyStored;
- property Title: TTXColumnTitle read FTitle write SetTitle;
- property Visible: Boolean read FVisible write SetVisible default true;
- property Width: Integer read GetWidth write SetWidth stored IsWidthStored;
- end;
- TTXColumns = class(TCollection)
- private
- FGrid: TTXStringGrid;
- function GetTXColumn(Index: Integer): TTXColumn;
- procedure SetTXColumn(Index: Integer; Value: TTXColumn);
- protected
- function GetOwner: TPersistent; override;
- procedure Update(Item: TCollectionItem); override;
- public
- constructor Create(Grid: TTXStringGrid; ColumnClass: TTXColumnClass);
- function Add: TTXColumn;
- procedure RestoreDefaults;
- property Grid: TTXStringGrid read FGrid;
- property Items[Index: Integer]: TTXColumn read GetTXColumn write SetTXColumn; default;
- end;
- TTXStringGridInplaceEdit = class(TInplaceEditList)
- private
- FDataList: TListBox;
- FUseDataList: Boolean;
- protected
- procedure CloseUp(Accept: Boolean); override;
- procedure DoEditButtonClick; override;
- procedure DropDown; override;
- procedure UpdateContents; override;
- public
- constructor Create(Owner: TComponent); override;
- property DataList: TListBox read FDataList;
- end;
- TTXStringGridClickEvent = procedure (Column: TTXColumn; ARow:integer) of object;
- TTXStringGrid = class(TStringGrid)
- private
- FColumns : TTXColumns;
- FTitleOffset: Byte;
- FUpdateLock: Byte;
- FLayoutLock: Byte;
- FDefaultDrawing: Boolean;
- FSelfChangingTitleFont: Boolean;
- FOnColEnter: TNotifyEvent;
- FOnColExit: TNotifyEvent;
- FVisibleColumns: TList;
- FOnEditButtonClick: TNotifyEvent;
- FOnColumnMoved: TMovedEvent;
- FOnCellClick : TTXStringGridClickEvent;
- FOnTitleClick : TTXStringGridClickEvent;
- function GetTXColumns() : TTXColumns;
- procedure SetTXColumns(value : TTXColumns);
- function AcquireFocus: Boolean;
- procedure InternalLayout;
- procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
- procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
- procedure CMDeferLayout(var Message); message cm_DeferLayout;
- procedure WMSize(var Message: TWMSize); message WM_SIZE;
- procedure WMSetFocus(var Message: TWMSetFocus); message WM_SetFOCUS;
- procedure WMKillFocus(var Message: TMessage); message WM_KillFocus;
- protected
- FAcquireFocus: Boolean;
- function AcquireLayoutLock: Boolean;
- procedure ColWidthsChanged; override;
- procedure BeginLayout;
- procedure BeginUpdate;
- procedure CancelLayout;
- function CanEditModify: Boolean; override;
- function CanEditShow: Boolean; override;
- procedure CellClick(Column: TTXColumn; ARow:integer); dynamic;
- procedure ColumnMoved(FromIndex, ToIndex: Longint); override;
- function CalcTitleRect(Col: TTXColumn; ARow: Integer;
- var MasterCol: TTXColumn): TRect;
- procedure ColEnter; dynamic;
- procedure ColExit; dynamic;
- function CreateEditor: TInplaceEdit; override;
- procedure CreateWnd; override;
- procedure DeferLayout;
- procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
- procedure EditButtonClick; dynamic;
- procedure EndLayout;
- procedure EndUpdate;
- function GetEditStyle(ACol, ARow: Longint): TEditStyle; override;
- function HighlightCell(DataCol, DataRow: Integer; const Value: string;
- AState: TGridDrawState): Boolean; virtual;
- procedure InvalidateTitles;
- procedure LayoutChanged; virtual;
- procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
- X, Y: Integer); override;
- procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
- X, Y: Integer); override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure Scroll(Distance: Integer); virtual;
- procedure SetColumnAttributes; virtual;
- function StoreColumns: Boolean;
- procedure TitleClick(Column: TTXColumn; ARow:integer); dynamic;
- procedure TopLeftChanged; override;
- property DefaultDrawing: Boolean read FDefaultDrawing write FDefaultDrawing default True;
- property LayoutLock: Byte read FLayoutLock;
- property ParentColor default False;
- property UpdateLock: Byte read FUpdateLock;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DefaultHandler(var Msg); override;
- procedure ShowPopupEditor(Column: TTXColumn; X: Integer = Low(Integer);
- Y: Integer = Low(Integer)); dynamic;
- property EditorMode;
- published
- property Columns : TTXColumns read GetTXColumns write SetTXColumns;
- property OnColEnter: TNotifyEvent read FOnColEnter write FOnColEnter;
- property OnColExit: TNotifyEvent read FOnColExit write FOnColExit;
- property OnEditButtonClick: TNotifyEvent read FOnEditButtonClick
- write FOnEditButtonClick;
- property OnColumnMoved: TMovedEvent read FOnColumnMoved write FOnColumnMoved;
- property OnCellClick: TTXStringGridClickEvent read FOnCellClick write FOnCellClick;
- property OnTitleClick: TTXStringGridClickEvent read FOnTitleClick write FOnTitleClick;
- end;
- procedure Register;
- implementation
- uses Math, Forms;
- procedure Register;
- begin
- RegisterComponents('Sample', [TTXStringGrid]);
- end;
- var
- DrawBitmap: TBitmap;
- UserCount: Integer;
- { public function }
- procedure KillMessage(Wnd: HWnd; Msg: Integer);
- // Delete the requested message from the queue, but throw back
- // any WM_QUIT msgs that PeekMessage may also return
- var
- M: TMsg;
- begin
- M.Message := 0;
- if PeekMessage(M, Wnd, Msg, Msg, pm_Remove) and (M.Message = WM_QUIT) then
- PostQuitMessage(M.wparam);
- end;
- procedure RaiseGridError(const S: string);
- begin
- raise EInvalidGridOperation.Create(S);
- end;
- procedure UsesBitmap;
- begin
- if UserCount = 0 then
- DrawBitmap := TBitmap.Create();
- Inc(UserCount);
- end;
- procedure ReleaseBitmap;
- begin
- Dec(UserCount);
- if UserCount = 0 then DrawBitmap.Free;
- end;
- procedure WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer;
- const Text: string; Alignment: TAlignment; ARightToLeft: Boolean);
- const
- AlignFlags : array [TAlignment] of Integer =
- ( DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
- DT_RIGHT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
- DT_CENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX );
- RTL: array [Boolean] of Integer = (0, DT_RTLREADING);
- var
- B, R: TRect;
- Hold, Left: Integer;
- I: TColorRef;
- begin
- I := ColorToRGB(ACanvas.Brush.Color);
- if GetNearestColor(ACanvas.Handle, I) = I then
- begin { Use ExtTextOut for solid colors }
- { In BiDi, because we changed the window origin, the text that does not
- change alignment, actually gets its alignment changed. }
- if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then
- ChangeBiDiModeAlignment(Alignment);
- case Alignment of
- taLeftJustify:
- Left := ARect.Left + DX;
- taRightJustify:
- Left := ARect.Right - ACanvas.TextWidth(Text) - 3;
- else { taCenter }
- Left := ARect.Left + (ARect.Right - ARect.Left) shr 1
- - (ACanvas.TextWidth(Text) shr 1);
- end;
- ACanvas.TextRect(ARect, Left, ARect.Top + DY, Text);
- end
- else begin { Use FillRect and Drawtext for dithered colors }
- DrawBitmap.Canvas.Lock;
- try
- with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and }
- begin { brush origin tics in painting / scrolling. }
- Width := Max(Width, Right - Left);
- Height := Max(Height, Bottom - Top);
- R := Rect(DX, DY, Right - Left - 1, Bottom - Top - 1);
- B := Rect(0, 0, Right - Left, Bottom - Top);
- end;
- with DrawBitmap.Canvas do
- begin
- Font := ACanvas.Font;
- Font.Color := ACanvas.Font.Color;
- Brush := ACanvas.Brush;
- Brush.Style := bsSolid;
- FillRect(B);
- SetBkMode(Handle, TRANSPARENT);
- if (ACanvas.CanvasOrientation = coRightToLeft) then
- ChangeBiDiModeAlignment(Alignment);
- DrawText(Handle, PChar(Text), Length(Text), R,
- AlignFlags[Alignment] or RTL[ARightToLeft]);
- end;
- if (ACanvas.CanvasOrientation = coRightToLeft) then
- begin
- Hold := ARect.Left;
- ARect.Left := ARect.Right;
- ARect.Right := Hold;
- end;
- ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
- finally
- DrawBitmap.Canvas.Unlock;
- end;
- end;
- end;
- { TTXColumnTitle }
- constructor TTXColumnTitle.Create(Column: TTXColumn);
- begin
- inherited Create;
- FColumn := Column;
- FFont := TFont.Create;
- FFont.Assign(DefaultFont);
- FFont.OnChange := FontChanged;
- end;
- destructor TTXColumnTitle.Destroy;
- begin
- FFont.Free;
- inherited Destroy;
- end;
- function TTXColumnTitle.DefaultAlignment: TAlignment;
- begin
- Result := taLeftJustify;
- end;
- function TTXColumnTitle.DefaultColor: TColor;
- var
- Grid: TTXStringGrid;
- begin
- Grid := FColumn.GetGrid;
- if Assigned(Grid) then
- Result := Grid.FixedColor
- else
- Result := clBtnFace;
- end;
- function TTXColumnTitle.DefaultFont: TFont;
- var
- Grid: TTXStringGrid;
- begin
- Grid := FColumn.GetGrid;
- if Assigned(Grid) then
- Result := Grid.Font
- else
- Result := FColumn.Font;
- end;
- procedure TTXColumnTitle.FontChanged(Sender: TObject);
- begin
- Include(FColumn.FAssignedValues, cvTitleFont);
- FColumn.Changed(True);
- end;
- function TTXColumnTitle.GetAlignment: TAlignment;
- begin
- if cvTitleAlignment in FColumn.FAssignedValues then
- Result := FAlignment
- else
- Result := DefaultAlignment;
- end;
- function TTXColumnTitle.GetColor: TColor;
- begin
- if cvTitleColor in FColumn.FAssignedValues then
- Result := FColor
- else
- Result := DefaultColor;
- end;
- function TTXColumnTitle.GetCaption: string;
- begin
- if cvTitleCaption in FColumn.FAssignedValues then
- Result := FCaption;
- end;
- function TTXColumnTitle.GetFont: TFont;
- var
- Save: TNotifyEvent;
- Def: TFont;
- begin
- if not (cvTitleFont in FColumn.FAssignedValues) then
- begin
- Def := DefaultFont;
- if (FFont.Handle <> Def.Handle) or (FFont.Color <> Def.Color) then
- begin
- Save := FFont.OnChange;
- FFont.OnChange := nil;
- FFont.Assign(DefaultFont);
- FFont.OnChange := Save;
- end;
- end;
- Result := FFont;
- end;
- function TTXColumnTitle.IsAlignmentStored: Boolean;
- begin
- Result := (cvTitleAlignment in FColumn.FAssignedValues) and
- (FAlignment <> DefaultAlignment);
- end;
- function TTXColumnTitle.IsColorStored: Boolean;
- begin
- Result := (cvTitleColor in FColumn.FAssignedValues) and
- (FColor <> DefaultColor);
- end;
- function TTXColumnTitle.IsFontStored: Boolean;
- begin
- Result := (cvTitleFont in FColumn.FAssignedValues);
- end;
- function TTXColumnTitle.IsCaptionStored: Boolean;
- begin
- Result := (cvTitleCaption in FColumn.FAssignedValues);
- end;
- procedure TTXColumnTitle.RefreshDefaultFont;
- var
- Save: TNotifyEvent;
- begin
- if (cvTitleFont in FColumn.FAssignedValues) then Exit;
- Save := FFont.OnChange;
- FFont.OnChange := nil;
- try
- FFont.Assign(DefaultFont);
- finally
- FFont.OnChange := Save;
- end;
- end;
- procedure TTXColumnTitle.RestoreDefaults;
- var
- FontAssigned: Boolean;
- begin
- FontAssigned := cvTitleFont in FColumn.FAssignedValues;
- FColumn.FAssignedValues := FColumn.FAssignedValues - ColumnTitleValues;
- FCaption := '';
- RefreshDefaultFont;
- { If font was assigned, changing it back to default may affect grid title
- height, and title height changes require layout and redraw of the grid. }
- FColumn.Changed(FontAssigned);
- end;
- procedure TTXColumnTitle.SetAlignment(Value: TAlignment);
- begin
- if (cvTitleAlignment in FColumn.FAssignedValues) and (Value = FAlignment) then Exit;
- FAlignment := Value;
- Include(FColumn.FAssignedValues, cvTitleAlignment);
- FColumn.Changed(False);
- end;
- procedure TTXColumnTitle.SetColor(Value: TColor);
- begin
- if (cvTitleColor in FColumn.FAssignedValues) and (Value = FColor) then Exit;
- FColor := Value;
- Include(FColumn.FAssignedValues, cvTitleColor);
- FColumn.Changed(False);
- end;
- procedure TTXColumnTitle.SetFont(Value: TFont);
- begin
- FFont.Assign(Value);
- end;
- procedure TTXColumnTitle.SetCaption(const Value: string);
- begin
- if Column.IsStored then
- begin
- if (cvTitleCaption in FColumn.FAssignedValues) and (Value = FCaption) then Exit;
- FCaption := Value;
- Include(Column.FAssignedValues, cvTitleCaption);
- Column.Changed(False);
- end;
- end;
- { TTXColumn }
- constructor TTXColumn.Create(Collection: TCollection);
- begin
- FDropDownRows := 7;
- FButtonStyle := tcbsNone;
- FFont := TFont.Create;
- FFont.Assign(DefaultFont);
- FFont.OnChange := FontChanged;
- FTitle := CreateTitle;
- FVisible := True;
- FWidth := self.DefaultWidth;
- inherited Create(Collection);
- FStored := True;
- end;
- destructor TTXColumn.Destroy;
- begin
- FTitle.Free;
- FFont.Free;
- FPickList.Free;
- inherited Destroy;
- end;
- procedure TTXColumn.Assign(Source: TPersistent);
- begin
- if Source is TTXColumn then
- begin
- if Assigned(Collection) then Collection.BeginUpdate;
- try
- RestoreDefaults;
- if cvColor in TTXColumn(Source).AssignedValues then
- Color := TTXColumn(Source).Color;
- if cvWidth in TTXColumn(Source).AssignedValues then
- Width := TTXColumn(Source).Width;
- if cvFont in TTXColumn(Source).AssignedValues then
- Font := TTXColumn(Source).Font;
- if cvAlignment in TTXColumn(Source).AssignedValues then
- Alignment := TTXColumn(Source).Alignment;
- if cvReadOnly in TTXColumn(Source).AssignedValues then
- ReadOnly := TTXColumn(Source).ReadOnly;
- Title := TTXColumn(Source).Title;
- DropDownRows := TTXColumn(Source).DropDownRows;
- ButtonStyle := TTXColumn(Source).ButtonStyle;
- PickList := TTXColumn(Source).PickList;
- PopupMenu := TTXColumn(Source).PopupMenu;
- finally
- if Assigned(Collection) then Collection.EndUpdate;
- end;
- end
- else
- inherited Assign(Source);
- end;
- function TTXColumn.CreateTitle: TTXColumnTitle;
- begin
- Result := TTXColumnTitle.Create(Self);
- end;
- function TTXColumn.DefaultAlignment: TAlignment;
- begin
- Result := taLeftJustify;
- end;
- function TTXColumn.DefaultColor: TColor;
- var
- Grid: TTXStringGrid;
- begin
- Grid := GetGrid;
- if Assigned(Grid) then
- Result := Grid.Color
- else
- Result := clWindow;
- end;
- function TTXColumn.DefaultFont: TFont;
- var
- Grid: TTXStringGrid;
- begin
- Grid := GetGrid;
- if Assigned(Grid) then
- Result := Grid.Font
- else
- Result := FFont;
- end;
- procedure TTXColumn.FontChanged;
- begin
- Include(FAssignedValues, cvFont);
- Title.RefreshDefaultFont;
- Changed(False);
- end;
- function TTXColumn.GetAlignment: TAlignment;
- begin
- if cvAlignment in FAssignedValues then
- Result := FAlignment
- else
- Result := DefaultAlignment;
- end;
- function TTXColumn.GetColor: TColor;
- begin
- if cvColor in FAssignedValues then
- Result := FColor
- else
- Result := DefaultColor;
- end;
- function TTXColumn.GetFont: TFont;
- var
- Save: TNotifyEvent;
- begin
- if not (cvFont in FAssignedValues) and (FFont.Handle <> DefaultFont.Handle) then
- begin
- Save := FFont.OnChange;
- FFont.OnChange := nil;
- FFont.Assign(DefaultFont);
- FFont.OnChange := Save;
- end;
- Result := FFont;
- end;
- function TTXColumn.GetGrid: TTXStringGrid;
- begin
- if Assigned(Collection) and (Collection is TTXColumns) then
- Result := TTXColumns(Collection).Grid
- else
- Result := nil;
- end;
- function TTXColumn.GetPickList: TStrings;
- begin
- if FPickList = nil then
- FPickList := TStringList.Create;
- Result := FPickList;
- end;
- function TTXColumn.GetReadOnly: Boolean;
- begin
- if cvReadOnly in FAssignedValues then
- Result := FReadOnly
- else
- Result := False; //default "can write"
- end;
- function TTXColumn.IsAlignmentStored: Boolean;
- begin
- Result := (cvAlignment in FAssignedValues) and (FAlignment <> DefaultAlignment);
- end;
- function TTXColumn.IsColorStored: Boolean;
- begin
- Result := (cvColor in FAssignedValues) and (FColor <> DefaultColor);
- end;
- function TTXColumn.IsFontStored: Boolean;
- begin
- Result := (cvFont in FAssignedValues);
- end;
- function TTXColumn.IsReadOnlyStored: Boolean;
- begin
- Result := (cvReadOnly in FAssignedValues) and (FReadOnly <> false);
- end;
- procedure TTXColumn.RefreshDefaultFont;
- var
- Save: TNotifyEvent;
- begin
- if cvFont in FAssignedValues then Exit;
- Save := FFont.OnChange;
- FFont.OnChange := nil;
- try
- FFont.Assign(DefaultFont);
- finally
- FFont.OnChange := Save;
- end;
- end;
- procedure TTXColumn.RestoreDefaults;
- var
- FontAssigned: Boolean;
- begin
- FontAssigned := cvFont in FAssignedValues;
- FTitle.RestoreDefaults;
- FAssignedValues := [];
- RefreshDefaultFont;
- FPickList.Free;
- FPickList := nil;
- ButtonStyle := tcbsNone;
- Changed(FontAssigned);
- end;
- procedure TTXColumn.SetAlignment(Value: TAlignment);
- begin
- if IsStored then
- begin
- if (cvAlignment in FAssignedValues) and (Value = FAlignment) then Exit;
- FAlignment := Value;
- Include(FAssignedValues, cvAlignment);
- Changed(False);
- end;
- end;
- procedure TTXColumn.SetButtonStyle(Value: TTXColButtonStyle);
- begin
- if Value = FButtonStyle then Exit;
- FButtonStyle := Value;
- Changed(False);
- end;
- procedure TTXColumn.SetColor(Value: TColor);
- begin
- if (cvColor in FAssignedValues) and (Value = FColor) then Exit;
- FColor := Value;
- Include(FAssignedValues, cvColor);
- Changed(False);
- end;
- procedure TTXColumn.SetFont(Value: TFont);
- begin
- FFont.Assign(Value);
- Include(FAssignedValues, cvFont);
- Changed(False);
- end;
- procedure TTXColumn.SetPickList(Value: TStrings);
- begin
- if Value = nil then
- begin
- FPickList.Free;
- FPickList := nil;
- Exit;
- end;
- PickList.Assign(Value);
- end;
- procedure TTXColumn.SetPopupMenu(Value: TPopupMenu);
- begin
- FPopupMenu := Value;
- if Value <> nil then Value.FreeNotification(GetGrid);
- end;
- procedure TTXColumn.SetReadOnly(Value: Boolean);
- begin
- if IsStored then
- begin
- if (cvReadOnly in FAssignedValues) and (Value = FReadOnly) then Exit;
- FReadOnly := Value;
- Include(FAssignedValues, cvReadOnly);
- Changed(False);
- end;
- end;
- procedure TTXColumn.SetTitle(Value: TTXColumnTitle);
- begin
- FTitle.Assign(Value);
- end;
- procedure TTXColumn.SetVisible(const Value: Boolean);
- begin
- if Value <> FVisible then
- begin
- FVisible := Value;
- Changed(True);
- end;
- end;
- function TTXColumn.GetWidth: Integer;
- begin
- if not Visible then
- Result := -1
- else if cvWidth in FAssignedValues then
- Result := FWidth
- else
- Result := DefaultWidth;
- end;
- function TTXColumn.IsWidthStored: Boolean;
- begin
- Result := (cvWidth in FAssignedValues) and
- (FWidth <> DefaultWidth);
- end;
- procedure TTXColumn.SetWidth(const Value: Integer);
- var
- Grid: TTXStringGrid;
- TM: TTextMetric;
- DoSetWidth: Boolean;
- begin
- DoSetWidth := IsStored;
- if not DoSetWidth then
- begin
- Grid := GetGrid;
- if Assigned(Grid) then
- begin
- if Grid.HandleAllocated then
- with Grid do
- begin
- Canvas.Font := Self.Font;
- GetTextMetrics(Canvas.Handle, TM);
- end;
- if (cvWidth in FAssignedValues) then
- DoSetWidth := True;
- end
- else
- DoSetWidth := True;
- end;
- if DoSetWidth then
- begin
- if ((cvWidth in FAssignedValues) or (Value <> DefaultWidth))
- and (Value <> -1) then
- begin
- FWidth := Value;
- Include(FAssignedValues, cvWidth);
- end;
- Changed(False);
- end;
- end;
- function TTXColumn.DefaultWidth: integer;
- begin
- if Assigned(self.Collection) and Assigned(TTXColumns(self.Collection).FGrid) then
- Result := TTXColumns(self.Collection).FGrid.DefaultColWidth
- else
- Result := 60;
- end;
- { TTXColumns }
- constructor TTXColumns.Create(Grid: TTXStringGrid; ColumnClass: TTXColumnClass);
- begin
- inherited Create(ColumnClass);
- FGrid := Grid;
- end;
- function TTXColumns.Add: TTXColumn;
- begin
- Result := TTXColumn(inherited Add);
- end;
- function TTXColumns.GetTXColumn(Index: Integer): TTXColumn;
- begin
- Result := TTXColumn(inherited Items[Index]);
- end;
- function TTXColumns.GetOwner: TPersistent;
- begin
- Result := FGrid;
- end;
- type
- TTXColumnsWrapper = class(TComponent)
- private
- FColumns: TTXColumns;
- published
- property Columns: TTXColumns read FColumns write FColumns;
- end;
- procedure TTXColumns.RestoreDefaults;
- var
- I: Integer;
- begin
- BeginUpdate;
- try
- for I := 0 to Count - 1 do
- Items[I].RestoreDefaults;
- finally
- EndUpdate;
- end;
- end;
- procedure TTXColumns.SetTXColumn(Index: Integer; Value: TTXColumn);
- begin
- Items[Index].Assign(Value);
- end;
- procedure TTXColumns.Update(Item: TCollectionItem);
- var
- Raw: Integer;
- begin
- if (FGrid = nil) or (csLoading in FGrid.ComponentState) then Exit;
- inherited;
- if Item = nil then
- begin
- self.FGrid.ColCount := self.Count;
- FGrid.LayoutChanged;
- end
- else
- begin
- Raw := Item.Index;
- FGrid.InvalidateCol(Raw);
- FGrid.ColWidths[Raw] := TTXColumn(Item).Width;
- end;
- end;
- function TTXStringGrid.GetTXColumns: TTXColumns;
- begin
- Result := self.FColumns;
- end;
- procedure TTXStringGrid.SetTXColumns(value: TTXColumns);
- begin
- self.Columns.Assign(value);
- end;
- { Class TTXStringGridInplaceEdit }
- constructor TTXStringGridInplaceEdit.Create(Owner: TComponent);
- begin
- inherited Create(Owner);
- end;
- procedure TTXStringGridInplaceEdit.CloseUp(Accept: Boolean);
- var
- ListValue: string;
- begin
- if ListVisible then
- begin
- if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
- if ActiveList = DataList then
- begin
- if DataList.ItemIndex >= 0 then
- ListValue := DataList.Items[DataList.ItemIndex];
- end
- else
- if PickList.ItemIndex <> -1 then
- ListValue := PickList.Items[Picklist.ItemIndex];
- SetWindowPos(ActiveList.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
- SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
- ListVisible := False;
- Invalidate;
- if Accept then
- with TTXStringGrid(Grid) do
- begin
- if ActiveList = DataList then
- Cells[Col, Row] := ListValue
- else
- if EditCanModify then
- Cells[Col, Row] := ListValue;
- end;
- end;
- end;
- procedure TTXStringGridInplaceEdit.DoEditButtonClick;
- begin
- TTXStringGrid(Grid).EditButtonClick;
- end;
- procedure TTXStringGridInplaceEdit.DropDown;
- var
- Column: TTXColumn;
- begin
- if not ListVisible then
- begin
- with TTXStringGrid(Grid) do
- Column := Columns[Col];
- with Column do begin
- if ActiveList = FDataList then
- begin
- FDataList.Color := Color;
- FDataList.Font := Font;
- end
- else if ActiveList = self.PickList then
- begin
- self.PickList.Items.Assign(PickList);
- self.DropDownRows := Column.DropDownRows;
- end;
- end;
- end;
- inherited DropDown;
- end;
- procedure TTXStringGridInplaceEdit.UpdateContents;
- var
- Column: TTXColumn;
- begin
- inherited UpdateContents;
- if FUseDataList then
- begin
- if FDataList = nil then
- begin
- FDataList := TListBox.Create(Self);
- FDataList.Visible := False;
- FDataList.Parent := Self;
- FDataList.OnMouseUp := ListMouseUp;
- end;
- ActiveList := FDataList;
- end;
- with TTXStringGrid(Grid) do
- Column := Columns[Col];
- Self.ReadOnly := Column.ReadOnly;
- Font.Assign(Column.Font);
- end;
- { TTXStringGrid }
- constructor TTXStringGrid.Create(AOwner: TComponent);
- var
- i : integer;
- begin
- inherited Create(AOwner);
- inherited DefaultDrawing := False;
- FAcquireFocus := True;
- FTitleOffset := 1;
- DesignOptionsBoost := [goColSizing, goRowSizing, goAlwaysShowEditor];
- VirtualView := True;
- UsesBitmap;
- FVisibleColumns := TList.Create;
- Color := clWindow;
- ParentColor := False;
- FDefaultDrawing := True;
- HideEditor;
- self.FColumns := TTXColumns.Create(self, TTXColumn);
- for i := 0 to self.ColCount - 1 do //create default columns
- Begin
- self.FColumns.Add();
- //self.ColWidths[i] := self.DefaultColWidth;
- end;
- end;
- destructor TTXStringGrid.Destroy;
- begin
- FColumns.Clear();
- FColumns.Free;
- FColumns := nil;
- FVisibleColumns.Free;
- FVisibleColumns := nil;
- inherited Destroy;
- ReleaseBitmap;
- end;
- function TTXStringGrid.AcquireLayoutLock: Boolean;
- begin
- Result := (FUpdateLock = 0) and (FLayoutLock = 0);
- if Result then BeginLayout;
- end;
- procedure TTXStringGrid.BeginLayout;
- begin
- BeginUpdate;
- if (FLayoutLock = 0) and (Assigned(Columns)) then Columns.BeginUpdate;
- Inc(FLayoutLock);
- end;
- procedure TTXStringGrid.BeginUpdate;
- begin
- Inc(FUpdateLock);
- end;
- procedure TTXStringGrid.CancelLayout;
- begin
- if FLayoutLock > 0 then
- begin
- if FLayoutLock = 1 then
- Columns.EndUpdate;
- Dec(FLayoutLock);
- EndUpdate;
- end;
- end;
- function TTXStringGrid.CanEditModify: Boolean;
- begin
- Result := not Columns[Col].ReadOnly;
- end;
- function TTXStringGrid.CanEditShow: Boolean;
- begin
- Result := (LayoutLock = 0) and inherited CanEditShow;
- end;
- procedure TTXStringGrid.CellClick(Column: TTXColumn; ARow:integer);
- begin
- if Assigned(FOnCellClick) then FOnCellClick(Column, ARow);
- end;
- procedure TTXStringGrid.ColEnter;
- begin
- if Assigned(FOnColEnter) then FOnColEnter(Self);
- end;
- procedure TTXStringGrid.ColExit;
- begin
- if Assigned(FOnColExit) then FOnColExit(Self);
- end;
- procedure TTXStringGrid.ColumnMoved(FromIndex, ToIndex: Longint);
- begin
- Columns[FromIndex].Index := ToIndex;
- inherited ColumnMoved(FromIndex, ToIndex);
- if Assigned(FOnColumnMoved) then FOnColumnMoved(Self, FromIndex, ToIndex);
- end;
- function TTXStringGrid.CreateEditor: TInplaceEdit;
- begin
- Result := TTXStringGridInplaceEdit.Create(Self);
- end;
- procedure TTXStringGrid.CreateWnd;
- begin
- BeginUpdate; { prevent updates in WMSize message that follows WMCreate }
- try
- inherited CreateWnd;
- finally
- EndUpdate;
- end;
- end;
- procedure TTXStringGrid.DefaultHandler(var Msg);
- var
- P: TPopupMenu;
- Cell: TGridCoord;
- begin
- inherited DefaultHandler(Msg);
- if TMessage(Msg).Msg = wm_RButtonUp then
- with TWMRButtonUp(Msg) do
- begin
- Cell := MouseCoord(XPos, YPos);
- if (Cell.X < 0) or (Cell.Y < 0) then Exit;
- P := Columns[Cell.X].PopupMenu;
- if (P <> nil) and P.AutoPopup then
- begin
- SendCancelMode(nil);
- P.PopupComponent := Self;
- with ClientToScreen(SmallPointToPoint(Pos)) do
- P.Popup(X, Y);
- Result := 1;
- end;
- end;
- end;
- procedure TTXStringGrid.DeferLayout;
- var
- M: TMsg;
- begin
- if HandleAllocated and
- not PeekMessage(M, Handle, cm_DeferLayout, cm_DeferLayout, pm_NoRemove) then
- PostMessage(Handle, cm_DeferLayout, 0, 0);
- CancelLayout;
- end;
- function TTXStringGrid.CalcTitleRect(Col: TTXColumn; ARow: Integer;
- var MasterCol: TTXColumn): TRect;
- var
- I,J, W: Integer;
- DrawInfo: TGridDrawInfo;
- begin
- MasterCol := Col; //we don't surpport Parent column
- I := Col.Index;
- J := ARow;
- Result := CellRect(I, J);
- W := self.ColWidths[I];
- Result.Right := Min(Result.Right, W + Result.Left);
- if (J < FixedRows-1) then
- begin
- CalcFixedInfo(DrawInfo);
- Result.Bottom := DrawInfo.Vert.FixedBoundary - DrawInfo.Vert.EffectiveLineWidth;
- end;
- end;
- procedure TTXStringGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);
- var
- FrameOffs: Byte;
- procedure DrawTitleCell(ACol, ARow: Integer; Column: TTXColumn; var AState: TGridDrawState);
- const
- ScrollArrows: array [Boolean, Boolean] of Integer =
- ((DFCS_SCROLLRIGHT, DFCS_SCROLLLEFT), (DFCS_SCROLLLEFT, DFCS_SCROLLRIGHT));
- var
- MasterCol: TTXColumn;
- TitleRect, TextRect: TRect;
- begin
- TitleRect := CalcTitleRect(Column, ARow, MasterCol);
- if MasterCol = nil then
- begin
- Canvas.FillRect(ARect);
- Exit;
- end;
- Canvas.Font := MasterCol.Title.Font;
- Canvas.Brush.Color := MasterCol.Title.Color;
- if [goVertLine, goHorzLine] * Options = [goVertLine, goHorzLine] then
- InflateRect(TitleRect, -1, -1);
- TextRect := TitleRect;
- with MasterCol.Title do
- WriteText(Canvas, TextRect, FrameOffs, FrameOffs, Caption, Alignment,
- IsRightToLeft);
- if [goVertLine, goHorzLine] * Options = [goVertLine, goHorzLine] then
- begin
- InflateRect(TitleRect, 1, 1);
- DrawEdge(Canvas.Handle, TitleRect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
- DrawEdge(Canvas.Handle, TitleRect, BDR_RAISEDINNER, BF_TOPLEFT);
- end;
- AState := AState - [gdFixed]; // prevent box drawing later
- end;
- var
- Highlight: Boolean;
- Value: string;
- DrawColumn: TTXColumn;
- begin
- if csLoading in ComponentState then
- begin
- Canvas.Brush.Color := Color;
- Canvas.FillRect(ARect);
- Exit;
- end;
- Dec(ARow, FTitleOffset);
- if (gdFixed in AState) and ([goVertLine, goHorzLine] * Options =
- [goVertLine, goHorzLine]) then
- begin
- InflateRect(ARect, -1, -1);
- FrameOffs := 1;
- end
- else
- FrameOffs := 2;
- if (gdFixed in AState) and (ACol < 0) then
- begin
- Canvas.Brush.Color := FixedColor;
- Canvas.FillRect(ARect);
- end
- else with Canvas do
- begin
- DrawColumn := Columns[ACol];
- if (not DrawColumn.Visible) then Exit; //don't draw hidden column
- if not (gdFixed in AState) then
- begin
- Font := DrawColumn.Font;
- Brush.Color := DrawColumn.Color;
- end;
- if ARow < 0 then
- DrawTitleCell(ACol, ARow + FTitleOffset, DrawColumn, AState)
- else
- begin
- inc(ARow, FTitleOffset);
- Value := self.Cells[ACol, ARow];
- Highlight := HighlightCell(ACol, ARow, Value, AState);
- if Highlight then
- begin
- Brush.Color := clHighlight;
- Font.Color := clHighlightText;
- end;
- if not Enabled then
- Font.Color := clGrayText;
- if FDefaultDrawing then
- WriteText(Canvas, ARect, 2, 2, Value, DrawColumn.Alignment, False);
- if FDefaultDrawing and (gdSelected in AState)
- and ((goDrawFocusSelected in Options) or Focused)
- and not (csDesigning in ComponentState)
- and not (goRowSelect in Options)
- and (UpdateLock = 0)
- and (ValidParentForm(Self).ActiveControl = Self) then
- Windows.DrawFocusRect(Handle, ARect);
- end;
- end;
- if (gdFixed in AState) and ([goVertLine, goHorzLine] * Options =
- [goVertLine, goHorzLine]) then
- begin
- InflateRect(ARect, 1, 1);
- DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
- DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT);
- end;
- end;
- procedure TTXStringGrid.EditButtonClick;
- begin
- if Assigned(FOnEditButtonClick) then
- FOnEditButtonClick(Self)
- else
- ShowPopupEditor(Columns[Col]);
- end;
- procedure TTXStringGrid.EndLayout;
- begin
- if FLayoutLock > 0 then
- begin
- try
- try
- if FLayoutLock = 1 then
- InternalLayout;
- finally
- if FLayoutLock = 1 then
- FColumns.EndUpdate;
- end;
- finally
- Dec(FLayoutLock);
- EndUpdate;
- end;
- end;
- end;
- procedure TTXStringGrid.EndUpdate;
- begin
- if FUpdateLock > 0 then
- Dec(FUpdateLock);
- end;
- function TTXStringGrid.GetEditStyle(ACol, ARow: Integer): TEditStyle;
- var
- Column: TTXColumn;
- begin
- TTXStringGridInplaceEdit(InplaceEditor).FUseDataList := False;
- Column := Columns[Col];
- Result := esSimple;
- case Column.ButtonStyle of
- tcbsEllipse:
- Result := esEllipsis;
- tcbsAutoSelect:
- Result := esPickList;
- end;
- end;
- function TTXStringGrid.HighlightCell(DataCol, DataRow: Integer;
- const Value: string; AState: TGridDrawState): Boolean;
- begin
- Result := (gdSelected in AState)
- and ((goDrawFocusSelected in Options) or Focused)
- { updatelock eliminates flicker when tabbing between rows }
- and ((UpdateLock = 0) or (goRowSelect in Options));
- end;
- { InternalLayout is called with layout locks and column locks in effect }
- procedure TTXStringGrid.InternalLayout;
- procedure CheckForPassthroughs; // check for Columns.State flip-flop
- var
- SeenPassthrough: Boolean;
- I, J: Integer;
- Column: TTXColumn;
- begin
- SeenPassthrough := False;
- for I := 0 to FColumns.Count-1 do
- if not FColumns[I].IsStored then
- SeenPassthrough := True
- else if SeenPassthrough then
- begin // we have both persistent and non-persistent columns. Kill the latter
- for J := FColumns.Count-1 downto 0 do
- begin
- Column := FColumns[J];
- if not Column.IsStored then
- Column.Free;
- end;
- Exit;
- end;
- end;
- procedure MeasureTitleHeights; //get the max height of the title
- var
- I, J, K: Integer;
- RestoreCanvas: Boolean;
- Heights: Integer;
- begin
- Heights := 0;
- RestoreCanvas := not HandleAllocated;
- if RestoreCanvas then
- Canvas.Handle := GetDC(0);
- try
- Canvas.Font := Font;
- K := Canvas.TextHeight('Wg') + 3;
- if goHorzLine in Options then
- Inc(K, GridLineWidth);
- DefaultRowHeight := K;
- if goFixedHorzLine in Options then
- begin
- for I := 0 to FColumns.Count-1 do
- begin
- if FColumns[I].Title <> nil then
- Canvas.Font := FColumns[I].Title.Font
- else
- Canvas.Font := FColumns[I].DefaultFont();
- J := Canvas.TextHeight('Wg') + 4;
- Heights := Max(J, Heights);
- end;
- if Heights = 0 then
- begin
- Canvas.Font := self.Font;
- Heights := Canvas.TextHeight('Wg') + 4;
- end;
- RowHeights[0] := Heights;
- end;
- finally
- if RestoreCanvas then
- begin
- ReleaseDC(0,Canvas.Handle);
- Canvas.Handle := 0;
- end;
- end;
- end;
- var
- I: Integer;
- begin
- if ([csLoading, csDestroying] * ComponentState) <> [] then Exit;
- if HandleAllocated then KillMessage(Handle, cm_DeferLayout);
- CheckForPassthroughs;
- FVisibleColumns.Clear;
- for I := 0 to FColumns.Count-1 do
- if (FColumns[I].Visible) then
- FVisibleColumns.Add(FColumns[I]);
- ColCount := FColumns.Count;
- FTitleOffset := 0;
- if goFixedHorzLine in Options then
- begin
- FTitleOffset := 1;
- end;
- MeasureTitleHeights;
- SetColumnAttributes;
- Invalidate;
- end;
- procedure TTXStringGrid.LayoutChanged;
- begin
- if AcquireLayoutLock then
- EndLayout;
- end;
- function TTXStringGrid.AcquireFocus: Boolean;
- begin
- Result := True;
- if FAcquireFocus and CanFocus and not (csDesigning in ComponentState) then
- begin
- SetFocus;
- Result := Focused or (InplaceEditor <> nil) and InplaceEditor.Focused;
- end;
- end;
- procedure TTXStringGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
- X, Y: Integer);
- var
- Cell: TGridCoord;
- begin
- if not AcquireFocus then Exit;
- if (ssDouble in Shift) and (Button = mbLeft) then
- begin
- DblClick;
- Exit;
- end;
- if Sizing(X, Y) then
- begin
- inherited MouseDown(Button, Shift, X, Y);
- Exit;
- end;
- Cell := MouseCoord(X, Y);
- if (Cell.X < 0) and (Cell.Y < 0) then
- begin
- inherited MouseDown(Button, Shift, X, Y);
- Exit;
- end;
- if (DragKind = dkDock) and
- (Cell.Y < FTitleOffset) and (not (csDesigning in ComponentState)) then
- begin
- BeginDrag(false);
- Exit;
- end;
- if ((csDesigning in self.ComponentState) or (goColSizing in self.Options)) and
- (Cell.Y < FTitleOffset) then
- begin
- inherited MouseDown(Button, Shift, X, Y);
- Exit;
- end;
- inherited MouseDown(Button, Shift, X, Y);
- end;
- procedure TTXStringGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
- X, Y: Integer);
- var
- Cell: TGridCoord;
- SaveState: TGridState;
- begin
- SaveState := FGridState;
- inherited MouseUp(Button, Shift, X, Y);
- if (SaveState = gsRowSizing) or (SaveState = gsColSizing) or
- ((InplaceEditor <> nil) and (InplaceEditor.Visible) and
- (PtInRect(InplaceEditor.BoundsRect, Point(X,Y)))) then Exit;
- Cell := MouseCoord(X,Y);
- if (Button = mbLeft) and (Cell.Y >= 0) then
- if Cell.Y < FTitleOffset then
- TitleClick(Columns[Cell.X], Cell.Y)
- else
- CellClick(Columns[Cell.X], Cell.Y);
- end;
- procedure TTXStringGrid.Notification(AComponent: TComponent;
- Operation: TOperation);
- var
- I: Integer;
- begin
- inherited Notification(AComponent, Operation);
- if (Operation = opRemove) then
- begin
- if (AComponent is TPopupMenu) then
- begin
- for I := 0 to Columns.Count-1 do
- if Columns[I].PopupMenu = AComponent then
- Columns[I].PopupMenu := nil;
- end ;
- end;
- end;
- procedure TTXStringGrid.Scroll(Distance: Integer);
- var
- OldRect, NewRect: TRect;
- RowHeight: Integer;
- begin
- if not HandleAllocated then Exit;
- OldRect := BoxRect(0, Row, ColCount - 1, Row);
- NewRect := BoxRect(0, Row, ColCount - 1, Row);
- ValidateRect(Handle, @OldRect);
- InvalidateRect(Handle, @OldRect, False);
- InvalidateRect(Handle, @NewRect, False);
- if Distance <> 0 then
- begin
- HideEditor;
- try
- if Abs(Distance) > VisibleRowCount then
- begin
- Invalidate;
- Exit;
- end
- else
- begin
- RowHeight := DefaultRowHeight;
- if goHorzLine in Options then Inc(RowHeight, GridLineWidth);
- NewRect := BoxRect(0, FTitleOffset, ColCount - 1, 1000);
- ScrollWindowEx(Handle, 0, -RowHeight * Distance, @NewRect, @NewRect,
- 0, nil, SW_Invalidate);
- end;
- finally
- if goAlwaysShowEditor in Options then ShowEditor;
- end;
- end;
- if UpdateLock = 0 then Update;
- end;
- procedure TTXStringGrid.SetColumnAttributes;
- var
- I: Integer;
- begin
- for I := 0 to FColumns.Count-1 do
- with FColumns[I] do
- begin
- TabStops[I] := Visible and not ReadOnly ;
- ColWidths[I] := Width;
- end;
- end;
- function TTXStringGrid.StoreColumns: Boolean;
- begin
- Result := true;
- end;
- procedure TTXStringGrid.TitleClick(Column: TTXColumn; ARow:integer);
- begin
- if Assigned(FOnTitleClick) then FOnTitleClick(Column, ARow);
- end;
- procedure TTXStringGrid.CMParentFontChanged(var Message: TMessage);
- begin
- inherited;
- if ParentFont then
- begin
- FSelfChangingTitleFont := True;
- FSelfChangingTitleFont := False;
- LayoutChanged;
- end;
- end;
- procedure TTXStringGrid.CMFontChanged(var Message: TMessage);
- var
- I: Integer;
- begin
- inherited;
- BeginLayout;
- try
- for I := 0 to Columns.Count-1 do
- Columns[I].RefreshDefaultFont;
- finally
- EndLayout;
- end;
- end;
- procedure TTXStringGrid.CMDeferLayout(var Message);
- begin
- if AcquireLayoutLock then
- EndLayout
- else
- DeferLayout;
- end;
- procedure TTXStringGrid.WMSize(var Message: TWMSize);
- begin
- inherited;
- InvalidateTitles;
- end;
- procedure TTXStringGrid.WMSetFocus(var Message: TWMSetFocus);
- begin
- if not ((InplaceEditor <> nil) and
- (Message.FocusedWnd = InplaceEditor.Handle)) then SetIme;
- inherited;
- end;
- procedure TTXStringGrid.WMKillFocus(var Message: TMessage);
- begin
- if not SysLocale.FarEast then inherited
- else
- begin
- ImeName := Screen.DefaultIme;
- ImeMode := imDontCare;
- inherited;
- if not ((InplaceEditor <> nil) and
- (HWND(Message.WParam) = InplaceEditor.Handle)) then
- ActivateKeyboardLayout(Screen.DefaultKbLayout, KLF_ACTIVATE);
- end;
- end;
- { Defer action processing to datalink }
- procedure TTXStringGrid.ShowPopupEditor(Column: TTXColumn; X, Y: Integer);
- var
- SubGrid: TTXStringGrid;
- I: Integer;
- FloatRect: TRect;
- Cmp: TControl;
- begin
- // find existing popup for this column field, if any, and show it
- for I := 0 to ComponentCount-1 do
- if Components[I] is TTXStringGrid then
- begin
- SubGrid := TTXStringGrid(Components[I]);
- begin
- SubGrid.Parent.Show;
- SubGrid.SetFocus;
- Exit;
- end;
- end;
- // create another instance of this kind of grid
- SubGrid := TTXStringGrid(TComponentClass(Self.ClassType).Create(Self));
- try
- SubGrid.Visible := False;
- SubGrid.FloatingDockSiteClass := TCustomDockForm;
- FloatRect.TopLeft := ClientToScreen(CellRect(Col, Row).BottomRight);
- if X > Low(Integer) then FloatRect.Left := X;
- if Y > Low(Integer) then FloatRect.Top := Y;
- FloatRect.Right := FloatRect.Left + Width;
- FloatRect.Bottom := FloatRect.Top + Height;
- SubGrid.ManualFloat(FloatRect);
- // SubGrid.ManualDock(nil,nil,alClient);
- SubGrid.Parent.BiDiMode := Self.BiDiMode; { This carries the BiDi setting }
- I := SubGrid.CellRect(SubGrid.ColCount-1, 0).Right;
- if (I > 0) and (I < Screen.Width div 2) then
- SubGrid.Parent.ClientWidth := I
- else
- SubGrid.Parent.Width := Screen.Width div 4;
- SubGrid.Parent.Height := Screen.Height div 4;
- SubGrid.Align := alClient;
- SubGrid.DragKind := dkDock;
- SubGrid.Color := Color;
- SubGrid.Ctl3D := Ctl3D;
- SubGrid.Cursor := Cursor;
- SubGrid.Enabled := Enabled;
- SubGrid.FixedColor := FixedColor;
- SubGrid.Font := Font;
- SubGrid.HelpContext := HelpContext;
- SubGrid.IMEMode := IMEMode;
- SubGrid.IMEName := IMEName;
- SubGrid.Options := Options;
- Cmp := Self;
- while (Cmp <> nil) and (TTXStringGrid(Cmp).PopupMenu = nil) do
- Cmp := Cmp.Parent;
- if Cmp <> nil then
- SubGrid.PopupMenu := TTXStringGrid(Cmp).PopupMenu;
- SubGrid.Visible := True;
- SubGrid.Parent.Show;
- except
- SubGrid.Free;
- raise;
- end;
- end;
- procedure TTXStringGrid.InvalidateTitles;
- var
- R: TRect;
- DrawInfo: TGridDrawInfo;
- begin
- if HandleAllocated then
- begin
- CalcFixedInfo(DrawInfo);
- R := Rect(0, 0, Width, DrawInfo.Vert.FixedBoundary);
- InvalidateRect(Handle, @R, False);
- end;
- end;
- procedure TTXStringGrid.TopLeftChanged;
- begin
- InvalidateTitles;
- inherited TopLeftChanged;
- end;
- procedure TTXStringGrid.ColWidthsChanged;
- var
- I: Integer;
- begin
- inherited ColWidthsChanged;
- if FColumns <> nil then
- begin
- if AcquireLayoutLock then
- try
- for I := 0 to ColCount - 1 do
- FColumns[I].Width := ColWidths[I];
- finally
- EndLayout;
- end;
- end;
- end;
- end.
===================================
非注明转载的文章和blog在未特殊声明情况下一般为本人原创或整理,
原创文章版权本人(lonefox)所有;转载文章版权归原作者所有;
http://blog.youkuaiyun.com/boythl
欢迎转载,但请注明出处,保留作者和版权信息。
===================================
本文介绍了一个Delphi组件TXStringGrid,它允许在TStringGrid中添加内置下拉列表,类似于TDBGrid的功能。该组件开源免费,支持列设置、事件监听等功能。
573





