真诚要请你来指正我程序不足之处,提出有效建议者,20分赠送,全部分数,送完为止!!!!!!(20分)

  • 主题发起人 主题发起人 zhaokaien
  • 开始时间 开始时间
Z

zhaokaien

Unregistered / Unconfirmed
GUEST, unregistred user!
软件编写的背景是,电台的频率接受机需要实现在某个时间段接受一个频率定值,这个定值的误差在+5(可调),如果超过该范围,就会导致电台停播,这对于电台来讲是重大事故,所以必须对频率值进行监控,并对出错情况进行相应的处理。

我编写的这个软件针对需求主要分三个模块:
(1)从gps获得相关数据,如精确到秒的时间值
(2)提供界面让工作人员可以随时将预定时间段的预设值写入数据库;监控接受机端口接收到的频率值,并扫描数据库,然后将频率值与从数据库中读取的预设值进行比对,如果超过误差范围,进行报警。
(3)向数据库中写入相关错误信息供工作人员查看。

软件整体使用了多线程,从Tthread派生了三个类,比对报警线程类,读GPS线程类,写错误日志线程类,
相关代码都在前面的程序单元里,里面也有相关构造函数参数的相关注释

对您的审阅表示感谢,如能得到你的指点,将不胜荣幸!

unit Unitthread;
interface
uses
Windows,Classes,Graphics,MSCommLib_TLB,DB,ADODB,NeoNumLED,dateutils,SysUtils,
syncobjs,StdCtrls,dialogs,ExtCtrls,MMSystem;
//引入Mscomm控件的时候,Mscommlib_tlb不能少
//使用showmessage函数的时候,dialogs不能少
//使用数据库控件时,DB,ADODB不能少
//使用日期函数如DecodeDateTime时,dateutils不能少
//使用now函数时,sysutils不能少
//使用criticalsection时syncobjs不能少
//使用Tedit时,StdCtrls不能少
//使用Tshape时,ExtCtrls不能少
//使用Tshape的颜色值时,Graphics不能少
type
TScanThread = class(TThread)
{************派生线程扫描接收机*************}
private
Rnum:string;
shape:Tshape;
table:string;
NeonumledR,NeonumledD,NeonumledC:TNeonumled;
portnumR,portnumG:integer;
commR:TMSComm;
query:TADOQuery;
procedure ScanDataR ;
//扫描接收机
procedure ScanDataD;
//扫描数据库
procedure comparedata;
//比较
protected
procedure Execute;
override;
public
//扫描接受机线程的构造函数
constructor create( createsuspend:boolean;
//create flag
AcommR:TMSComm;
//接收机端口控件
Aquery:TAdoquery;
//扫描数据库预设值
ANeonumledR:TNeonumled;
//显示预设值
ANeonumledC:TNeonumled;
//显示频率差
ANeonumledD:TNeonumled;
//显示实际频率
Atable:string;
//预设值所在数据库
AportnumR:integer;
//接收机端口号
Ashape:Tshape;
//报警信号标志
ARnum:string //接收机号
);
overload;
end;

//errnum=(y = 1,e = 2,s = 3,ss = 4,w = 5,l = 6,q = 7,b = 8);
implementation
uses
unitmain;
var
//flag:array of boolean;
//criticalsection,criticalsection1:Tcriticalsection;
facttime,errfre,yushefre:string;
errnum:string;
weekflag:word;
i:integer;
n:integer;

constructor TScanThread.create(createsuspend:boolean;
AcommR:TMSComm;
Aquery:TAdoquery;
ANeonumledR:TNeonumled;
ANeonumledC:TNeonumled;
ANeonumledD:TNeonumled;
Atable:string;
AportnumR:integer;
Ashape:Tshape;
ARnum:string);
{********************扫描接受机端口的线程的构造函数*******************************}
begin
create(createsuspend);
Rnum:=ARnum;
shape:=Ashape;
commR:=AcommR;
query:=Aquery;
NeonumledR:=ANeonumledR;
NeonumledC:=ANeonumledC;
NeonumledD:=ANeonumledD;
table:=Atable;
portnumR:=AportnumR;
freeOnTerminate:=true;
end;

procedure TScanThread.Execute;
{********************扫描接受机端口的线程的执行函数****************************}
begin
while truedo
begin
try
//criticalsection.Enter;
synchronize(scandataD);
synchronize(scandataR);
synchronize(comparedata);
sleep(500);
// criticalsection.Leave;
except
showmessage('接收机错误');
exit;
end;
//try
end;
//while
end;
//procedure

