我正在使用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实例。如果这样做,那么它将不是与主程序实例相同的实例。如果是这种情况,那么当您需要访问其字段或公共变量时,您将不得不一直创建新的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;
我想在线程中使用所有变量,它们恰好位于mainform公共区域内。
由于
答案 0 :(得分:1)
将您的主题所需的内容作为参数传递给其构造函数。将对这些对象的引用存储为线程类中的字段。在线程运行时使用它们。
并且不要让你的线程类成为主窗体的后代。这是没有意义的。如果您的线程需要访问整个表单,则将MainForm
引用传递给线程的构造函数。但是,如果您的所有线程需求都是串行端口对象,那么只需传递它,而不是整个表单。
不要创建MainForm
的其他实例。这将创造更多的形式;它不会让您访问真实主表单的字段值。
答案 1 :(得分:1)
您的线程过程(class procedure mythread; static;
)似乎是“静态”或“类”,而您要访问的字段是MainForm 实例的常规字段。这不起作用,因为只有一个procedure mythread
,但可能有多个MainForm
个实例。虽然在实践中可能只有一个MainForm
实例,编译器不知道。
您应首先从该过程中删除class
前缀和static
sufix,以使其成为可以读取实例字段的常规实例过程。即使这还不够,因为你从你的MainForm 派生,我假设你创建了一个ThreadCom
的新实例并启动线程:一旦你使方法成为常规实例方法代码将编译,但结果不会是您期望的结果,因为您将访问不同的 MainForm实例的成员。
解决方案:
mythread
程序成为MainForm
的实例方法。它将获得对所有必填字段的访问权限并从适当的实例访问它们!MainForm
,在构造函数中传递MainForm
的实例,通过线程过程传递它。您(再次)需要避免使用静态/类字段和过程,因为这些字段和过程无法链接到一个 MainForm实例。