Showing posts with label Delphi. Show all posts
Showing posts with label Delphi. Show all posts

Apr 15, 2009

毕业设计(新增加密解密工具)




1:配置文件里新增了加密的相关配置信息。主要就是两个,一个是加密的关键字符串key,另外一个是一个0~1之间的小数(最好只到小数点后两位)。它们共同构成了加密的算法。算法是我从网上搜刮来的,我改了一下。原先我将算法直接用来加密memo里的所有内容,结果发现会发生一些小概率的加密未完成便中止的现象。后来我把它改成逐行读取逐行加密就没有问题了。这个BUG真的很奇怪,我已经发给老大了,希望他有时间帮我看一下。我数学不行啊。哎~~~~~



2:该图是输入明文后的效果。这个加密工具可以独立使用也可以嵌入到任何一个工具里。只要包含了加密工具的单元,调用它的一个hasIniOriginalText或者hasIniDecodedText将其设置为true,就可以讲你要加密的内容从你的工具里导入到加密工具的明文或密文输入栏了。


3:上图为加密后的脚本内容,看不懂吧,呵呵。这个密文可以放到明文显示栏里再加密,每次加密可以更换不同的key和percent,只要记住顺序,一次次的用正确的key和percent解密就行了,很方便很强大吧。。。真是要感谢贴了这个加密算法的蝈蝈。之前上网搜了,论坛问了,有人让我用MD5加密,这个加密虽然破解还是有一定难度,可是解密也很麻烦的。当然,我对MD5甚至对密码学根本是门外汉,上述完全是凭直觉哈。

下边贴出我稍微改动后的加密算法代码:

var
frmCryptograph: TfrmCryptograph;

key: string;
percent1: Double;

implementation

{$R *.dfm}

function TfrmCryptograph.DeCode(aCryptograph, aKey: string): string;
var
i,keylen,codelen:integer;
begin
keylen :=Length(akey);
codelen:=Length(aCryptograph);
SetLength(Result, Length(aCryptograph));
for i:=1 to codelen do
begin
Result[i]:=Chr(Ord(aCryptograph[i])-Ord(aKey[(i mod KeyLen)+1]));
end;
end;


function TfrmCryptograph.EnCode(aCryptograph, aKey: string): string;
var
i,keylen,codelen:integer;
begin
keylen:=Length(akey);
codelen:=Length(aCryptograph);
SetLength(Result, Length(aCryptograph));
for i:=1 to codelen do
begin
Result[i]:=Chr(Ord(aCryptograph[i])+Ord(aKey[(i mod KeyLen)+1]));
end;
end;

function TfrmCryptograph.GetKey(aKey: string; aPercent: Double): string;
var
i:integer;
begin
SetLength(Result,Length(aKey));
for i:=1 to Length(aKey) do
begin
Result[i]:=Chr(Round(Ord(aKey[i])*aPercent));
end;
end;

procedure TfrmCryptograph.btnEncodeClick(Sender: TObject);
var
i: Integer;
str: string;
begin
mmoOutput.Clear;
pgcCryptograph.ActivePageIndex := 1;
for i := 0 to mmoInput.Lines.Count do
begin
str := EnCode(mmoInput.Lines.Strings[i],GetKey(Key,Percent1));
mmoOutput.Lines.Append(str);
end;
end;

procedure TfrmCryptograph.btnDecodeClick(Sender: TObject);
var
i: Integer;
str: string;
begin
mmoInput.Clear;
pgcCryptograph.ActivePageIndex := 0;
for i := 0 to mmoOutput.Lines.Count do
begin
str := DeCode(mmoOutput.Lines.Strings[i],GetKey(Key,Percent1)) ;
mmoInput.Lines.Append(str)
end;
end;

procedure TfrmCryptograph.FormCreate(Sender: TObject);
begin
initEnDeCodeForm(Sender);
pgcCryptograph.ActivePageIndex := 0;
end;

procedure TfrmCryptograph.initEnDeCodeForm(Sender: TObject);
var
iniFileName: string;
begin
{如果没有初始化的明文输入,则清空}
if not withIniOriginalText then
mmoInput.Clear;
if not withIniDecodedText then
mmoOutput.Clear;
iniFileName := 'config\config.ini';
with TInifile.Create(iniFileName) do
begin
percent1 := ReadFloat('CRYPTOGRAPHY','PERCENT',0);
key := ReadString('CRYPTOGRAPHY','KEY','');
Free;
end;
end;

procedure TfrmCryptograph.FormShow(Sender: TObject);
begin
initEnDeCodeForm(Sender);
end;

procedure TfrmCryptograph.btnImportEncodeClick(Sender: TObject);
begin
dlgOpenCryptograph.Execute;
mmoInput.Clear;
try
mmoInput.Lines.LoadFromFile(dlgOpenCryptograph.FileName);
except
Exit;
// MessageBox(Handle, '读取文件出错,请重试', '提示', MB_OK);
end;
end;

procedure TfrmCryptograph.btnExportEncodeClick(Sender: TObject);
begin
dlgSaveCryptograph.Execute;
try
mmoInput.Lines.SaveToFile(dlgSaveCryptograph.FileName + '.sql');
except
Exit;
// MessageBox(Handle, '保存文件出错,请重试', '提示', MB_OK);
end;
end;

procedure TfrmCryptograph.btnImportDecodeClick(Sender: TObject);
begin
dlgOpenCryptograph.Execute;
mmoInput.Clear;
try
mmoInput.Lines.LoadFromFile(dlgOpenCryptograph.FileName);
except
Exit;
// MessageBox(Handle, '读取文件出错,请重试', '提示', MB_OK);
end;
end;

procedure TfrmCryptograph.btnExportDecodeClick(Sender: TObject);
begin
dlgSaveCryptograph.Execute;
try
mmoOutput.Lines.SaveToFile(dlgSaveCryptograph.FileName + '.sql');
except
Exit;
// MessageBox(Handle, '保存文件出错,请重试', '提示', MB_OK);
end;
end;

procedure TfrmCryptograph.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
mmoInput.Clear;
mmoOutput.Clear;
withIniOriginalText := False;
withIniDecodedText := False;
end;

总结:这个小工具花了我一天多的时间。其中大部分用来找加密未完成却中断的原因了,结果还是没有找到,可见要成为IT中的牛人,数学是多么重要。虽然实际开发中未必用得了算法,未必要那么考虑效率,可是,对于一个程序员来说,追求完美是一种天性,应该坚持下去。

Apr 13, 2009

毕业设计(未完工)

前言: 上周的时间几乎都花在搞毕设上了。感觉做的这个毕业设计很奇怪,没有参考代码就算了,连需求文档,软件架构分析,模块划分等都没有,直接就是开了几个小会,说了些功能要求就让我们自己写。没法,TA的老大们最近忙着推出4.0版本的TA系统,没空理我们。我们10F这些实习生闲的心慌慌,以为毕设没法完成了。谁知道Delphi这么强大。。开发进度很快,已经差不多要完工了。贴几张图上来记录一下成果
格式: 图在上,解说在下.




1 :这是框架的配置文件,主要用于配置登录数据库的方案名,用户名(暂时没把密码考虑进去,不然还要考虑加密,况且数据库目前只支持Oracle)。登录窗口直接从这里读取这两个配置文件从而进行初始化这里使用了Delphi中的TIniFile类进行配置文件的读取和写入。确实是非常好用的一个类。
可以在配置文件上直接更改。若检测到改动会提示保存与否。




2:这是登录成功后从系统工具菜单里打开的新报表生成工具的第一页。主要用于查询现有可用报表,从一个专门的数据库表单中读取数据并显示在DBGrid中。这一页使用的是DBGrid,确实没有DBGridEh方便,为了写一个随鼠标滚轮而移动TDataSource的游标,并且实现在移动到表格边界时自动翻页,我得另外写个窗口过程,将DBGrid原先的窗口过程保存为一个TWndMethod的变量,将新的窗口过程赋给它。在新的窗口过程中要捕获WM_MOUSEWHEEL消息并做如下处理
if Message.WParam >0 then
ADBGrid.DataSource.DataSet.MoveBy(-1)
else
ADBGrid.DataSource.DataSet.MoveBy(1);
对于非鼠标滚轮消息则调用保存的原DBGrid窗口过程处理。同时,如果要在不同页里其他DBGrid里实现相同效果,我得做类似的处理。还要小心非鼠标滚轮的消息不会被忘记处理,不然马上会报错。
而如果使用DBGridEh,它是自带的属性 -_-##
上边蓝色部分两个Edit组件是用来跟踪当前选中报表信息,可以随顺表滚轮滚动动态更新为当前所在记录行



3:这是第2个页面。主要功能是绿色部分的SQL语句查询功能并在下边的表格里显示。在SQL语句输入框上有几个功能键:可以从外部带入一个SQL脚本,可以将输入的SQL脚本导出到硬盘,清空SQL输入框内容,执行SQL语句,另外带了一个拼写帮助。如右上角对话框所示。
可以在显示结果的DBGridEh中直接修改记录数据,并且修改将会被自动保存(暂时不支持回滚)。令人感动的DBGridEh自带了even和odd行颜色不同的功能,如果用普通的DBGrid又得自己写属性。