procedure TScanThread.ScanDataR;
{********************扫描接收机端口频率值**************************************}
var
Rdata:olevariant;
Rstr:string;
begin
{扫描接收机}
commR.CommPort:=portnumR;
commR.InBufferSize:=1024;
commR.OutBufferSize:=512;
commR.InBufferCount:=0;
commR.OutBufferCount:=0;
commR.Settings:='9600,n,8,1';
commR.RThreshold:=128;
commR.InputLen:=0;
if commR.CommEvent=comEvReceive then
begin
try
Rdata:=commR.Input;
Rstr:=Rdata;
//接受接收机端口数据,这里还要添加相应的处理数据的程序
NeonumledR.Text:=Rstr;
errfre:=Rstr;

if Rdata='' then
begin
showmessage('端口无数据');
abort;
end;

except
showmessage('数据接受失败!');
abort;
end;
//try
end
else
begin
NeonumledR.Text:='0';
errfre:='0';
end;
//if
end;
//procedure

procedure TScanThread.ScanDataD;
{********************扫描数据库预设值******************************************}
begin
{扫描数据库}
query.SQL.Clear;
query.SQL.text:='select * from '+ table+' where (:settime between开始时间 and 结束时间) and(发射机号='+''''+Rnum+''''+')';
if facttime<>'' then
begin
{拿当前时间和数据库中预设时间段进行比较}
query.Parameters.ParamByName('settime').Value:=strtodatetime(facttime);
end
else
begin
showmessage('无时间值');
abort;
//terminate,exit,abort中,经过试验得出的结论是,abort能
//退出到程序(暂时不执行线程)外,效果最强
end;

query.open;
if query.Fields.Fields[weekflag].Value=true then
begin

if query.Fields.Fields[1].asstring<>'' then
//数据库里的预设频率值是否为零
begin
NeonumledD.Text:=query.Fields.Fields[1].asstring;
yushefre:=query.Fields.Fields[1].asstring;
end
else
begin
NeonumledD.Text:='0';
end;

end
else
begin

if query.Fields.Fields[weekflag].Value=false then
{判断星期的标志}
begin

if query.Fields.Fields[1].asstring<>'' then
begin
NeonumledD.Text:='0';
NeonumledR.Text:='0';
NeonumledC.Text:='0';
end;

end
else
//如果星期为nil值,即没有符合扫描条件数据值时
begin
NeonumledD.Text:='0';
end;

end;
//以上的逻辑是:如果星期标志设置,那么看扫到纪录的预设频率值相,若频率值非空,此值为预设频率值
end;
//procedure

procedure TScanThread.comparedata;
{********************比较预设值与实际值,并进行相应处理*************************}
var
soundstr:string;
soundnum:string;
begin
i:=strtoint(NeonumledD.Text)-strtoint(NeonumledR.Text);
//数据库预设置-实际频率值
NeonumledC.Text:=inttostr(i);
if i>5 then
//如果频率差大于5 ,进行相应的处理
begin
shape.Brush.Color:=clRed;
errnum:=rnum;//保存错误接收机号 ,rnum是从构造函数赋值的
if errnum='一号机' then
begin
soundnum:='1.wav';
end
else

if errnum='二号机' then
begin
soundnum:='2.wav';
end
else

if errnum='三号机' then
begin
soundnum:='3.wav';
end
else

if errnum='四号机' then
begin
soundnum:='4.wav';
end
else

if errnum= '五号机' then
begin
soundnum:='5.wav';
end
else

if errnum='六号机' then
begin
soundnum:='6.wav';
end
else

if errnum='七号机' then
begin
soundnum:='7.wav';
end
else

if errnum='八号机' then
begin
soundnum:='8.wav';
end
else

begin
showmessage('找不到声音文件');
exit;
end;

{if errnum='一号机' then
begin
flag[0]:=true;
end
else
if errnum='二号机' then
begin
flag[1]:=true;
end
else
if errnum='三号机' then
begin
flag[2]:=true;
end
else
if errnum='四号机' then
begin
flag[3]:=true;
end
else
if errnum='五号机' then
begin
flag[4]:=true;
end
else
if errnum='六号机' then
begin
flag[5]:=true;
end
else
if errnum='七号机' then
begin
flag[6]:=true;
end
else
if errnum='八号机' then
begin
flag[7]:=true;
end
else
begin
for n:=0 to 7do
begin
flag[n]:=false;
end;
//for
end;
}
try
if query.Fields.Fields[11].asstring<>''then
begin

if fileexists(query.Fields.Fields[11].asstring) then
begin
soundstr:=query.Fields.Fields[11].asstring;
end
else
begin
soundstr:=extractfilepath(paramstr(0))+'/res/'+ soundnum;
end;

