调用表单方法时访问冲突

时间:2015-07-17 07:09:51

标签: delphi delphi-2010

我有一个表格TForm1,其中我保留了cxSpreadsheet组件。我还创建了一个名为TTest的类。 TTest类包含两个用于加载数据的方法和另一个用于保存数据的方法。

当我在TTest类方法中调用TForm1类的方法时,即使创建了组件,当我调用Test.LoadMyData方法时它会给出访问冲突,它会给ATableView1变量提供访问冲突。

我做错了什么?

Uri imageUri = intent.getData();
Bitmap bitmap =     MediaStore.Images.Media.getBitmap(this.getContentResolver(),imageUri);
Imageview imgview1 = (Imageview ) findViewById (R.id.imgview1);
imgeview1.setImageBitmap(bitmap);

4 个答案:

答案 0 :(得分:3)

你陷入了混乱。 Delphi方法对隐式Self对象(实例)进行操作。也称为方法调用的目标。如果我们使用Self明确编写您的代码,那么它看起来像这样:

procedure TForm1.FormShow(Sender: TObject);
begin
  Form1 := TForm1.Create(Self);
  Self.Initilize;
  Test := TTest.Create;
  Test.LoadMyData;
end;

procedure TForm1.Initilize;
begin
  Self.ATableView1 := Self.dxSpreadSheet1.Sheets[0] as TdxSpreadSheetTableView;
end;

procedure TForm1.LoadData;
begin
  Self.ATableView1.Cells[10,1].SetText('Test Application');
end;

procedure TTest.LoadMyData;
begin
  Form1.LoadData;
end;

正如您所看到的,您对SelfForm1的引用相当混乱。请注意,使用以下代码行在.dpr文件中实例化Form1全局变量:

Application.CreateForm(TForm1, Form1);

最终会导致在FormShow上调用Form1。然后,您覆盖Form1,现在有两个TForm1个实例。您在Initilize上致电Self,然后在LoadData上致电Form1

整件事情一团糟。代码可能如下所示:

// remove global variable Test

procedure TForm1.FormShow(Sender: TObject);
var
  Test: TTest;
begin
  Initilize;
  Test := TTest.Create;
  try 
    Test.LoadMyData(Self);
  finally
    Test.Free;
  end;
end;

procedure TForm1.Initilize;
begin
  ATableView1 := dxSpreadSheet1.Sheets[0] as TdxSpreadSheetTableView;
end;

procedure TForm1.LoadData;
begin
  ATableView1.Cells[10,1].SetText('Test Application');
end;

procedure TTest.LoadMyData(Form: TForm1);
begin
  Form.LoadData;
end;

我们将表单引用作为参数传递,而不是使用全局变量。

一旦掌握了这一点,您可以考虑完全删除全局变量Form1。 IDE在假设每个表单只有一个实例的情况下创建此变量。但是没有必要这么做的理由。就个人而言,我认为通过删除这些全局变量,您将从长远来看受益。

答案 1 :(得分:3)

在你的问题中,你遗漏了一个非常重要的难题。您已经在评论中提到过它,但我在此重复一遍,因为它是您问题的直接触发因素。在评论中,您说表单创建如下:

with TForm1.Create(Self) do
begin
  try
    ShowModal;
  finally
    Free;
  end;
end;

您的问题是,在ShowModal的调用链中,您希望{em}专门为您刚刚创建的实例分配<{1}}。但显然你还没有做任何事情来设置Form1

您的解决方案&#34;是在Form1调用链中分配Form1。虽然这解决了你眼前的问题,但这远非正确,我将在后面解释原因。首先,我将展示一个完全避免问题的简单解决方案(请注意,它不是一个完整的解决方案,因为您的代码存在的问题远远超出您的意识)。

解决方案,摆脱

ShowModal

Vishal,试一试。如果你这样做,你会发现它有效。希望我现在全神贯注。你一开始并不相信,但也许你现在意识到我真的 正确理解

那我为什么要说你的解决方案&#34;错误?毕竟它似乎解决了这个问题....

  