3:这是第三个字段设置页。主要用来勾选新报表要采用的字段,grid里的checkbox还没有加上去,因为要修改原表结构,添加至少三个字段进去,所以要问下导师要不要加。可以查询所有可用字段,可以添加和删除字段。
这一页可以从第一页双击GRID中某行数据跳转过来,如果是这样的话左边的新报表信息栏会已从第一页选中的报表配置为模版导入。图中左边显示的就是导入报表模版的结果



4:最后一个是SQL脚本生成。将生成新报表的操作全部翻译为SQL语句,导出成为脚本,如果某台计算机上装了相应的数据库导入了相应的表,那只要运行这个脚本,就可以在任意计算机上生成根据配置结果生成的新报表。

总结:一切都只草草带过。具体技术细节有时间我会陆续发上来,不过其实也没什么难的,是Delphi这把刀太好使了。如果是用MFC,这框架就得累死我。
这个框架写的还是不错的,可扩展性很强。有新的功能可以独立编写一个功能模块然后把相应的FORM做一些格式上更改就可以直接加入现有的框架了。但我觉得还不够,如果所有的功能模块都可以写成DLL文件形式的那就跟方便了,主程序也不会越写越大。

同时我有个想法,因为DLL文件调试很不方便(一旦生成了就没法跟进文件调了),而调试DLL的方法除了专门建个测试工程,还剩一个使用系统日志调试的。我想写个这样的DLL调试工具,liangpei2008在CSDN里回复说建议我用COM+写. GOSH,我还不清楚COM+是什么呢!慢慢来。总是会懂的,我要加油

Apr 9, 2009

Delphi中调试DLL文件(感谢liangpei2008的回答)

可以调试!

完整的调试 DLL方法如下:

1)新建一个 DLL 工程,名字就叫 MyDll 吧,编译后生成 MyDll.dll,我们要调试的就是它了。

2)新建一个用来调试 MyDll 的 Application 工程,名字就叫 MyDllTest 吧,编译后生成的可执行性文件为 MyDllTest.exe,这就是我们用来调试 MyDll.dll 的宿主程序

3)MyDllTest.exe 所在目录中不能有 MyDll.dll(重要!)

4)MyDllTest 采用静态调用的方法调用 MyDll.dll 的导出函数(重要!)

5)进入 MyDll 工程,执行菜单“Run”->“Parameters”,将弹出的对话框的 Local 页中的“Host Application”设置为上面的 MyDllTest.exe(含路径)


还要注意的是,调试 dll 的时候,被调试的 dll 和宿主程序不能在同一个 Project Group中,也就是说,你不要把 dll 和宿主程序放在同一个 Project Group中再进行调试,一定要单独打开 dll 工程进行调试。否则,调试也会不成功。


不过能调试DLL是省了一些时间,但不太规范!
创建一个日志输出模块(最好写成COM+),声明几个接口,这样整个项目的日志记录均输出于此(同时在WIndows下的各种开发环境均可调用)!而且还可以复用!

Apr 6, 2009

Delphi做的百叶窗小程序

做了一个百叶窗小程序
碰到了几个问题,比如说两个用到LoadFromFile函数的地方第一次可以识别相对路径
而如果我更改了其中一个的路径使其变为硬盘上某个绝对路径
那另外一个LoadFromFile就不能识别原先的相对路径了,很奇怪
我采取了加判断绕过这个问题的方法
先上代码,主要的是shutter单元,是作为一个组件来编写的
另外还写了个测试单元。主要针对Shutter的某些属性进行设置从而测试Shutter

unit Shutter;
{ CopyRight@ Swetter }
interface

uses
SysUtils, Windows, Classes, Forms, Controls, Graphics,
Messages, ExtCtrls, Dialogs;

const
{位图344*500,沿Y轴等分成10块
yInc存储了每块的高度
BitMapWid存储了位图的宽度
BitMapHei存储了位图的高度
ShowPixels为随Timer每次递增的行宽度
TimerInterval为Timer的时间间隔}
YInc = 50;
// ShowPixels = 1;
BitMapWid = 344;
BitMapHei = 500;
// TimerInterval = 50;

type
EShutterError = class(Exception);

TShutter = class(TCustomPanel)
private
FMemBitMap: TBitmap;
FMemMskBtMp: TBitmap;
FTimer: TTimer;
FActive: Boolean;
FCurrHei: Integer;
FVRect: TRect;
{FOpen指示百叶窗打开与关闭效果,true则百叶窗打开,false则百叶窗关闭
FDone指示位图是否显示完毕
FViewPic指示是否要查看原图
true为查看原图,此时FCurrHei值直接为yInc而不置0
false为不查看原图,此时在SetActive为false后FCurrHei置0
FNFrstm指示在百叶窗打开模式下(即清空图像)是否已贴上原图
false为未贴上原图,需重新贴一次;true为已贴上原图,可以开始贴屏蔽图}
FOpen: Boolean;
FDone: Boolean;
FViewPic: Boolean;
FOnDone: TNotifyEvent;
FNFrstm: Boolean;
FBkFileName: string;
FFgFileName: string;
ShowPixels: Integer;
TimerInterval: Integer;
procedure IncWid;
procedure SetActive(AValue: Boolean);
procedure ActOnTimer(Sender: TObject);
procedure DoTimer;
protected
procedure Paint; override;
procedure FillBitmap; virtual;
public
procedure CoordinateTimer;
procedure ImageChanged;
property Pixel: Integer read ShowPixels write ShowPixels;
property Interval: Integer read TimerInterval write TimerInterval;
property BkFileName: string read FBkFileName write FBkFileName;
property FgFileName: string read FFgFileName write FFgFileName;
property NFrstm: Boolean read FNFrstm write FNFrstm;
property Open: Boolean read FOpen write FOpen;
property ViewPic: Boolean read FViewPic write FViewPic;
property Active: Boolean read FActive write SetActive;
property Done: Boolean read FDone write FDone;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Publish inherited properties: }
property OnDone: TNotifyEvent read FOnDone write FOnDone;
property Align;
property Alignment;
property BevelInner;
property BevelOuter;
property BevelWidth;
property BorderWidth;
property BorderStyle;
property Color;
property Ctl3D;
property Font;
property Locked;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property Visible;
property OnClick;
property OnDblClick;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnResize;
end;

implementation

{ TShutter }

procedure TShutter.DoTimer;
begin
with FTimer do
begin
Enabled := False;
Interval := TimerInterval;
OnTimer := ActOnTimer;
end;
end;

constructor TShutter.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
TimerInterval := 50;
ShowPixels := 1;
FTimer := TTimer.Create(Self);
DoTimer;
{ 实例初始化的值 }
Width := 344;
Height := 500;
FActive := False;
BevelWidth := 3;
FFgFileName := '.\pics\pic.bmp';
FBkFileName := '.\pics\view.bmp';
end;

destructor TShutter.Destroy;
begin
SetActive(False);
FTimer.Free;
inherited Destroy;
end;

procedure TShutter.ActOnTimer(Sender: TObject);
begin
IncWid;
InvalidateRect(Handle, @FVRect, false);
end;

procedure TShutter.FillBitmap;
begin
//FVRect存储了整张内存位图的区域大小
FVRect := Rect(0, 0, BitMapWid, BitMapHei);
//初始化FMemBitMap的宽度和高度
FMemMskBtMp:= TBitmap.Create;
FMemBitMap := TBitmap.Create;
FMemMskBtMp.Width := BitMapWid;
FMemMskBtMp.Height:= BitMapHei;
FMemBitMap.Width := BitMapWid;
FMemBitMap.Height := BitMapHei;
try
if FBkFileName <> '.\pics\view.bmp' then
FMemMskBtMp.LoadFromFile(FBkFileName);
if FFgFileName <> '.\pics\pic.bmp' then
FMemBitMap.LoadFromFile(FFgFileName);
except
on EFOpenError DO
MessageBox(Handle,'打开文件出错,请重试','提示',MB_OK);
end;
end;

procedure TShutter.IncWid;
begin
if not FOpen and (not FDone) then
begin
if FCurrHei + ShowPixels <= yInc then Inc(FCurrHei, ShowPixels) //为保存位图,不要SetActive(False) else FDone := True; end else if FOpen and(not FDone) then begin if FCurrHei - ShowPixels >= 0 then
Dec(FCurrHei, ShowPixels)
else
FDone := True;
end;
end;

procedure TShutter.Paint;
var
i: Integer;
begin
//如果要查看背景图,直接贴上去
if FViewPic then
BitBlt(Canvas.Handle, 0, 0, BitMapWid, BitMapHei,
FMemBitMap.Canvas.Handle, 0, 0, srcCopy);

if FActive and not FOpen then
for i := 0 to 9 do
BitBlt(Canvas.Handle, 0, i*YInc, BitMapWid, FCurrHei,
FMemBitMap.Canvas.Handle, 0, i*YInc, srcCopy)
else if FActive and FOpen then
begin
if not NFrstm then
begin
for i := 0 to 9 do
BitBlt(Canvas.Handle, 0, i*YInc, BitMapWid, YInc,
FMemBitMap.Canvas.Handle, 0, i*YInc, SRCCOPY);
NFrstm := True;
end
else
for i := 0 to 9 do
BitBlt(Canvas.Handle, 0, i*YInc , BitMapWid, YInc - FCurrHei,
FMemMskBtMp.Canvas.Handle, 0, i*YInc, SRCCOPY);
end
else inherited Paint;
end;