mciexecute(pchar('play '+soundstr));
{播放报警声音}
//注意这里不能使用playsound或者snplaysound,不然这里的播放效率会非常低
//而且有可能 造成死机
//PlaySound(Pansichar('1wave'),hinstance ,SND_RESOURCE orSND_NODEFAULT);
//记住上面使用wave类型资源文件的方法
//abort;
end
else
begin
exit;
end;
except
abort;
end;
//end try
end
else
begin
shape.Brush.Color:=clLime;
end;
//end if i>5
end;
//procedure
initialization
//criticalsection:=Tcriticalsection.Create;
end.



unit UnitthreadE;
interface
uses
Windows,Classes,Graphics,MSCommLib_TLB,DB,ADODB,NeoNumLED,dateutils,SysUtils,
syncobjs,StdCtrls,dialogs,ExtCtrls,MMSystem;
//引入Mscomm控件的时候,Mscommlib_tlb不能少
//使用showmessage函数的时候,dialogs不能少
//使用数据库控件时,DB,ADODB不能少
//使用日期函数如DecodeDateTime时,dateutils不能少
//使用now函数时,sysutils不能少
//使用criticalsection时syncobjs不能少
//使用Tedit时,StdCtrls不能少
//使用Tshape时,ExtCtrls不能少
//使用Tshape的颜色值时,Graphics不能少
type

TScanThreadE=class(TThread)
{************派生线程写错误日志*************}
private
queryerr:TADOQuery;
procedure writeerr;
protected
procedure Execute;
override;
public
//写错误日志线程的构造函数
constructor create( createsuspend:boolean;
Aqueryerr:TAdoquery //向数据库写入错误日志
);
overload;
end;

//errnum=(y = 1,e = 2,s = 3,ss = 4,w = 5,l = 6,q = 7,b = 8);
implementation
uses
unitmain,unitthreadR,unitthreadG;
var
//flag:array of boolean;
//criticalsection,criticalsection1:Tcriticalsection;
facttime,errfre,yushefre:string;
errnum:string;
weekflag:word;
i:integer;
n:integer;

constructor TScanThreadE.create(createsuspend:boolean;
Aqueryerr:TAdoquery);
{********************写错误日志的线程的构造函数********************************}
begin
queryerr:=Aqueryerr;
create(createsuspend);
freeOnTerminate:=true;
Priority:=tpnormal;
end;

procedure TScanThreadE.Execute;
{********************写错误日志的线程的执行函数********************************}
begin
while truedo
begin
try
synchronize(writeerr);
sleep(500);
except
showmessage('写入日志错误');
exit;
end;
//try
end;
//while
end;
//procedure

procedure TScanThreadE.writeerr;
{********************写错误日志************************************************}
begin
if (i>5) then
//如果频率差大于5,写日志
begin
queryerr.SQL.Clear;
queryerr.SQL.Text:='insert into errlogo values(:errtime,:reiceivenum,:yushefre,:errfre,:memo)';
queryerr.Parameters.ParamByName('reiceivenum').Value:=errnum;
queryerr.Parameters.ParamByName('errtime').Value:=strtodatetime(facttime);
queryerr.Parameters.ParamByName('yushefre').Value:=yushefre;
queryerr.Parameters.ParamByName('errfre').Value:=errfre;
if strtoint(errfre)=0 then
begin
queryerr.Parameters.ParamByName('memo').Value:='接收机无接收数据';
end
else
begin
queryerr.Parameters.ParamByName('memo').Value:='频率值不正确';
end;

queryerr.ExecSQL;
queryerr.Close;
end;
//if first
end;
//procedure

initialization
//criticalsection:=Tcriticalsection.Create;
end.


unit UnitthreadG;
interface
uses
Windows,Classes,Graphics,MSCommLib_TLB,DB,ADODB,NeoNumLED,dateutils,SysUtils,
syncobjs,StdCtrls,dialogs,ExtCtrls,MMSystem;
//引入Mscomm控件的时候,Mscommlib_tlb不能少
//使用showmessage函数的时候,dialogs不能少
//使用数据库控件时,DB,ADODB不能少
//使用日期函数如DecodeDateTime时,dateutils不能少
//使用now函数时,sysutils不能少
//使用criticalsection时syncobjs不能少
//使用Tedit时,StdCtrls不能少
//使用Tshape时,ExtCtrls不能少
//使用Tshape的颜色值时,Graphics不能少
type

TScanthreadG=class(TThread)
{************派生线程扫描GPS*************}
private
NeonumledG:TNeonumled;
commG:TMSComm;
portnumG : integer;
procedure ScanDataG;
protected
procedure Execute;override;
public
//扫描GPS线程的构造函数
constructor create( createsuspend:boolean;
AcommG:TMSComm;
//GPS端口控件
ANeonumledG:TNeonumled;
//显示GPS时间
AportnumG:integer //GPS端口号
);
overload;
end;

