【问题标题】:StringGrid Objects - access violationStringGrid 对象 - 访问冲突
【发布时间】:2015-07-30 10:03:34
【问题描述】:

我试图在我的后代中使用 Stringgrid 的 Objects 属性,但我认为我做错了什么。 因此,我创建了一个简单的类用于我的 StringGrid 单元格,例如:

type

  TKind = (tkNone,tkStart, tkEnd, tkMiddle);

  TMyCell = class(TObject)
  private
    FKind:string; // TKind: start, middle, end, none
    FOfType:string; // new, registered, paid, over, none
    FActualDate:TDate; 
    FTheText:string; // if you want to show a text in it
    FIsWeekend:Boolean;
    function IsItWeekend(dt:Tdate):boolean;
    procedure setKind(s:string);
    { Private declarations }
  protected
    { Protected declarations }
  public
    constructor Create;
    property Kind:string read FKind write setKind;
    property OfType:string read FOfType write FOfType;
    property ActualDate:TDate read FActualDate write FActualDate;
    property TheText:string read FTheText write FTheText;
    property IsWeekend:Boolean read FIsWeekend write FIsWeekend default false;
    { Public declarations }
  published
    { Published declarations }
  end;


implementation

procedure TMyCell.setKind(s:string);
begin
  FKind:=s;
end;

function TMyCell.IsItWeekend(dt:Tdate):boolean;
begin
  if (DayOfTheWeek(dt)=6) or (DayOfTheWeek(dt)=7) then IsItWeekend:=true else IsItWeekend:=false;    
end;

constructor TMyCell.Create;
var
  i:integer;
  a,l,z:word;
  dt:TDate;
begin
  FKind:='none';
  FOfType:='none';
  FActualDate:=now;
  FTheText:='';
  FIsWeekend:=IsItWeekend(FActualDate);
end;

然后,在我的 StringGrid 后代 (TMyGrid) 中,我执行以下操作:

 TMyGrid = class(TStringGrid)
  private
    FStartSelection:integer;
    FFixedColor:TColor;
    FRowCount:integer;
  ...
  published
    property ColCount;
    property RowCount;
  ...

constructor TMyGrid.Create(AOwner: TComponent);
var
  i:integer;
  a,l,z:word;
  dt:TDate;
  j: Integer;
  myCell:TMyCell;
begin
  inherited;
  ...// different settings
  RowCount:=5;
  for i := 0 to colCount-1 do
    for j := 0 to RowCount-1 do
      begin
        Objects[i, j] := TMyCell.Create;
      end;
end;

destructor TMyGrid.Destroy;
var
  i,j:integer;
begin
  for i := 0 to colCount-1 do
    for j := 0 to RowCount-1 do
      begin
        TMyCell(Objects[i, j]).Free;
      end;
  inherited;
end;

... // other stuff

procedure Register;
begin
  RegisterComponents('mygrid', [TMyGrid]);
end;

问题是当开发人员在运行应用程序之前更改 objectInspector 中的 RowCount 时,我不知道如何告诉我的控件有更多行。 所以我将我的 StrinGrid 后代放在一个表单上,并将 rowCount 设置为 10。但是我的 StringGrid 没有为新行创建对象,因此 ARow=5->9 上的单元格没有创建对象......因为在OnCreate 我只将 RowCount 的初始值设置为 5,并为 i:=0 创建对象到 RowCount-1。

在开发人员更改 ObjectInspector 中的 rowCount 后,是否有可以告诉 StringGrid 创建对象的事件或方法?

我确定这是我的问题,因为使用上面的代码,当我将 stringGrid 放在表单上并将其 rowCount(设计时间或运行时)设置为 10 时,我想为Row>4 上的单元格我得到 AccessViolation,但如果我对

我在这里找到了一些有用的东西:http://embarcadero.newsgroups.archived.at/public.delphi.ide/200904/0904193279.html 但我不知道如何以及在何处将此代码放置在我的 StringGrid 后代类中,以便在设计时/运行时更改 RowCount 时调用它