procedure TShutter.SetActive(AValue: Boolean);
begin
if AValue and (not FActive) then
begin
FActive := True;
FillBitmap;
{FViewPic,true则查看位图
FOpen,True则为百叶窗打开模式}
if not FOpen then
FCurrHei := 0
else
FCurrHei := YInc;

try
FTimer.Enabled := True;
except
EShutterError.Create('Timer初始化出错');
end;
end
else if (not AValue) and FActive then
begin
FTimer.Enabled := False; //停止计时
if Assigned(FOnDone) // fire OnDone event,
then FOnDone(Self);
FActive := False; //停止组件
FMemBitMap.Free; //释放内存位图
FMemMskBtMp.Free; //释放屏蔽位图
Invalidate; //清空组件窗口内容
end;
end;

procedure TShutter.ImageChanged;
begin
if (FMemMskBtMp <> nil) and (FMemBitMap <> nil) then
begin
FMemMskBtMp.FreeImage; //释放所占用的位图资源免得重新加载错误
FMemBitMap.FreeImage;
end;
FillBitmap;
end;

procedure TShutter.CoordinateTimer;
begin
DoTimer;
end;

end.

基本上运行效果还是可以的
但是从代码中可以看到很多的boolean值的参数
它们是用来判断功能从而有选择的调用BitBlt函数
设计还是不够好,其实可以用case语句来区分不同功能
我用了太多的boolean来判断导致扩展起来很不方便,容易出BUG
先放这里,慢慢再改

Apr 5, 2009

仿Windows的画图程序

仅贴出关键的代码部分

unit MainFrm;

interface

uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Buttons, ExtCtrls, ColorGrd, StdCtrls, Menus, ComCtrls;

const
crMove = 1;
rate1 = 0.38;
rate2 = 0.19;
type

TDrawType = (dtLineDraw, dtRectangle, dtEllipse, dtRoundRect,
dtClipRect, dtCrooked, dtPolyLine, dtPolygon,
dtTriangle, dtFan);
{用于画三角形的record}
TTriangle = record
FStrtDot: TPoint;
FEndDot : TPoint;
FFrstDot: TPoint;
FScndDot: TPoint;
FThrdDot: TPoint;
FScndVal: Boolean;
end;
{用于画扇形的record}
TFan = record
FStrtDot: TPoint;
FOrgDot : TPoint;
FLstDot : TPoint;
FNFrst : Boolean;
end;
{用于画五角星的record,记录五个端点}
TStar = record
FTL: TPoint;
FBR: TPoint;
FFrstDot: TPoint;
FScndDot: TPoint;
FThrdDot: TPoint;
FFrthDot: TPoint;
FFfthDot: TPoint;
end;