//errnum=(y = 1,e = 2,s = 3,ss = 4,w = 5,l = 6,q = 7,b = 8);
implementation
uses
unitmain,unitthreadR,unitthreadE;
var
//flag:array of boolean;
//criticalsection,criticalsection1:Tcriticalsection;
facttime,errfre,yushefre:string;
errnum:string;
weekflag:word;
i:integer;
n:integer;

constructor TScanThreadG.create(createsuspend:boolean;
AcommG:TMSComm;
ANeonumledG:TNeonumled;
AportnumG:integer);
{********************扫描GPS端口的线程的构造函数*******************************}
begin
NeonumledG:=ANeonumledG;
portnumG:=AportnumG ;
commG:=AcommG;
create(createsuspend);
freeOnTerminate:=true;
Priority:=tptimecritical;
end;

procedure TScanThreadG.Execute;
{********************扫描GPS端口的线程的执行函数*******************************}
begin
//criticalsection1.Enter;
while truedo
begin
try
synchronize(scandataG);
sleep(200);
except
showmessage('GPS err!');
eixt;
end;
//try
end;
//while
//criticalsection1.Leave;
end;
//procedure

procedure TScanThreadG.ScanDataG ;
{********************扫描GPS端口时间值*****************************************}
var
Gdata:olevariant;
Gstr:string;
y,m,d,h,min,sec,milisec,weekofyear,dayofweek:WORD;
years,mons,days,hours,minutes,seconds,miliseconds,weeks:string;
begin
{扫描GPS}
commG.CommPort:=portnumG;
commG.InBufferSize:=1024;
commG.OutBufferSize:=512;
commG.InBufferCount:=0;
commG.OutBufferCount:=0;
commG.Settings:='9600,n,8,1';
commG.RThreshold:=128;
commG.InputLen:=0;
if commG.InBufferCount<>0 then
begin
{取GPS时间}
if commG.CommEvent=comEvReceive then
begin
try
Gdata:=commG.Input;
Gstr:=Gdata;
if Gdata='' then
begin
showmessage('GPS端口无数据!');
end;

except
showmessage('GPS数据接收失败!');
abort;
end;
//try
end;

NeonumledG.Text:=Gstr;
facttime:=Gstr;
end
else
begin
try
{取系统时间}
Decodedatetime(now,y,m,d,h,min,sec,milisec);
Decodedateweek(now,y,weekofyear,dayofweek);
weekflag:=dayofweek+3;
case dayofweek of
1:
weeks:='星期一';
2:
weeks:='星期二';
3:
weeks:='星期三';
4:
weeks:='星期四';
5:
weeks:='星期五';
6:
weeks:='星期六';
7:
weeks:='星期天';
end;

years:=inttostr(y);
mons:=inttostr(m);
days:=inttostr(d);
hours:=inttostr(h);
minutes:=inttostr(min);
seconds:=inttostr(sec);
miliseconds:=inttostr(milisec);
NeonumledG.Text:=years+'-'+mons+'-'+days+' '+hours+':'+minutes+':'+seconds;
facttime:=years+'-'+mons+'-'+days+' '+hours+':'+minutes+':'+seconds;
except
showmessage(' 系统时间获取失败');
exit;
end;
//try
end;
//if
end;
//procedure
initialization
//criticalsection:=Tcriticalsection.Create;
end.
 
大家可以随便拍砖,无论怎样批评,我都将不胜荣幸,如果能够提出能够使本程序得到重大改进建议者,我将倾我所有酬谢!!
 
审阅完毕,不知所云。
 
首先希望得到大家关于程序本身结构问题的意见,
以上是我程序里线程的三个单元
我一直觉得线程构造函数参数太多了,不知道有没有大侠能帮忙解决一下
 
代码无法测试,所以就正确性来说不得而知。仅从编程风格来说比较中庸,基本是顺着思路一路写下来,建议重构。对于线程构造函数参数太多的问题的确是这样,建议仿照VCL写个CustomXXX Class在从这个Class inherited暴露一些必要的接口,其实三个Thread有一些共同的方法和属性,不过是功能不同罢了。建议写Interface在进一步用Thread来实现,这样有比较统一完善的调度过程。呵呵,代码没细看,不足之处请批评指正
 
非常感谢Rainstorey,kinneng给的点评,
由于我水平有限,所以一直不能有所改进,
Rainstorey给我提供很好的改进建议,尤其是使用接口技术,非常的感谢,
衷心希望各位高手继续给小弟拍砖,不胜感激,小分一点聊表谢意!!
 
多人接受答案了。
 

Similar threads

后退
顶部