嗯,你自己说过:你期望在//This first line is the most important. //It explicitly sets which variable must be assigned to the new form. Form1 := TForm1.Create(Self); try Form1.ShowModal; finally Form1.Free; end; 开始时分配Form1。你是对的,它应该是。通过在FormShow内分配Form1 := Self;,您只需修补之前的错误。当然,你同意修复原来的错误比仅仅修补它更好吗?

但是这里有一个更深层次的问题......我不确定你是否理解&#34;对象实例之间的区别&#34;和&#34;班级&#34;。 (如果你这样做,那么请继续阅读接下来的几段进行修订。

您似乎期望在创建FormShow时,它应自动分配给TForm1变量。好像你期望在任何时间点内存中只有一个Form1。但TForm1是一种类型;这意味着它通常定义任意数量的相同类型的对象实例的行为。每次创建TForm1时,它都是表单的新单独实例。每个实例都可以拥有自己的变量。 E.g。

TForm1

考虑一下您的错误&#34;解决方案会发生什么?#34;如果你需要2个表格变量?你会在JohnsForm1 := TForm1.Create(Self); PaulsForm1 := TForm1.Create(Self); 方法中写些什么? FormShow JohnsForm1 := Self;

当然,你仍然可以选择,一次只在内存中保留一个PaulsForm1 := Self;个实例。但是Delphi没有办法自动知道你的意图。所以你仍然应该如上所述明确地做任何所需的任务。

我提到你的代码还有更严重的问题。它与上面关于对象实例和类类型的讨论有关。

你的TForm1课程做了一系列不必要的假设:

  • 假设只有TTest的一个实例。
  • 假设表格在需要时始终可用。
  • 并假设表单将分配给TForm1变量。

同样,如果您需要Form1JohnsForm1,您的代码将无法正常使用。

PaulsForm1TTest.LoadMyData的微小变化解决了这些问题。

TForm1.FormShow

为了记录,David已经在his answer中向您提供了此信息。他的回答也证明了对新//Write LoadMyData so it can be told which form instance to load the data into procedure TTest.LoadMyData(ALoadForm: TForm1); begin ALoadForm.LoadData; end; //Change FormShow to tell Test which form to use in LoadMyData procedure TForm1.FormShow(Sender: TObject); begin Initilize; Test := TTest.Create; Test.LoadMyData(Self); end; 实例的适当资源保护,而我为了简单起见将其排除在外。

  

顺便说一句,这两个小小的改变也可以解决你的问题   基本上,您的代码中有2个错误。两个错误的结合导致了你的问题   您可以修复其中任何一个以解决问题。但你应该解决这两个问题,以使你的代码更好。

答案 2 :(得分:0)

大卫如此雄辩地说,这是你创造的混乱。他说,IDE在项目文件中插入一行自动为您创建表单是正确的。因此,自己创建它是多余的。

在这个实例中,OnShow处理程序可能是向网格添加一些测试数据的正确位置,但我不打算使用TTest类来执行此操作。也就是说,首先让逻辑工作,然后根据需要将这些东西移到另一个类中。我建议这是因为你似乎没有很好地掌握如何做OOD。我们一次都在那里!首先简化事情。

我为CodeRage 9制作了一个你可能感兴趣的视频。它被称为“你最近拥抱过你的内部软件管道工吗?”在YouTube上搜索它。它会让你对这个一般主题(可能太多)有所了解。

答案 3 :(得分:-10)

type
  TForm1 = class(TForm)
    dxSpreadSheet1: TdxSpreadSheet;
    procedure FormShow(Sender: TObject);
  public
    ATableView1 : TdxSpreadSheetTableView;
    procedure Initilize;
    procedure LoadData;
  end;

  TTest = class
  public
    procedure SaveMyData(MyValue : String);
    procedure LoadMyData;
  end;

var
  Form1: TForm1;
  Test: TTest;

implementation

{$R *.dfm}

procedure TForm1.FormShow(Sender: TObject);
begin
  //Form1 is nil, if I check before executing below statement.
  Form1 := Self; //This statement make my code work. mmmhhhhhaaaa Love This Statement.

  Initilize;
  Test := TTest.Create;
  Test.LoadMyData;
end;