TMainForm = class(TForm)
sbxMain: TScrollBox;
imgDrawingPad: TImage;
pnlToolBar: TPanel;
sbLine: TSpeedButton;
sbRectangle: TSpeedButton;
sbEllipse: TSpeedButton;
sbRoundRect: TSpeedButton;
pnlColors: TPanel;
cgDrawingColors: TColorGrid;
pnlFgBgBorder: TPanel;
pnlFgBgInner: TPanel;
Bevel1: TBevel;
mmMain: TMainMenu;
mmiFile: TMenuItem;
mmiExit: TMenuItem;
N2: TMenuItem;
mmiSaveAs: TMenuItem;
mmiSaveFile: TMenuItem;
mmiOpenFile: TMenuItem;
mmiNewFile: TMenuItem;
mmiEdit: TMenuItem;
mmiPaste: TMenuItem;
mmiCopy: TMenuItem;
mmiCut: TMenuItem;
sbRectSelect: TSpeedButton;
SaveDialog: TSaveDialog;
OpenDialog: TOpenDialog;
stbMain: TStatusBar;
pbPasteBox: TPaintBox;
sbFreeForm: TSpeedButton;
RgGrpFillOptions: TRadioGroup;
cbxBorder: TCheckBox;
sbPolyline: TSpeedButton;
sbPolygon: TSpeedButton;
sbTriangle: TSpeedButton;
sbFan: TSpeedButton;
dlgColor: TColorDialog;
btnBorder: TButton;
btnFill: TButton;
procedure FormCreate(Sender: TObject);
procedure sbLineClick(Sender: TObject);
procedure imgDrawingPadMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure imgDrawingPadMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure imgDrawingPadMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure cgDrawingColorsChange(Sender: TObject);
procedure mmiExitClick(Sender: TObject);
procedure mmiSaveFileClick(Sender: TObject);
procedure mmiSaveAsClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure mmiNewFileClick(Sender: TObject);
procedure mmiOpenFileClick(Sender: TObject);
procedure mmiEditClick(Sender: TObject);
procedure mmiCutClick(Sender: TObject);
procedure mmiCopyClick(Sender: TObject);
procedure mmiPasteClick(Sender: TObject);
procedure pbPasteBoxMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure pbPasteBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure pbPasteBoxMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure pbPasteBoxPaint(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure RgGrpFillOptionsClick(Sender: TObject);
procedure btnBorderClick(Sender: TObject);
procedure btnFillClick(Sender: TObject);
public
{ Public declarations }
MouseOrg: TPoint; // Stores mouse information
NextPoint: TPoint; // Stores mouse information
Drawing: Boolean; // Drawing is being performed flag
DrawType: TDrawType; // Holds the draw type information: TDrawType
FillSelected, // Fill shapes flag
BorderSelected: Boolean; // Draw Shapes with no border flag
EraseClipRect: Boolean; // Specifies whether or not to erase the
// clipping rectangle
Modified: Boolean; // Image modified flag
FileName: String; // Holds the filename of the image
OldClipViewHwnd: Hwnd; // Holds the old clipboard view window
{ Paste Image variables }
PBoxMoving: Boolean; // PasteBox is moving flag
PBoxMouseOrg: TPoint; // Stores mouse coordinates for moving PasteBox
PasteBitMap: TBitmap; // Stores a bitmap image of the pasted data
Pasted: Boolean; // Data pasted flag
LastDot: TPoint; // Hold the TPoint coordinate for performing
// free line drawing
procedure DrawToImage(TL, BR: TPoint; PenMode: TPenMode);
{ This procedure paints the image specified by the DrawType field
to imgDrawingPad }
procedure SetDrawingStyle;
{ This procedure sets various Pen/Brush styles based on values
specified by the form's controls. The Panels and color grid is
used to set these values }
procedure CopyPasteBoxToImage;
{ This procedure copies the data pasted from the Windows clipboard
onto the main image component imgDrawingPad }
procedure WMDrawClipBoard(var Msg: TWMDrawClipBoard);
message WM_DRAWCLIPBOARD;
{ This message handler captures the WM_DRAWCLIPBOARD messages
which is sent to all windows that have been added to the clipboard
viewer chain. An application can add itself to the clipboard viewer
chain by using the SetClipBoardViewer() Win32 API function as
is done in FormCreate() }
procedure CopyCut(Cut: Boolean);
{ This method copies a portion of the main image, imgDrawingPad, to the
Window's clipboard. }
end;

var
MainForm: TMainForm;

{用于画PolyLine的专用全局变量,Polyline随鼠标滑动而动态绘制
PLStart: TPoint,用于保存Polyline的起点,随着每次鼠标UP而动态更新
PLLast: TPoint,用于保存鼠标每滑动一次的终止点
PLDrawed: Boolean,用于鼠标滑动时检查是否已画了折线
true 则XOR掉起点到Move当前点上一点所绘制的折线并重画
false则直接重画
}
PLStart, PLLast: TPoint;
PLDrawed: Boolean;

{用于画Triangle的量,为TTriangle类型}
Trngl: TTriangle;
{用于画Fan的量,为TFan类型}
Fn: TFan;

implementation
uses ClipBrd, Math;

{$R *.DFM}

procedure TMainForm.FormCreate(Sender: TObject);
{ This method sets the form's field to their default values. It then
creates a bitmap for the imgDrawingPad. This is the image on which
drawing is done. Finally, it adds this application as part of the
Windows clipboard viewer chain by using the SetClipBoardViewer()
function. This makes enables the form to get WM_DRAWCLIPBOARD messages
which are sent to all windows in the clipboard viewer chain whenever
the clipboard data is modified. }
begin
Screen.Cursors[crMove] := LoadCursor(hInstance, 'MOVE');

FillSelected := False;
BorderSelected := True;

Modified := False;
FileName := '';
Pasted := False;
pbPasteBox.Enabled := False;

// Create a bitmap for imgDrawingPad and set its boundaries
with imgDrawingPad do
begin
SetBounds(0, 0, 600, 400);
Picture.Graphic := TBitMap.Create;
Picture.Graphic.Width := 600;
Picture.Graphic.Height := 400;
end;
// Now create a bitmap image to hold pasted data
PasteBitmap := TBitmap.Create;
pbPasteBox.BringToFront;
{ Add the form to the Windows clipboard viewer chain. Save the handle
of the next window in the chain so that it may be restored by the
ChangeClipboardChange() Win32 API function in this form's
FormDestroy() method. }
OldClipViewHwnd := SetClipBoardViewer(Handle);
end;

procedure TMainForm.WMDrawClipBoard(var Msg: TWMDrawClipBoard);
begin
{ This method will be called whenever the clipboard data
has changed. Because the main form was added to the clipboard
viewer chain, it will receive the WM_DRAWCLIPBOARD message
indicating that the clipboard's data was changed. }
inherited;
{ Make sure that the data contained on the clipboard is actually
bitmap data. }
if ClipBoard.HasFormat(CF_BITMAP) then
mmiPaste.Enabled := True
else
mmiPaste.Enabled := False;
Msg.Result := 0;
end;


procedure TMainForm.DrawToImage(TL, BR: TPoint; PenMode: TPenMode);
{ This method performs the specified drawing operation. The
drawing operation is specified by the DrawType field }
var
//用于画五角星的点
x1,y1,x2,x3: Integer;
begin
with imgDrawingPad.Canvas do
begin
Pen.Mode := PenMode;

case DrawType of
dtLineDraw, dtPolyLine, dtTriangle, dtFan:
begin
MoveTo(TL.X, TL.Y);
LineTo(BR.X, BR.Y);
end;
dtPolygon:
begin
//x1这一点前边别忘记加上TL.X,否则画出奇怪的图形啊!!!
x1 := TL.X + (BR.X - TL.X) div 2;
y1 := trunc(TL.Y+(BR.Y-TL.Y)*rate1);
x2 := trunc(TL.X+(BR.X-TL.X)*rate2);
x3 := trunc(BR.X-(BR.X-TL.X)*rate2);
MoveTo(x1, TL.Y);
LineTo(x2, BR.y);
LineTo(BR.X, y1);
LineTo(TL.X, y1);
LineTo(x3, BR.Y);
LineTo(x1, TL.Y);
x1 := 0;
y1 := 0;
x2 := 0;
x3 := 0;
end;
dtRectangle:
Rectangle(TL.X, TL.Y, BR.X, BR.Y);
dtEllipse:
Ellipse(TL.X, TL.Y, BR.X, BR.Y);
dtRoundRect:
RoundRect(TL.X, TL.Y, BR.X, BR.Y,
(TL.X - BR.X) div 2, (TL.Y - BR.Y) div 2);
dtClipRect:
Rectangle(TL.X, TL.Y, BR.X, BR.Y);

end;
end;
end;

procedure TMainForm.CopyPasteBoxToImage;
{ This method copies the image pasted from the Windows clipboard onto
imgDrawingPad. It first erases any bounding rectangle drawn by PaintBox
component, pbPasteBox. It then copies the data from pbPasteBox onto
imgDrawingPad at the location where pbPasteBox has been dragged
over imgDrawingPad. The reason we don't copy the contents of
pbPasteBox's canvas and use PasteBitmap's canvas instead, is because
when a portion of pbPasteBox is dragged out of the viewable area,
Windows does not paint the portion pbPasteBox not visible. Therefore,
it is necessary to the pasted bitmap from the off-screen bitmap }
var
SrcRect, DestRect: TRect;
begin
// First, erase the rectangle drawn by pbPasteBox
with pbPasteBox do
begin
Canvas.Pen.Mode := pmNotXOR;
Canvas.Pen.Style := psDot;
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(0, 0, Width, Height);
DestRect := Rect(Left, Top, Left+Width, Top+Height);
SrcRect := Rect(0, 0, Width, Height);
end;
{ Here we must use the PasteBitmap instead of the pbPasteBox because
pbPasteBox will clip anything outside if the viewable area. }
imgDrawingPad.Canvas.CopyRect(DestRect, PasteBitmap.Canvas, SrcRect);
pbPasteBox.Visible := false;
pbPasteBox.Enabled := false;
Pasted := False; // Pasting operation is complete
end;

procedure TMainForm.imgDrawingPadMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Modified := True;
// Erase the clipping rectangle if one has been drawn
if (DrawType = dtClipRect) and EraseClipRect then
DrawToImage(MouseOrg, NextPoint, pmNotXOR)
else if (DrawType = dtClipRect) then
EraseClipRect := True; // Re-enable cliprect erasing
if Pasted then
CopyPasteBoxToImage;

Drawing := True;
// Save the mouse information
if (DrawType = dtPolyline) and (not PLDrawed) then
begin
PLStart := Point(X,Y);
PLLast := PLStart;
end ;
if (DrawType = dtTriangle) and (not Trngl.FScndVal) then
begin
Trngl.FFrstDot := Point(X,Y);
Trngl.FStrtDot := Point(X,Y);
Trngl.FEndDot := Trngl.FStrtDot;
end;
if (DrawType = dtFan) and (not Fn.FNFrst) then
begin
Fn.FStrtDot := Point(X,Y);
Fn.FOrgDot := Point(X,Y);
Fn.FLstDot := Point(X,Y);
end;
MouseOrg := Point(X, Y);
NextPoint := MouseOrg;
LastDot := NextPoint; // Lastdot is updated as the mouse moves
//将线的起点移动到鼠标按下的点
imgDrawingPad.Canvas.MoveTo(X, Y);
end;

procedure TMainForm.imgDrawingPadMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
{ This method determines the drawing operation to be performed and
either performs free form line drawing, or calls the
DrawToImage method which draws the specified shape }
begin
if Drawing then
begin
case DrawType of
dtCrooked:
begin
imgDrawingPad.Canvas.MoveTo(LastDot.X, LastDot.Y);
imgDrawingPad.Canvas.LineTo(X, Y);
LastDot := Point(X,Y);
end;
dtPolyLine:
begin
DrawToImage(PLStart, PLLast, pmNotXor);
PLLast := Point(X,Y);
DrawToImage(PLStart, PLLast, pmNotXor);
PLDrawed := True;
end;
dtTriangle:
begin
DrawToImage(Trngl.FStrtDot, Trngl.FEndDot, pmNotXor);
Trngl.FEndDot := Point(X,Y);
DrawToImage(Trngl.FStrtDot, Trngl.FEndDot, pmNotXor);
end;
dtFan:
if not Fn.FNFrst then
begin
DrawToImage(Fn.FStrtDot, Fn.FOrgDot, pmNotXor);
Fn.FOrgDot := Point(X, Y);
DrawToImage(Fn.FStrtDot, Fn.FOrgDot, pmNotXor);
end
else begin
///:~@@@@@@@使用了pmCopy后扇形的前一条边就不会消失,为什么??
DrawToImage(Fn.FStrtDot, Fn.FOrgDot, pmCopy);
DrawToImage(Fn.FOrgDot, Fn.FLstDot, pmNotXor);
DrawToImage(Fn.FStrtDot, Fn.FLstDot, pmNotXor);
Fn.FLstDot := Point(X,Y);
DrawToImage(Fn.FOrgDot, Fn.FLstDot, pmNotXor);
DrawToImage(Fn.FStrtDot, Fn.FLstDot, pmNotXor);
end
else begin
DrawToImage(MouseOrg, NextPoint, pmNotXor);
NextPoint := Point(X, Y);
DrawToImage(MouseOrg, NextPoint, pmNotXor)
end;
end;
end;
// Update the status bar with the current mouse location
stbMain.Panels[1].Text := Format('X: %d, Y: %D', [X, Y]);
end;

procedure TMainForm.imgDrawingPadMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
{ Prevent the clipping rectangle from destroying the images already
on the image }
case DrawType of
dtPolyLine:
begin
DrawToImage(PLStart, Point(X,Y), pmCopy);
PLStart := Point(X,Y);
end;
dtTriangle:
begin
if not Trngl.FScndVal then
begin
Trngl.FScndDot := Point(X,Y);
DrawToImage(Trngl.FStrtDot, Trngl.FEndDot, pmCopy);
Trngl.FStrtDot := Trngl.FScndDot;
Trngl.FScndVal := True;
end
else begin
Trngl.FThrdDot := Point(X,Y);
DrawToImage(Trngl.FStrtDot, Trngl.FEndDot, pmCopy);
DrawToImage(Trngl.FThrdDot, Trngl.FFrstDot, pmNotXor);
Trngl.FScndVal := False;
end;
end;
dtFan:
if not Fn.FNFrst then
begin
DrawToImage(Fn.FStrtDot, Fn.FLstDot, pmCopy);
Fn.FNFrst := True;
end
else begin
DrawToImage(Fn.FStrtDot, Fn.FOrgDot, pmCopy);
DrawToImage(Fn.FStrtDot, Fn.FLstDot, pmCopy);
DrawToImage(Fn.FOrgDot, Fn.FLstDot, pmCopy);
Fn.FOrgDot := Point(X,Y);
end;
dtLineDraw, dtRectangle, dtEllipse, dtRoundRect, dtCrooked:
DrawToImage(MouseOrg, Point(X, Y), pmCopy);
end;
Drawing := False;
end;

procedure TMainForm.sbLineClick(Sender: TObject);
begin
// First erase the cliprect if current drawing type
if DrawType = dtClipRect then
DrawToImage(MouseOrg, NextPoint, pmNotXOR);

{ Now set the DrawType field to that specified by the TSpeedButton
invoking this method. The TSpeedButton's Tag values match a
specific TDrawType value which is why the typecasting below
successfully assigns a valid TDrawType value to the DrawType field. }
if Sender is TSpeedButton then
DrawType := TDrawType(TSpeedButton(Sender).Tag);

// Now make sure the dtClipRect style doesn't erase previous drawings
if DrawType = dtClipRect then begin
EraseClipRect := False;
end;
// Set the drawing style
SetDrawingStyle;
end;

procedure TMainForm.cgDrawingColorsChange(Sender: TObject);
{ This method draws the rectangle representing fill and border colors
to indicate the users selection of both colors. pnlFgBgInner and
pnlFgBgBorder are TPanels arranged one on to of the other for the
desired effect }
begin
pnlFgBgBorder.Color := cgDrawingColors.ForeGroundColor;
pnlFgBgInner.Color := cgDrawingColors.BackGroundColor;
SetDrawingStyle;
end;


procedure TMainForm.SetDrawingStyle;
{ This method sets the various drawing styles based on the selections
on the pnlFillStyle TPanel for Fill and Border styles }
begin
with imgDrawingPad do
begin
if DrawType = dtClipRect then
begin
Canvas.Pen.Style := psDot;
Canvas.Brush.Style := bsClear;
Canvas.Pen.Color := clBlack;
end

else if FillSelected then
Canvas.Brush.Style := bsSolid
else
Canvas.Brush.Style := bsClear;

if BorderSelected then
Canvas.Pen.Style := psSolid
else
Canvas.Pen.Style := psClear;


if FillSelected and (DrawType <> dtClipRect) then
Canvas.Brush.Color := pnlFgBgInner.Color;

if DrawType <> dtClipRect then
Canvas.Pen.Color := pnlFgBgBorder.Color;
end;
end;

procedure TMainForm.mmiExitClick(Sender: TObject);
begin
Close; // Terminate application
end;

procedure TMainForm.mmiSaveFileClick(Sender: TObject);
{ This method saves the image to the file specified by FileName. If
FileName is blank, however, SaveAs1Click is called to get a filename.}
begin
if FileName = '' then
mmiSaveAsClick(nil)
else begin
imgDrawingPad.Picture.SaveToFile(FileName);
stbMain.Panels[0].Text := FileName;
Modified := False;
end;
end;

procedure TMainForm.mmiSaveAsClick(Sender: TObject);
{ This method launches SaveDialog to get a file name to which
the image's contents will be saved. }
begin
if SaveDialog.Execute then
begin
FileName := SaveDialog.FileName; // Store the filename
mmiSaveFileClick(nil)
end;
end;

procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
{ If the user attempts to close the form before saving the image, they
are prompted to do so in this method. }
var
Rslt: Word;
begin
CanClose := False; // Assume fail.
if Modified then begin
Rslt := MessageDlg('File has changed, save?', mtConfirmation, mbYesNOCancel, 0);
case Rslt of
mrYes: mmiSaveFileClick(nil);
mrNo: ; // no need to do anything.
mrCancel: Exit;
end
end;
CanClose := True; // Allow use to close application
end;

procedure TMainForm.mmiNewFileClick(Sender: TObject);
{ This method erases any drawing on the main image after prompting the
user to save it to a file in which case the mmiSaveFileClick event handler
is called. }
var
Rslt: Word;
begin
if Modified then begin
Rslt := MessageDlg('File has changed, save?', mtConfirmation, mbYesNOCancel, 0);
case Rslt of
mrYes: mmiSaveFileClick(nil);
mrNo: ; // no need to do anything.
mrCancel: Exit;
end
end;

with imgDrawingPad.Canvas do begin
Brush.Style := bsSolid;
Brush.Color := clWhite; // clWhite erases the image
FillRect(ClipRect); // Erase the image
FileName := '';
stbMain.Panels[0].Text := FileName;
end;
SetDrawingStyle; // Restore the previous drawing style
Modified := False;
end;

procedure TMainForm.mmiOpenFileClick(Sender: TObject);
{ This method opens a bitmap file specified by OpenDialog.FileName. If
a file was already created, the user is prompted to save
the file in which case the mmiSaveFileClick event is called. }
var
Rslt: Word;
begin

if OpenDialog.Execute then
begin

if Modified then begin
Rslt := MessageDlg('File has changed, save?', mtConfirmation, mbYesNOCancel, 0);
case Rslt of
mrYes: mmiSaveFileClick(nil);
mrNo: ; // no need to do anything.
mrCancel: Exit;
end
end;

imgDrawingPad.Picture.LoadFromFile(OpenDialog.FileName);
FileName := OpenDialog.FileName;
stbMain.Panels[0].Text := FileName;
Modified := false;
end;

end;

procedure TMainForm.mmiEditClick(Sender: TObject);
{ The timer is used to determine if an area on the main image is
surrounded by a bounding rectangle. If so, then the Copy and Cut
menu items are enabled. Otherwise, they are disabled. }
var
IsRect: Boolean;
begin
IsRect := (MouseOrg.X <> NextPoint.X) and (MouseOrg.Y <> NextPoint.Y);
if (DrawType = dtClipRect) and IsRect then
begin
mmiCut.Enabled := True;
mmiCopy.Enabled := True;
end
else begin
mmiCut.Enabled := False;
mmiCopy.Enabled := False;
end;
end;

procedure TMainForm.CopyCut(Cut: Boolean);
{ This method copies a portion of the main image to the clipboard.
The portion copied is specified by a bounding rectangle
on the main image. If Cut is true, the area in the bounding rectandle
is erased. }
var
CopyBitMap: TBitmap;
DestRect, SrcRect: TRect;
OldBrushColor: TColor;
begin
CopyBitMap := TBitMap.Create;
try
{ Set CopyBitmap's size based on the coordinates of the
bounding rectangle }
CopyBitMap.Width := Abs(NextPoint.X - MouseOrg.X);
CopyBitMap.Height := Abs(NextPoint.Y - MouseOrg.Y);
DestRect := Rect(0, 0, CopyBitMap.Width, CopyBitmap.Height);
SrcRect := Rect(Min(MouseOrg.X, NextPoint.X)+1,
Min(MouseOrg.Y, NextPoint.Y)+1,
Max(MouseOrg.X, NextPoint.X)-1,
Max(MouseOrg.Y, NextPoint.Y)-1);
{ Copy the portion of the main image surrounded by the bounding
rectangle to the Windows clipboard }
CopyBitMap.Canvas.CopyRect(DestRect, imgDrawingPad.Canvas, SrcRect);
{ Previous versions of Delphi required the bitmap's Handle property
to be touched for the bitmap to be made available. This was due to
Delphi's caching of bitmapped images. The step below may not be
required. }
CopyBitMap.Handle;
// Assign the image to the clipboard.
ClipBoard.Assign(CopyBitMap);
{ If cut was specified the erase the portion of the main image
surrounded by the bounding Rectangle }
if Cut then
with imgDrawingPad.Canvas do
begin
OldBrushColor := Brush.Color;
Brush.Color := clWhite;
try
FillRect(SrcRect);
finally
Brush.Color := OldBrushColor;
end;
end;
finally
CopyBitMap.Free;
end;
end;

procedure TMainForm.mmiCutClick(Sender: TObject);
begin
CopyCut(True);
end;

procedure TMainForm.mmiCopyClick(Sender: TObject);
begin
CopyCut(False);
end;

procedure TMainForm.mmiPasteClick(Sender: TObject);
{ This method pastes the data contained in the clipboard to the
paste bitmap. The reason it is pasted to the PasteBitmap, an off-
screen bitmap, is so that the user can relocate the pasted image
elsewhere on to the main image. This is done by having the pbPasteBox,
a TPaintBox component, draw the contents of PasteImage. When the
user if done positioning the pbPasteBox, the contents of TPasteBitmap
is drawn to imgDrawingPad at the location specified by pbPasteBox's location.}
begin
{ Clear the bounding rectangle }

pbPasteBox.Enabled := True;
if DrawType = dtClipRect then
begin
DrawToImage(MouseOrg, NextPoint, pmNotXOR);
EraseClipRect := False;
end;

PasteBitmap.Assign(ClipBoard); // Grab the data from the clipboard
Pasted := True;
// Set position of pasted image to top left
pbPasteBox.Left := 0;
pbPasteBox.Top := 0;
// Set the size of pbPasteBox to match the size of PasteBitmap
pbPasteBox.Width := PasteBitmap.Width;
pbPasteBox.Height := PasteBitmap.Height;

pbPasteBox.Visible := True;
pbPasteBox.Invalidate;
end;

procedure TMainForm.pbPasteBoxMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
{ This method set's up pbPasteBox, a TPaintBox for being moved by the
user when the left mouse button is held down }
begin
if Button = mbLeft then
begin
PBoxMoving := True;
Screen.Cursor := crMove;
PBoxMouseOrg := Point(X, Y);
end
else
PBoxMoving := False;
end;

procedure TMainForm.pbPasteBoxMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
{ This method moves pbPasteBox if the PBoxMoving flag is true indicating
that the user is holding down the left mouse button and is dragging
PaintBox }
begin
if PBoxMoving then
begin
pbPasteBox.Left := pbPasteBox.Left + (X - PBoxMouseOrg.X);
pbPasteBox.Top := pbPasteBox.Top + (Y - PBoxMouseOrg.Y);
end;
end;

procedure TMainForm.pbPasteBoxMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
{ This method disables moving of pbPasteBox when the user lifts the left
mouse button }
if PBoxMoving then
begin
PBoxMoving := False;
Screen.Cursor := crDefault;
end;
pbPasteBox.Refresh; // Redraw the pbPasteBox.
end;

procedure TMainForm.pbPasteBoxPaint(Sender: TObject);
{ The paintbox is drawn whenever the user selects the Paste option
form the menu. pbPasteBox draws the contents of PasteBitmap which
holds the image gotten from the clipboard. The reason for drawing
PasteBitmap's contents in pbPasteBox, a TPaintBox class, is so that
the user can also move the object around on top of the main image.
In other words, pbPasteBox can be moved, and hidden when necessary. }
var
DestRect, SrcRect: TRect;
begin
// Display the paintbox only if a pasting operation occurred.
if Pasted then
begin
{ First paint the contents of PasteBitmap using canvas's CopyRect
but only if the paintbox is not being moved. This reduces
flicker }
if not PBoxMoving then
begin
DestRect := Rect(0, 0, pbPasteBox.Width, pbPasteBox.Height);
SrcRect := Rect(0, 0, PasteBitmap.Width, PasteBitmap.Height);
pbPasteBox.Canvas.CopyRect(DestRect, PasteBitmap.Canvas, SrcRect);
end;
{ Now copy a bounding rectangle to indicate that pbPasteBox is
a moveable object. We use a pen mode of pmNotXOR because we
must erase this rectangle when the user copies PaintBox's
contents to the main image and we must preserve the original
contents. }
pbPasteBox.Canvas.Pen.Mode := pmNotXOR;
pbPasteBox.Canvas.Pen.Style := psDot;
pbPasteBox.Canvas.Brush.Style := bsClear;
pbPasteBox.Canvas.Rectangle(0, 0, pbPasteBox.Width, pbPasteBox.Height);
end;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
// Remove the form from the clipboard chain
ChangeClipBoardChain(Handle, OldClipViewHwnd);
PasteBitmap.Free; // Free the PasteBitmap instance
end;

procedure TMainForm.RgGrpFillOptionsClick(Sender: TObject);
begin
FillSelected := RgGrpFillOptions.ItemIndex = 0;
BorderSelected := cbxBorder.Checked;
SetDrawingStyle;
end;

procedure TMainForm.btnBorderClick(Sender: TObject);
begin
dlgColor.Execute;
pnlFgBgBorder.Color := dlgColor.Color;
SetDrawingStyle;
end;

procedure TMainForm.btnFillClick(Sender: TObject);
begin
dlgColor.Execute;
pnlFgBgInner.Color := dlgColor.Color;
SetDrawingStyle;
end;

end.


关键的几个函数是DrawToImage, 还有
procedure imgDrawingPadMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure imgDrawingPadMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure imgDrawingPadMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
这三个函数用来跟踪画图面板上的鼠标消息
在其中加入处理函数可以实现与画图程序一样的绘图效果
注意,procedure TMainForm.DrawToImage(TL, BR: TPoint; PenMode: TPenMode);
最后一个PenMode如果要实现动态绘制(即鼠标移到哪线就画到哪)
就必须用pmNotXor用来动态擦除再动态画上新的
而如果鼠标左键点下(代表确定要画在那),则要使用pmCopy把最终一条线画上去

Apr 3, 2009

UltraEdit中加入Delphi的语法高亮显示

很多人非常喜欢用UltraEdit写代码,其功能强大相信很多人都是有目共睹的

然而ultra edit本身没有提供delphi的关键字语法高亮

(pascal就这样悲剧的被忽略了)

只找到c/c++/java/vb/jsp/mysql/python/ruby等等等等

没关系,可以配置的

依次打开 高级--配置--编辑器显示--语法高亮

在‘词语列表完整路径’里默认指向UltraEdit的语法高亮配置文件

比如我的电脑上为

C:\Documents and Settings\wybin\Application Data\IDMComp\UltraEdit\WORDFILE.UEW

注意,某些版本中可能是txt格式

点击打开,打开该文件

在末尾加入以下代码。

注意,开头的/L14数字是可以改的,取决于你的UE上已经配置了多少个语法高亮文件

{--------------------Beginning of the codes, do not copy this line------------------------------ }

/L14"Delphi" Nocase Line Comment = // Block Comment On = { Block Comment On Alt = (* Block Comment Off = } Block Comment Off Alt = *) Escape Char = ?String Chars = ' File Extensions = pas dpr
/Delimiters = #$&'()*+,-./;<>@[]^{}
/Function String = "%^{procedure^}^{function^}"
/Indent Strings = "begin" "repeat" "asm"
/Unindent Strings = "end" "until"
/C1"Reserved words"
array asm
begin
case class const constructor
destructor dispinterface do downto
else end except exports
file finalization finally for function
goto
if implementation inherited initialization inline interface
label library
nil
object of out
packed procedure program property
raise record repeat resourcestring
set string
then threadvar to try type
unit until
uses
var
while with
/C2"Directives"
absolute abstract assembler automated
cdecl contains
default dispid dynamic
export external
far forward
implements index
message
name near nodefault
overload override
package pascal private protected public published
read readonly register reintroduce requires resident
safecall stdcall stored
virtual
write writeonly
/C3"Operators"
*
+
-
// /
< <= <>
=
> >=
@
and as
div
in is
mod
not
or
shl shr
xor
/C4"Special symbols"
#
$
&
(
(.
)
,
.
.)
..
:
:=
;
[
]
^

{------------------------End of the codes, do not copy this line------------------------------ }

保存,就可以高亮DELPHI的关键字了

Mar 7, 2009

【转】Delphi中常用VCL函数说明

BCB/Delphi中常用的VCL函数说明
说明,BCB,Delphi,C++Builder,内存分配,文件操作,磁盘目录管理,字符串操作,时间日期管理,类型转换

--------------------
内存分配
--------------------
函数名称:AllocMem
函数说明:在队中分配指定字节的内存块,并将分配的每一个字节初始化为 0.函数原型如下:
void * __fastcall AllocMem(Cardinal Size);

函数名称:SysFreeMem
函数说明:释放所指定的内存块.函数原型如下:
int __fastcall SysFreeMem(void * P);

函数名称:SysReallocMem
函数说明:要求重新分配参数Size所指定的内存.函数原型如下:
void * __fastcall SysReallocMem(void * P , int Size);

--------------------
文件操作
--------------------
函数名称:ChangeFileExt
函数说明:更改指定文件的扩展名,函数原型如下:
AnsiString __fastcall ChangeFileExt(const AnsiString FileName,const AnsiString Extension);

函数名称:DeleteFile
函数说明:在计算机磁盘中删除指定的文件,如果操作成功,则函数返回真,函数原型如下:
bool __fastcall DeleteFile(const AnsiString FileName);

函数名称:ExtractFileDir
函数说明:返回指定文件的工作目录,函数原型如下:
AnsiString __fastcall ExtractFileDir(const AnsiString FileName);

函数名称:ExtractFileDrive
函数说明:返回指定文件的驱动器,函数原型如下:
AnsiString __fastcall ExtractFileDrive(const AnsiString FileName);

函数名称:ExtractFileExt
函数说明:返回指定文件的扩展名,函数原型如下:
AnsiString __fastcall ExtractFileExt(const AnsiString FileName);

函数名称:ExtractFileName
函数说明:返回指定文件的文件名及扩展名,函数原型如下:
AnsiString __fastcall ExtractFileName(const AnsiString FileName);

函数名称:ExtractFilePath
函数说明:返回指定文件的工作路径,函数原型如下:
AnsiString __fastcall ExtractFilePath(const AnsiString FileName);

函数名称:FileAge
函数说明:返回指定文件的时间标签,如果操作失败,则返回-1,函数原型如下:
int __fastcall FileAge(const System::AnsiString FileName);

函数名称:FileClose
函数说明:关闭指定的文件,函数原型如下:
void __fastcall FileClose(int Handle);

函数名称:FileCreate
函数说明:以指定的文件名称创建一个新的文件,如果返回为正数,表示操作成功,返回值为文件句柄,如果返回值为-1,表示操作失败.函数原型如下:
int __fastcall FileCreate(const System ::AnsiString FileName);

函数名称:FileExists
函数说明:用于测试指定的文件是否存在,如果存在返回真,否则返回假,函数原型如下:
bool __fastcall FileExists(const System::AnsiString FileName);

函数名称:FileGetAttr
函数说明:返回指定文件的属性,如果操作失败,则函数返回-1,函数原型如下;
int __fastcall FileGetAttr(const System::AnsiString FileName);

函数名称:FileGetDate
函数说明:返回指定文件的DOS时间标签,如果操作失败,则近回-1,函数原型如下:
int __fastcall FileGetDate(int Handle);

函数名称:FileOpen
函数说明:打开指定的文件,如果返回为正数,表示操作成功,返回值为文件句柄:如果返回值为-1,表示操作失败,函数原型如下:
int __fastcall FileOpen(const System::AnsiString FileName,int Mode);

函数名称:FileRead
函数说明:从文件中读取指定字节的数据到缓冲区中,函数返回实际读取的字节数,函数原型如下;
int __fastcall FileRead(int Handle,void *Buffer,int Count);

函数名称:FileSeek
函数说明:调整文件指针到新的位置,如果操作成功,则返回新的文件位置,如果操作失败,则函数返回-1,函数原型如下:
int __fastcall FileSeek(int Handle,int Offset,int Origin);

函数名称:FileSetAttr
函数说明:更改指定文件的属性参数,如果操作成功,则返回0,函数原型如下;
int __fastcall FileSetAttr(const System::AnsiString FileName,int Attr);

函数名称:FileSetDate
函数说明:更改指定文件的DOS时间标签,如果操作成功,返回0,否则返回错误代码,函数原型如下:
int __fastcall FileSetDate(int Handle,int Age);

函数名称:FileWrite
函数说明:将缓冲区的数据写入到指定的文件的当前位置中去如果操作成功,函数返回实际写入的字节数,如果返回为-1,则表示操作产生错误,函数原型如下:
int __fastcall FileWrite(int Handle,const void *Buffer,int Count);

函数名称:FindClose
函数说明:释放FindFirst操作所申请的内存资源,函数原型如下:
void __fastcall FindClose(TSearchRec &F);

函数名称:FindFirst
函数说明:在指定的文件目录内,搜寻符合特定属性参数的文件,如果成功地查找到符合条件的文件,则函数返回0,否则函数返回一个错误代码,函数原型如下:
int __fastcall FindFirst(const System::AnsiString Path,int Attr,TSearchRec &F);

函数名称:FindNext
函数说明:继续搜寻FindFirst所指定属性参数的文件,如果成功地查找到符合条件的文件,则函数返回0,否则函数返回一个错误代码,函数原型如下:
int __fastcall FindNext(TSearchRec &F);
// 本文转自 C++Builder 研究 - http://www.ccrun.com/article.asp?i=983&d=22l01d

函数名称:RenameFile
函数说明:更改指定文件的名称,如果操作成功,则函数返回真,函数原型如下:
bool __fastcall RenameFile(const AnsiString OldName, const AnsiString NewName);

--------------------
磁盘目录管理
--------------------
函数名称:CreateDir
函数说明:创建新的目录,如果操作成功,返回真,否则返回假,函数原型如下:
bool __fastcall CreateDir(const AnsiString Dir);

函数名称:DiskFree
函数说明:返回指定磁盘的剩余空间,如果操作成功,返回剩余磁盘空间,如果操作失败,则返回-1,函数原型如下:
int __fastcall DiskFree(Byte Drive);

函数名称:DiskSize
函数说明:返回指定磁盘的空间,如果操作成功,返回磁盘空间,如果操作失败,则返回-1,函数原型如下:
int __fastcall DiskSize(Byte Drive);

函数名称:GetCurrentDir
函数说明:返回当前工作目录,函数原型如下:
AnsiString __fastcall GetCurrentDir();

函数名称:RemoveDir
函数说明:删除指定的目录,如果操作成功,返回真,否则返回假,函数原型如下:
bool __fastcall RemoveDir(const AnsiString Dir);

函数名称:SetCurrentDir
函数说明:设置当前工作目录,如果操作成功,则返回真,函数原型如下:
bool __fastcall SetCurrentDir(const AnsiString Dir);

--------------------
字符串操作
--------------------
函数名称:CompareStr
函数说明:比较两个AnsiString字符串,函数原型如下:
int __fastcall CompareStr(const AnsiString S1, const AnsiString S2);

函数名称:CompareText
函数说明:比较两个AnsiString字符串,函数原型如下:
int __fastcall CompareText(const AnsiString S1, const AnsiString S2);

函数名称:LowerCase
函数说明:将指定的AnsiString字符串转换为小写形式,函数原型如下:
AnsiString __fastcall LowerCase(const AnsiString S);

函数名称:StrAlloc
函数说明:为字符串分配指定字节的内存,并返回内存指针,函数原型如下:
char * __fastcall StrAlloc(Cardinal Size);

函数名称:StrBufSize
函数说明:返回*Str所指向内存的大小,函数原型如下:
Cardinal __fastcall StrBufSize(const char * Str);

函数名称:StrCat
函数说明:连接两个字符串,并返回目的字符串指针,函数原型如下:
char * __fastcall StrCat(char * Dest, const char * Source);

函数名称:StrComp
函数说明:两个字符串相到比较,返回比较的结果,函数原型如下:
int __fastcall StrComp(const char * Str1, const char * Str2);

函数名称:StrCopy
函数说明:将源字符串拷贝到目的字符串中,函数原型如下:
char * __fastcall StrCopy(char * Dest, const char * Source);

函数名称:StrECopy
函数说明:将源字符串拷贝到目的字符串中,并返回目的字符串结尾指针,函数原型如下:

char * __fastcall StrECopy(char * Dest, const char * Source);

函数名称:StrEnd
函数说明:返回字符串结尾指针,函数原型如下:
char * __fastcall StrEnd(const char * Str);

函数名称:StrIComp
函数说明:两个字符串相互比较(不论大小写),返回比较的结果,函数原型如下:
int __fastcall StrIComp(const char * Str1, const char * Str2);

函数名称:StrLCat
函数说明:将指定数目的源字符串连接到目的字符串,并返回目的字符串指针,函数原型如下:
char * __fastcall StrLCat(char * Dest, const char * Source, Cardinal MaxLen);

函数名称:StrLComp
函数说明:对两个字符串指定数目的字符进行比较操作,函数原型如下:
int __fastcall StrLComp(const char * Str1, const char * Str2, Cardinal MaxLen);

函数名称:StrLCopy
函数说明:将源字符串指定数目的字符拷贝到目的字符串中,并返回目的字符串指针,函数原型如下:
char * __fastcall StrLCopy(char * Dest, const char * Source, Cardinal MaxLen);

函数名称:StrLen
函数说明:返回字符串的长度,函数原型如下:
Cardinal __fastcall StrLen(const char * Str);

函数名称:StrLower
函数说明:将字符串转换为小写形式,函数原型如下:
char * __fastcall StrLower(char * Str);

函数名称:StrMove
函数说明:从源字符串向目的字符串拷贝指定数目的字符,函数原型如下:
char * __fastcall StrMove(char * Dest, const char * Source, Cardinal Count);

函数名称:StrNew
函数说明:在堆中为指定字符串分配空间,并将字符串拷贝到此空间中,函数原型如下:
char * __fastcall StrNew(const char * Str);

函数名称:StrPas
函数说明:将指定的字符串转换为AnsiString类型字符串对象,函数原型如下:
AnsiString __fastcall StrPas(const char * Str);

函数名称:StrPCopy
函数说明:将AnsiString类型的源字符串拷贝到目的字符串中,并返回目的字符串指针,函数原型如下:
char * __fastcall StrPCopy(char * Dest, const AnsiString Source);

函数名称:StrPLCopy
函数说明:将源字符串(AnsiString类型)指定数目的字符拷贝到目的字符串中,并返回目的字符串指针,函数原型如下:
char * __fastcall StrPLCopy(char * Dest, const AnsiString Source, Cardinal MaxLen);

函数名称:StrPos
函数说明:在Strl所指定的字符串中寻找Str2所指定的子字符串,并返回Str2在Str2中第一个子字符的指针,函数原型如下:
char * __fastcall StrPos(const char * Str1, const char * Str2);

函数名称:StrRScan
函数说明:在指定的字符串中寻找特定的字符,并返回字符串中最后一个特定字符的指针,函数原型如下:
char * __fastcall StrRScan(const char * Str, char Chr);

函数名称:StrScan
函数说明:在指定的字符串中寻找特定的字符,并返回字符串中第一个特定字符的指针,函数原型如下:
char * __fastcall StrScan(const char * Str, char Chr);

函数名称:StrUpper
函数说明:将字符串转换为大写形式,函数原型如下:
char * __fastcall StrUpper(char * Str);

函数名称:UpperCase
函数说明:将指定的AnsiString字符串转换为大写形式,函数原型如下:
AnsiString __fastcall UpperCase(const AnsiString S);

--------------------
类型转换
--------------------
函数名称:FloatToStr
函数说明:将浮点数转换为AnsiString字符串,函数原型如下:
AnsiString __fastcall FloatToStr(Extended Value);

函数名称:FloatToStrF
函数说明:将浮点数转换为指定格式的AnsiString字符串,函数原型如下:
AnsiString __fastcall FloatToStrF(Extended Value, TFloatFormat Format,int Precision, int Digits);

函数名称:IntToHex
函数说明:将整数转换为十六进制字符串,函数原型如下:
AnsiString __fastcall IntToHex(int Value, int Digits);

函数名称:IntToStr
函数说明:将整数转换为AnsiString字符串,函数原型如下:
AnsiString __fastcall IntToStr(int Value);

函数名称:StrToFloat
函数说明:将AnsiString字符串转换为一个浮点数值,函数原型如下:
Extended __fastcall StrToFloat(const AnsiString S);

函数名称:StrToInt
函数说明:将AnsiString字符串转换为整数值,如果不能进行转换,则产生EConvertError异常,函数原型如下:
int __fastcall StrToInt(const AnsiString S);

函数名称:StrToIntDef
函数说明:将AnsiString字符串转换为一个数值,函数原型如下:
int __fastcall StrToIntDef(const System::AnsiString S,int Default);

--------------------
时间日期管理
--------------------
函数名称:Date
函数说明:返回TDateTime对象,包含当前的年月日信息,函数原型如下:
System::TDateTime __fastcall Date(void);

函数名称:DateTimetoStr
函数说明:将TDateTime对象转换为字符串对象,函数原型如下:
AnsiString __fastcall DateTimeToStr(System::TDateTime DateTime);

函数名称:DatetimeToString
函数说明:将TDateTime对象转换为指定格式的字符串对象,函数原型如下:
void __fastcall DateTimeToString(AnsiString &Result, const AnsiString Format,System::TDateTime DateTime);

函数名称:DateTimeToSystemTime
函数说明:将TDateTime对象转换为操作系统时间,函数原型如下:
void __fastcall DateTimeToSystemTime( System::TDateTime DateTime, _SYSTEMTIME &SystemTime);

函数名称:DateToStr
函数说明:将TDateTime对象(包含当前年月日信息)转换为字符串对象,函数原型如下:
AnsiString __fastcall DateToStr(System::TDateTime Date);

函数名称:Now
函数说明:返回TDateTime对象,获取当前的日期和时间信息,函数原型如下:
System::TDateTime __fastcall Now(void);

函数名称:StrToDate
函数说明:将字符串对象转换为年月日对象,函数原型如下:
System::TDateTime __fastcall StrToDate(const AnsiString S);

函数名称:StrToDateTime
函数说明:将字符串对象转换为年月日时间对象,函数原型如下:
System::TDateTime __fastcall StrToDateTime(const AnsiString S);

函数名称:StrToTime
函数说明:将字符串对象转换时间对象,函数原型如下:
System::TDateTime __fastcall StrToTime(const AnsiString S);

函数名称:SystemTimeToDateTime
函数说明:将操作系统时间转换为TDateTime对象,函数原型如下:
System::TDateTime __fastcall SystemTimeToDateTime(const _SYSTEMTIME &SystemTime);

函数名称:Time
函数说明:返回TDateTime对象,包含当前的时间信息,函数原型如下:
System::TDateTime __fastcall Time(void);

函数名称:TimeToStr
函数说明:将当前日期转换为字符串对象,函数原型如下:
AnsiString __fastcall TimeToStr(System::TDateTime Time);


本文档是ccrun(老妖)根据网上资料整理而成。

Delphi中属性的使用(unit2)

unit Unit2;

interface

uses
Windows, Messages, SysUtils, Variants, Classes;

type
// 基类employee
employee=class
protected
name:string; // 姓名
empno:string; // 雇员号
accumpay:real;// 月薪
public
constructor create();// 构造函数
Procedure pay(); Virtual; // 计算月薪函数(虚拟方法)
Procedure displaystatus(); Virtual;// 显示信息函数(虚拟方法)
end;

//技术员类technician
technician=class(employee)
private
hrRate:string;//每小时酬金
hr:string; //当月工作时数
function GetHourlyRate():string;
procedure SetHourlyRate(Value: string);
function GetWorkHours():string;
procedure SetWorkHours(Value: string);

public
property MyHourlyRate: string read GetHourlyRate write SetHourlyRate;
property MyWorkHours: string read GetWorkHours write SetWorkHours;
Procedure pay(); override; //计算月薪函数(覆盖基类中同名方法)
Procedure displaystatus();override; //显示信息函数(覆盖基类中同名方法)
end;

//销售员类(派生于employee)
salesman=class(employee)
private
comm:string;//提取销售额的百分比
sale:string;//销售额
function GetCommrateRate():string;
procedure SetCommrateRate(Value: string);
function GetSales():string;
procedure SetSales(Value: string);
public
property MyCommRate: string read GetCommrateRate write SetCommrateRate;
property MySales: string read GetSales write SetSales;
Procedure pay(); override; //计算月薪函数(覆盖基类中同名方法)
Procedure displaystatus(); override; //显示信息函数(覆盖基类中同名方法)
end;

var
tech: technician;
sales: salesman;
name1,number,result1: string;

implementation
//employee类的函数实现
constructor employee.create();
begin
name:=name1; // name1为存放雇员姓名的全局变量
empno:=number; // number为存放雇员号的全局变量
accumpay:=0.0;
end;

Procedure employee.pay();
begin
end;

Procedure employee.displaystatus();
begin
end;

//技术员类的函数实现
Procedure technician.pay();
begin
accumpay:=strtofloat(GetHourlyRate)*strtofloat(GetWorkHours);
end;

Procedure technician.displaystatus();
begin
result1:=empno+'号技术员'+name+'的本月工资为 '+floattostr(accumpay);
end;
//技术员工资结算
function technician.GetHourlyRate(): string;
begin
GetHourlyRate:=hrRate;
end;
procedure technician.SetHourlyRate(Value: string);
begin
hrRate:=Value;
end;
function technician.GetWorkHours(): string;
begin
GetWorkHours:=hr;
end;
procedure technician.SetWorkHours(Value: string);
begin
hr:=value;
end;

//销售员类的函数实现
Procedure salesman.pay();
begin
accumpay:=strtofloat(GetCommrateRate)*strtofloat(GetSales);
end;

Procedure salesman.displaystatus();
begin
result1:=empno+'号销售员'+name+'的本月工资为 '+floattostr(accumpay);
end;
//销售人员工资结算
function salesman.GetCommrateRate(): string;
begin
GetCommrateRate:=comm;
end;
procedure salesman.SetCommrateRate(Value: string);
begin
comm:=value;
end;
function salesman.GetSales(): string;
begin
GetSales:=sale;
end;
procedure salesman.SetSales(Value: string);
begin
sale:=value;
end;

end.

Delphi中属性的使用(unit1)

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons;

type
TForm1 = class(TForm)
Label1: TLabel;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
tch: TGroupBox;
sls: TGroupBox;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
jsyno: TEdit;
jsyxm: TEdit;
hours: TEdit;
Label5: TLabel;
xsyno: TEdit;
Label6: TLabel;
xsyxm: TEdit;
xsl: TEdit;
Label7: TLabel;
Label8: TLabel;
result: TEdit;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
lblHrRate: TLabel;
edtHrRate: TEdit;
lblComm: TLabel;
edtComm: TEdit;
GroupBox3: TGroupBox;
procedure BitBtn1Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ResetTech(flag: boolean); //设置只读属性
procedure ResetSale(flag: boolean);
procedure RadioButton1Click(Sender: TObject);
procedure RadioButton2Click(Sender: TObject); //flag标志着只读属性,true则只读,false则可修改
procedure SetEmptyTech();
procedure SetEmptySale();
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses Unit2;
{$R *.dfm}

procedure TForm1.BitBtn1Click(Sender: TObject);
var
t1: technician;
s1: salesman;
begin
if RadioButton1.Checked =true then
begin
// 计算技术员的月薪
number:=jsyno.Text ;
name1:= jsyxm.Text ;
t1:=technician.create ();
t1.MyHourlyRate := edtHrRate.Text;
t1.MyWorkHours := hours.Text;
t1.pay ();
t1.displaystatus ();
end
else begin
// 计算销售员的月薪
number:= xsyno.Text ;
name1:= xsyxm.Text ;
s1:=salesman.create ();
s1.MySales := xsl.Text;
s1.MyCommRate := edtComm.Text;
s1.pay ();
s1.displaystatus ();
end;
// 将信息显示在result文本框中
SetEmptyTech();
SetEmptySale();
result.Text :=result1;
end;

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
form1.Close;
end;

procedure TForm1.ResetTech(flag: boolean); //根据radio button选择情况设置各输入组的只读情况
begin
if flag = true then
begin
jsyno.ReadOnly := true;
jsyxm.ReadOnly := true;
hours.ReadOnly := true;
edtHrRate.ReadOnly := true;
jsyno.Enabled := false;
jsyxm.Enabled := false;
hours.Enabled := false;
edtHrRate.Enabled := false;
end
else begin
jsyno.ReadOnly := false;
jsyxm.ReadOnly := false;
hours.ReadOnly := false;
edtHrRate.ReadOnly := false;
jsyno.Enabled := true;
jsyxm.Enabled := true;
hours.Enabled := true;
edtHrRate.Enabled := true;
end;
end;

procedure TForm1.ResetSale(flag: boolean);
begin
if flag = true then
begin
xsyno.ReadOnly := true;
xsyxm.ReadOnly := true;
xsl.ReadOnly := true;
edtComm.ReadOnly := true;
xsyno.Enabled := false;
xsyxm.Enabled := false;
xsl.Enabled := false;
edtComm.Enabled := false;
end
else begin
xsyno.ReadOnly := false;
xsyxm.ReadOnly := false;
xsl.ReadOnly := false;
edtComm.ReadOnly := false;
xsyno.Enabled := true;
xsyxm.Enabled := true;
xsl.Enabled := true;
edtComm.Enabled := true;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
if RadioButton1.Checked =true then//选中了技术员
begin
ResetTech(false); //将技术员的只读属性设置为false
ResetSale(true);//将销售员的只读属性设置为true
end
else begin
ResetTech(true); //将技术员的只读属性设置为true
ResetSale(false);//将销售员的只读属性设置为false
end;
end;

procedure TForm1.RadioButton1Click(Sender: TObject);
begin
ResetTech(false); //将技术员的只读属性设置为false
ResetSale(true);//将销售员的只读属性设置为true
end;

procedure TForm1.RadioButton2Click(Sender: TObject);
begin
ResetTech(true); //将技术员的只读属性设置为true
ResetSale(false);//将销售员的只读属性设置为false
end;

procedure TForm1.SetEmptySale;
begin
xsyno.Text := '';
xsyxm.Text := '';
xsl.Text := '';
edtComm.Text := '';
end;

procedure TForm1.SetEmptyTech;
begin
jsyno.Text := '';
jsyxm.Text := '';
hours.Text := '';
edtHrRate.Text := '';
end;

end.
Powered By Blogger