ผู้เขียนได้มีโอกาสใช้ Thread Object อยู่บ่อยครั้ง เนื่องจากต้องการที่จะลดภาระของ Process บางอย่างของ Server และทำให้เป็น User Friendly มากขึ้นเพราะโปรแกรมจะไม่ต้องหยุดรอ ก็เปรียบได้กับการใช้ Ajax บนเว็บ
ผู้เขียนจะทดสอบสร้าง Thread Object 2 แบบด้วยกันโดยใช้ Delphi Version 7
- แบบแรกคือการสร้าง Thread Class โดยแยกออกมาจากไฟล์ Unit อื่นๆ
- แบบที่สองคือการใส่ Thread Class แทรกไปที่ใดๆของ Unit ที่มีอยู่แล้ว
ผู้เขียนทดสอบเรียกข้อมูลบาง Field ของ Table Employee มาแสดง
ข้อมูลพนักงานเลือกใช้ 6 Field |
การสร้าง Thread Object ทำได้โดยเข้าไปที่เมนู File > New > Other
จะปรากฎ Dialog New item ให้เลือก Thread Object ที่อยู่ภายใน Tab New แล้วกด OK
โปรแกรมจะถามถึงชื่อ Thread Class ที่ต้องการสร้างขึ้น พร้อมกับชื่อของ Thread โดยชื่อของ Thread จะตั้งหรือไม่ก็ได้ โดยหาก Thread ไม่มีชื่อก็ใช้การอ้างอิงเป็น Thread id ก็ได้
หลังจากนั้นจะได้ ไฟล์ Unit ของ Thread Class ที่จะกอบด้วย Class และ Interface ของ Class รอให้นำไป Implement ต่อได้
TthdEmployee = class(TThread) //คลาสที่สืบทอดมาจาก TThread ที่อยู่ใน Libraly Classes
private
procedure SetName;
protected
procedure Execute; override;
end;
method ที่ได้สร้างมาให้แล้วคือ SetName ซึ่งมีหน้าที่กำหนด Thread info เมื่อมีการทำงานของ Thread ส่วน method Execute นั้นเป็น abstract method ที่ได้รับมาจากการสืบทอดมาจาก TThread เพื่อให้ implement ต่อ method Execute นี้สำคัญมาก เพราะ Thread จะใช้ method นี้ในการทำงาน
เมื่อผู้เขียนจะใช้งาน Thread ร่วมกับ DataSet และ ListBox ที่อยู่บนฟอร์ũ7; จึงจำเป็นต้องให้ Thread Class $26;ามารถใช้งาน DataSet ที่อยู่ภายนอก Class ได้ โดยผู้เขียนจะทำการ Hiding Constructor ของ Thread Class ตามนี้
TthdEmployee = class(TThread)
private
procedure SetName;
protected
procedure Execute; override;
public //เพิ่มส่วนของ Encapsulation สาธารณะ
employeeDataSource: TDataSource; //ประกาศ Instance DataSource ที่รับมาจากภายนอก
employeeList: TListBox; //ประกาศ Instance ListBox ที่รับมาจากภายนอก
// ประกาศ Interface เป็น Hiding Constructor
constructor Create(DS:TDataSource;listBox: TListBox);
end;
จากนั้นก็เป็นส่วนของตัว method ที่ผู้เขียนจะทำการ Hiding เพื่อเพิ่มประสิทธิภาพของ Constructor เดิม
constructor TthdEmployee.Create(DS:TDataSource;listBox: TListBox);
begin
inherited Create(false); //อ้างใช้ Constructor เดิมของ TThread
//อ้างอิง DataSource ที่รับมาจากภายนอกให้กับ Instance ที่ประกาศไว้
Self.employeeDataSource:=DS;
// อ้างอิง ListBox ที่รับมาจากภายนอกให้กับ Instance ที่ประกาศไว้
Self.employeeList:=listBox;
end;
ต่อมาก็คือส่วนของกระบวนการทำงานของ Thread คือ method Execute คำสั่งที่อยู่ภายใน method หมายถึงระยะเวลาของ Thread ด้วย
ในตัวอย่างผู้เขียนจะทำการวนลูป นำข้อมูลที่อยู่ภายใน DataSet ผ่าน DataSource ที่รับเข้ามา เพื่อนำไปใส่ใน ListBox
procedure TthdEmployee.Execute;
Var
itemText: String;
begin
SetName; //เซ็ตค่า Thread info
with Self.employeeDataSource.DataSet do
Begin
//ให้ curser อยู่ที่ตำแหน่งข้อมูลแถวแรกก่อน
First;
//ล้างค่าของ ListBox
Self.employeeList.Clear;
//วนลูปข้อมูลทั้งหมดที่มีอยู่ใน DataSet
while not Eof do
Begin
itemText:='รหัสพนักงาน '+FieldByName('EMP_COD').AsString;
itemText:=itemText + ' ชื่อ '+ FieldByName('EMP_NAM1').AsString + FieldByName('EMP_NAM2').AsString;
itemText:=itemText + ' นามสกุล '+ FieldByName('EMP_NAM3').AsString;
//แปลงค่า M หรือ F ของเพศเป็นข้อความ
if Trim(FieldByName('EMP_SEX').AsString)='M' then
itemText:=itemText + 'เป็น ผู้ชาย '
else
itemText:=itemText + 'เป็น ผู้หญิง ';
//เมื่อได้ข้อความทั้งหมดแล้วให้ใส่เข้าใน ListBox
Self.employeeList.Items.Add(itemText);
//เลื่อนไปแถวถัดไป
Next;
end;
end;
end;
ตอนนี้ Thread Class พร้อมที่จะทำงานแล้ว
หมายเหตุ
ไฟล์ของ Thread Class ที่สร้างขึ้นจำเป็นต้อง uses Libraly ของ Delphi เข้ามาให้ครบด้วย
uses
Classes {$IFDEF MSWINDOWS} , Windows {$ENDIF},DB,StdCtrls,SysUtils;
ผู้เขียนจะเรียกใช้งานจากฟอร์ม โดยเรียกที่ Event FormShow()
uses Unit2; //uses ไฟล์ของ Thread Class เข้ามา
procedure TForm1.FormShow(Sender: TObject);
begin
//เมื่อเรียกใช้ Constructor ของ Thread ก็จะเริ่มทำงานทันที จนจบการทำงานของ method Execute
TthdEmployee.Create(Self.DataSource1,Self.ListBox1);
end;
ทดสอบโดยรันโปรแกรมจะได้ผลตามที่ Thread ทำงาน
Source Code ทั้งหมด
ไฟล์ Unit1.pas หรือ Form1
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
ADOTable1: TADOTable;
DataSource1: TDataSource;
ADOTable1EMP_COD: TStringField;
ADOTable1EMP_NAM1: TStringField;
ADOTable1EMP_NAM2: TStringField;
ADOTable1EMP_NAM3: TStringField;
ADOTable1EMP_SEX: TStringField;
ADOTable1EMP_BRTH: TDateTimeField;
ListBox1: TListBox;
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin
TthdEmployee.Create(Self.DataSource1,Self.ListBox1);
end;
Unit2.pas ไฟล์ Unit ของ Thread
unit Unit2;
interface
uses
Classes {$IFDEF MSWINDOWS} , Windows {$ENDIF},DB,StdCtrls,SysUtils;
type
TthdEmployee = class(TThread)
private
procedure SetName;
protected
procedure Execute; override;
public
employeeDataSource: TDataSource;
employeeList: TListBox;
constructor Create(DS:TDataSource;listBox: TListBox);
end;
implementation
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TthdEmployee.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{$IFDEF MSWINDOWS}
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;{$ENDIF}
{ TthdEmployee }
procedure TthdEmployee.SetName;{$IFDEF MSWINDOWS}
var
ThreadNameInfo: TThreadNameInfo;{$ENDIF}
begin
{$IFDEF MSWINDOWS}
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'thdEmployee';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), @ThreadNameInfo );
except
end;
{$ENDIF}
end;
procedure TthdEmployee.Execute;
Var
itemText: String;
begin
SetName;
with Self.employeeDataSource.DataSet do
Begin
First;
Self.employeeList.Clear;
while not Eof do
Begin
itemText:=' รหัสพนักงาน '+FieldByName('EMP_COD').AsString;
itemText:=itemText + ' ชื่อ '+ FieldByName('EMP_NAM1').AsString + FieldByName('EMP_NAM2').AsString;
itemText:=itemText + ' นามสกุล '+ FieldByName('EMP_NAM3').AsString;
if Trim(FieldByName('EMP_SEX').AsString)='M' then
itemText:=itemText + ' เป็น ผู้ชาย '
else
itemText:=itemText + ' เป็น ผู้หญิง ';
Self.employeeList.Items.Add(itemText);
Next;
end;
end;
end;
constructor TthdEmployee.Create(DS:TDataSource;listBox: TListBox);
begin
inherited Create(false);
Self.employeeDataSource:=DS;
Self.employeeList:=listBox;
end;
end.
อยากให้เขียนตัวอย่าง ใช้ thread ในdelphi 7 แบบแทรกใน unit เดียวกับฟอร์ม อ่านข้อมูลจากฐานข้อมูลมาใส่ใน combobox ครับ (ปกติที่ผมใช้อยู่ใช้ Tquery อ่านมาใส่ commbobox บางทีข้อมูลเยอะ ๆ จะกระตุกนิด ๆ ครับ)
ตอบลบขอบคุณครับ