0

我正在使用 Delphi Prism 为 Mono 编写和构建我的软件。所以,我决定我的串行通信将由一个线程处理。由于除非您为项目启用全局变量选项,否则严格不允许使用全局变量,因此我决定遵循 Delphi Prism 约定。那么,如何传递或使公共变量或字段可供线程访问?

这是我的测试主窗体代码:

MainForm = partial class(System.Windows.Forms.Form)

  private
    method SignalBtn_Click(sender: System.Object; e: System.EventArgs);
    method CommBtn_Click(sender: System.Object; e: System.EventArgs);
    method button1_Click(sender: System.Object; e: System.EventArgs);
    method button2_Click(sender: System.Object; e: System.EventArgs);
    method button4_Click(sender: System.Object; e: System.EventArgs);
    method button5_Click(sender: System.Object; e: System.EventArgs);
    method MainForm_Load(sender: System.Object; e: System.EventArgs); 
    method ShutdownBtn_Click(sender: System.Object; e: System.EventArgs);
    method MySerialData(sender: System.Object; e:SerialDataReceivedEventArgs);
    method LoginBtn_Click(sender: System.Object; e: System.EventArgs);
  protected
    method Dispose(disposing: Boolean); override;
  public
    RX:Array[0..5] of byte;
    TX:Array[0..6] of byte;
    serialPort1:System.IO.Ports.SerialPort;
    thr:Thread;
    stoploop:Boolean;
    mcommand:Byte;
    thechannel:Integer;
    constructor;
    method FillTable;
  end;

这是串行通信的线程:

  ThreadComm = class(MainForm)
  public
    class procedure mythread; static;
  end;

以下是 ThreadComm 的运行方式:

class procedure ThreadComm.mythread;
begin
    while true do
    begin
        TX[0]:=$FF;
        TX[1]:=$01;
        TX[2]:=$01;
        TX[3]:=$04;
        TX[4]:=$A2;
        TX[5]:=(TX[2] xor TX[3] xor TX[4]);

        SerialPort1.Write(TX,0,6);
        while SerialPort1.BytesToWrite>0 do;
        Thread.Sleep(100);

        if (stoploop) then
            break;
    end;
end;

每次我编译代码时,它都会引发 30 条左右类似的错误消息,说明如下:

没有实例引用就无法调用实例成员“SerialPort1”

我知道错误的含义,但解决它的唯一方法是创建主窗体的实例。如果你这样做,那么它将与主程序的实例不同。如果是这种情况,那么当您需要访问它的字段或公共变量时,您将不得不一直创建新的 mainform 实例。正确的?

class method Program.Main(args: array of string);
begin
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  Application.ThreadException += OnThreadException;
  **using lMainForm := new MainForm do
    Application.Run(lMainForm);**
end;

我想使用所有这些变量都在线程中,并且它们恰好在主窗体公共区域内。

谢谢

4

2 回答 2

1

您的线程过程 ( class procedure mythread; static;) 似乎是“静态”或“类”,而您要访问的字段是 MainForm实例的常规字段。那是行不通的,因为只有一个procedure mythread,但可能有多个MainForm. 虽然在实践中可能只有一个 的实例MainForm,但编译器并不知道这一点。

您应该首先从该过程中删除class前缀和static后缀,使其成为可以读取实例字段的常规实例过程。即使这还不够,因为您从 MainForm派生,并且我假设您创建了一个新实例ThreadCom并启动线程:一旦您将该方法设为常规实例方法,代码将编译,但结果不会成为您期望的那个,因为您将访问MainForm不同实例的成员。

解决方案:

  • 使该mythread过程成为您的MainForm. 它将获得对所有必填字段的访问权限,并从适当的实例中访问它们!
  • 按照 Rob 的建议:创建一个新类,而不是从 派生的MainForm,在构造函数中传递一个实例MainForm,你来自线程过程。您将(再次)需要避免使用静态/类字段和过程,因为它们不能链接到MainForm 的一个实例。
于 2011-07-12T13:52:12.933 回答
1

将你的线程需要的东西作为参数传递给它的构造函数。将对这些对象的引用存储为线程类中的字段。在线程运行时使用它们。

并且不要让你的线程类成为你的主窗体的后代。这是没有意义的。如果您的线程需要访问整个表单,则将MainForm引用传递给线程的构造函数。但是,如果您的线程需要的只是一个串行端口对象,那么只需传递它,而不是整个表单。

不要创建MainForm. 这将创造更多的形式;它不会让您访问真正的主表单的字段值。

于 2011-07-12T13:39:24.433 回答