编辑

在阅读了您的 cmets 之后,我尝试了您的想法(这似乎有效)来覆盖 SizeChanged(我不知道该方法存在,我之前搜索时一定跳过了它)。 无论如何,我将此代码添加到我的班级:

TMyGrid = class(TStringGrid)
  private
    ...
    procedure SizeChanged(OldColCount, OldRowCount: Longint); override;
    procedure UpdateGridDimensions(NewColCount, NewRowCount: Integer);
    ...

procedure TMyGrid.SizeChanged(OldColCount, OldRowCount: Longint);
begin
  inherited;
  if (OldRowCount<>FRowCount)or(OldColCount<>ColCount) then
    UpdateGridDimensions(ColCount, FRowCount);
end;


procedure TMyGrid.UpdateGridDimensions(NewColCount, NewRowCount: Integer);
 var
    C, R: Integer;
    Old: Integer;
 begin
    if NewColCount <> ColCount then
    begin
        if NewColCount < ColCount then
        begin
            for R := 0 to RowCount-1 do
            begin
                for C := ColCount-1 downto NewColCount do
                    Objects[C, R].Free;
            end;
        end;

        Old := ColCount;
        ColCount := NewColCount;

        if NewColCount > Old then
        begin
            for R := 0 to RowCount-1 do
            begin
                for C := Old to NewColCount-1 do
                    Objects[C, R] := TMyCell.Create;
            end;
        end;
    end;

    if NewRowCount <> RowCount then
    begin
        if NewRowCount < RowCount then
        begin
            for C := 0 to ColCount-1 do
            begin
                for R := RowCount-1 downto NewRowCount do
                    Objects[C, R].Free;
            end;
        end;

        Old := RowCount;
        RowCount := NewColCount;

        if NewRowCount > Old then
      begin
            for C := 0 to ColCount-1 do
            begin
                for R := Old to NewRowCount-1 do
                    Objects[C, R] := TMyCell.Create;
            end;
        end;
    end;
 end;

但是现在每当我将控件放在表单上时,rowcount 是 93... 我在哪里设置 rowCount?因为我不知道。

而且,如果我将 RowCount 从 93 增加到 100 之类的其他值,那么前 93 行存在我的对象,但不会为 93-100 行创建它们...

所以这个想法听起来很棒,但它并没有像我预期的那样工作......

有什么想法吗? 我做错了吗?

【问题讨论】:

  • 检测您何时处于设计时模式:Component Initialization - Runtime vs. Designtime.
  • 我认为您可以覆盖动态方法 SizeChanged 并根据新大小正确初始化网格。
  • 不要使用Objects[]。这是针对消费者而不是组件作者的。
  • 我试图给消费者一个准备好填充数据的组件,并让他免于创建新的类和对象。特别是因为我的共同目标将是一个特定的目的,所以消费者不需要为单元格的对象实现不同的类。但我明白你的意思
  • 这个问题现在很乱。我认为你需要回归基础。这里有很多错误。

标签: delphi


【解决方案1】:
// SizeChanged - Called when the size of the grid has changed.
protected
  procedure SizeChanged(OldColCount, OldRowCount: Longint); dynamic;

您可以重写动态方法 SizeChanged 并根据新大小初始化网格。您可以检查是否是设计时间(LU RD suggested 链接)。正如大卫所提到的,最好为组件的消费者保留 Objects 属性。改为创建并使用您自己的 TList/TObjectList。

【讨论】:

  • 所以,它不起作用,请检查我在问题中的编辑
  • “创建并使用您自己的 TList/TObjectList”是什么意思?而不是细胞的对象?我不明白这对我有什么帮助。我的组件是用于计划目的的组件(类似于甘特网格)。我想在单元格中保存信息,以便消费者在点击的单元格中拥有他需要的一切
猜你喜欢
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多