Google

星期二, 一月 06, 2009

[学习]Delphi控制并行端口位操作

并行端口简称并口,它有3个端口:数据端口、状态端口、控制端口,常用的并口为LPT1,它的3个端口的地址分别为:378H、379H和37AH。

  一、并口读写

  在汇编语言中,可以用 in、out 指令操作并口,而在Delphi中并没有相对应的函数、方法可对并口进行读写,幸运的是Delphi可以嵌入汇编程序,通过直接嵌入汇编指令 in、out 可方便地对并口进行读写。我们还可以通过调用 Windows API 函数或第三方提供的DLL、VXD来访问并口,但通过使用嵌入汇编的方法对并口进行读写更方便、快捷。

  使用下面的 ReadPort 函数和 WritePort 过程可以读写并口,参数 Port 为要操作的端口地址。

function ReadPort(Port:WORD):BYTE;

var

B:BYTE;

begin

ASM

MOV DX, Port;

IN AL, DX;

MOV B, AL;

END;

Result:=B;

end;

procedure WritePort(Port:WORD;ConByte:BYTE);

begin

ASM

MOV DX, Port;

MOV AL, ConByte;

OUT DX, AL;

END;

end;

二、位操作

  要按位来控制并口,可以先读取并口的数据,再进行位操作,最后再重新写入并口,就可以实现对并口的位的控制。

  逻辑运算符and对两个要操作的数执行按位的逻辑与运算:即中有1“与”1的结果为1,其它的0“与”1、1“与”0、0“与”0的结果都为0。

  逻辑运算符or对两个要操作的数执行按位的逻辑或运算:即只要相“或”的两位有一位是1,结果就为1;否则“或”的结果为0。


  使用and运算符可以对指定的位置0,例如:十六进制84H的二进制为:10000100,它的第三位为1,若要将第三位置为0,且其它位不变,可以使用:$84 and $FB = $80,80H的二进制值为10000000。

  使用or运算符可以对指定的位置1,例如:十六进制84H的第二位为0,若要将第二位置为1,且其它位不变,可以使用:$84 or $02 = $86,86H的二进制值为10000110。

  例子:

  1、将数据端口378H的D2位的电位设置为低,即置0:

B:=ReadPort($378);

B:=B and $FB;

WritePort($378,B);

  2、将数据端口378H的D2位的电位设置为高,即置1:

B:=ReadPort($378);

B:=B or $04;

WritePort($378,B);

  3、判断数据端口378H的D2位的电位高低:

B:=ReadPort($378);

if ((B and $04)=$04) then

//电位为高时的代码

else

//电位为低时的代码

或:

B:=ReadPort($378);

if ((B or $FB)=$FF) then

//电位为高时的代码

else

//电位为低时的代码

  三、具体实现

  下面的例子是控制并口的数据端口378H的各个位的电位高低。数据端口的8个位:D0~D7分别对应并行接口的2~9脚,关于并行接口其它的引脚的说明就查看相关资料,这里就不多说了。

  首先运行 Delphi,新建一个工程,按一下F12在Form1的单元文件Unit1中加入读写端口的代码:

function ReadPort(Port:WORD):BYTE;

procedure WritePort(Port:WORD;ConByte:BYTE);

function ReadPort(Port:WORD):BYTE;

var

B:BYTE;

begin

ASM

MOV DX, Port;

IN AL, DX;

MOV B, AL;

END;

Result:=B;

end;

procedure WritePort(Port:WORD;ConByte:BYTE);

begin

ASM

MOV DX, Port;

MOV AL, ConByte;

OUT DX, AL;

END;

end;


  添加8个 CheckBox 组件,修改它们的 Caption(标题)属性分别为 D0 到 D7 ,将它们按右到左进行排列好。

  双击 CheckBox1,在CheckBox1组件的OnClick(单击)事件中加入以下的程序代码:

procedure TForm1.CheckBox1Click(Sender: TObject);

var

b:BYTE;

begin

b:=0;

if CheckBox1.Checked then

b:=b or $01;

if CheckBox2.Checked then

b:=b or $02;

if CheckBox3.Checked then

b:=b or $04;

if CheckBox4.Checked then

b:=b or $08;

if CheckBox5.Checked then

b:=b or $10;

if CheckBox6.Checked then

b:=b or $20;

if CheckBox7.Checked then

b:=b or $40;

if CheckBox8.Checked then

b:=b or $80;

WritePort($378,b); //写数据端口

end;


  输入完成后,把CheckBox2到CheckBox8这7个CheckBox组件的OnClick事件设置为CheckBox1的OnClick事件:CheckBox1Click。

  此时编译运行程序,已经可以通过点击这8个CheckBox来控制LPT1的数据端口的各个位的电位高低了。

  下面再加入监控并口的数据端口状态的功能。

  在Form1中加入一个Timer组件:Timer1,修改它的Enabled属性为False,Interval属性为1。

  在Timer1的OnTimer事件中加入:

procedure TForm1.Timer1Timer(Sender: TObject);

var

B:BYTE;

begin

B:=ReadPort($378); //读数据端口

CheckBox1.Checked:=((B or $FE)=$FF);

CheckBox2.Checked:=((B or $FD)=$FF);

CheckBox3.Checked:=((B or $FB)=$FF);

CheckBox4.Checked:=((B or $F7)=$FF);

CheckBox5.Checked:=((B or $EF)=$FF);

CheckBox6.Checked:=((B or $DF)=$FF);

CheckBox7.Checked:=((B or $BF)=$FF);

CheckBox8.Checked:=((B or $7F)=$FF);

end;


  再加入一个CheckBox组件,修改的Caption属性为“监控并口”,并在它的OnClick事件中加入:

procedure TForm1.CheckBox9Click(Sender: TObject);

begin

Timer1.Enabled:=CheckBox9.Checked;

end;


  编译运行程序,点击“监控并口”,就可以监控并口LPT1数据端口378H的状态,并可以实时地修改它的状态。

  为了方便查看、验证数据端口378H的状态,我做了一个小小的并口测试电路,该电路使用了一个打印接口、8个LED(发光二极管)和8个1K的电阻,连接线路如图所示:




  按照电路图制作完成后,安装到电脑的并口上,运行编写好的程序就可以方便地查看数据端口378H的各个位的电位高低了。

  最后,我们再来做一个走马灯实验。

  先声明一个全局变量 tb:在“Form1:TForm1”的下面加上“tb:BYTE”:

var

Form1: TForm1;

tb:BYTE;

  再在Form1中加入一个Timer和一个CheckBox,修改Timer2的Enabled属性为False,修改Interval属性为300,双击Timer2,在它的OnTimer事件中加入:

procedure TForm1.Timer2Timer(Sender: TObject);

var

B:BYTE;

begin

if tb=0 then

tb:=1

else

tb:=tb * 2;

WritePort($378,tb);

B:=ReadPort($378);

CheckBox1.Checked:=((B or $FE)=$FF);

CheckBox2.Checked:=((B or $FD)=$FF);

CheckBox3.Checked:=((B or $FB)=$FF);

CheckBox4.Checked:=((B or $F7)=$FF);

CheckBox5.Checked:=((B or $EF)=$FF);

CheckBox6.Checked:=((B or $DF)=$FF);

CheckBox7.Checked:=((B or $BF)=$FF);

CheckBox8.Checked:=((B or $7F)=$FF);

end;

  修改CheckBox10的Caption属性为“走马灯演示”,再双击CheckBox10,在它OnClick事件中加入:

procedure TForm1.CheckBox10Click(Sender: TObject);

begin

Timer2.Enabled:=CheckBox10.Checked;

end;


  编译运行程序。




  点击“走马灯演示”,有没有看到“走马灯”的效果?通过修改Timer2的Interval可以调节速度,更多、更Cool的效果就看你的创意了。

  注意:以上嵌入汇编访问并口的方法只能在Win9X下使用,若要在WinNT/2K下访问并口应该使用 Windows API 函数或专门读写并口的DLL、VXD。

  以上程序在Win98+Delphi6.0下测试通过

http://www.yesky.com/20020801/1623061_1.shtml

标签: , ,

星期二, 十二月 30, 2008

How to set menu item right justified?

1. I have a menu M with M.OwnerDraw=false set at design-time.
2. Also at design-time, a menu item MI, belonging to a sub-sub-menu of M,
has
MI.OnAdvancedDrawItem set to an event handler procedure.
3. At run-time, in the form's OnCreate event handler, I try to modify MI's
fType flag as follows
-----------------------------
var mii : TMenuItemInfo;
begin
FillChar (mii, SizeOf (TMenuItemInfo), #0);
mii.cbSize := SizeOf (TMenuItemInfo);
mii.fMask := MIIM_TYPE;
GetMenuItemInfo (MI.Parent.Handle, MI.Command, false, mii);
mii.fType := mii.fType or MFT_OWNERDRAW;
SetMenuItemInfo (MI.Parent.Handle, MI.Command, false, mii);
end;
-----------------------------
4. When I open the menu and hover the mouse cursor till MI, the execution
doesn't enter the MI.OnAdvancedDrawItem code and MI is drawn in the default
Windows manner.

There must be something wrong in my above MFT_OWNERDRAW setting.
So, I am looking for a sample code which could let me to pinpoint my error.

Jacek

http://delphi.newswhat.com/geoxml/forumhistorythread?groupname=borland.public.delphi.rtl.win32&messageid=438ba88a@newsgroups.borland.com

标签: ,

[学习]DelphiZeus 9. 菜单和列表框--3

procedure CopyMenuItem;
begin
{这个过程将通过 GetMenuItemInfo 获取菜单项设置并在 menuListB2 最后一个菜单项
复制一次。}
MenuInfo.cbSize := SizeOf(MenuInfo);
MenuInfo.dwTypeData := @CharBuffer[0];
{给 MenuInfo.dwTypeData 赋值一个内存区域}
MenuInfo.cch := 256;
{由于使用 GetMenuItemInfo 获取一个字符串,你需要设置 MenuInfo.cch 。}
MenuInfo.fMask := MIIM_STATE or MIIM_ID or MIIM_TYPE or MIIM_DATA or
MIIM_SUBMENU or MIIM_CHECKMARKS;
{留个标志全部使用,这样不管菜单项是字符串、分隔符、子菜单还是位图,这将得到所有的设置。}
GetMenuItemInfo(menuFile, CopyNum, False, MenuInfo);
{GetMenuItemInfo 将放置所有菜单项的设置到 MenuInfo 里面,包括类型与状态。}
SetMenuItemInfo(menuListB2, 6, True, MenuInfo);
{SetMenuItemInfo 将复制 menuFile 的所有菜单项的设置到 menuListB2 菜单的 MenuInfo 。}
if CopyNum < stresult =" $FFFFFFFF" stresult =" StResult" fstate =" MenuInfo.fState" wparam =" 901" wparam =" 902" lparam =" 0"> 2 then
begin
if CFolder[Length(CFolder)] <> '\' then
CFolder := CFolder + '\';
if DirectoryExists(CFolder) then
begin
GetShortPathName(@Cfolder[1], Buffer, 82);
Cfolder := Buffer + '*.*';
SendMessage(hListBox1, LB_RESETCONTENT, 0, 0);
SendMessage(hListBox1, LB_DIR, DDL_READONLY or DDL_DIRECTORY,
Integer(PChar(CFolder)))
end
else
MessageBox(hForm1, '文件夹不存在', '无文件夹',
MB_OK or MB_ICONERROR);
end;
end;
mID_m2AddSel: SelToLB3(True);
mID_m2Clear: SendMessage(hListBox1, LB_RESETCONTENT, 0, 0);
mID_m2ChangeItem:
begin
{这里使用 SetMenuItemInfo 函数立即改变几个菜单项属性}
MenuInfo.cbSize := SizeOf(MenuInfo);
MenuInfo.fMask := MIIM_STATE;
GetMenuItemInfo(menuListB1, 205, False, MenuInfo);
if MenuInfo.fState = MenuInfo.fState or MFS_CHECKED then
begin
MenuInfo.fMask := MIIM_STATE or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.fState := MFS_UNCHECKED;
MenuInfo.dwTypeData := '旧的 菜单项';
end
else
begin
MenuInfo.fMask := MIIM_STATE or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.fState := MFS_CHECKED or MFS_GRAYED;
MenuInfo.dwTypeData := '新的 菜单项';
end;
SetMenuItemInfo(menuListB1, 205, False, MenuInfo);
{这里 SetMenuItemInfo 改变菜单项的三个属性:勾选、文本与变灰。}
Returned := GetMenuDefaultItem(menuListB1, 0, 0);
{如果没有默认菜单项则返回 4294967295 = $FFFFFFFF}
SetWindowText(hEdit1, PChar(Int2Str(Returned)));
end;
mID_m2Item: DoMessage;
{上面的所有菜单项 ID 使用常量名代替了。下面会直接使用菜单项的 ID 编号,
这样知道 ID 代表哪个菜单和哪个菜单项比较困难,这里使用百位数(301,401,
501)来表示不同的子菜单,但是你需要参照菜单创建部分了解数字(如 302)
表示哪个菜单项。使用菜单项 ID 的常量是比较好的做法,采用命名约定如
mID_m1New、mID_m2NewFolder,m1 和 m2 分辨表示子菜单1 和子菜单2 。}
301:
begin
CFolder := GetWindowStr(hEdit1);
if Length(CFolder) > 2 then
begin
if CFolder[Length(CFolder)] <> '\' then
CFolder := CFolder + '\';
if DirectoryExists(CFolder) then
GetFiles(Cfolder)
else
MessageBox(hForm1, '文件夹不存在', '无文件夹',
MB_OK or MB_ICONERROR);
end;
end;
302: SelToLB3(False);
303: SendMessage(hListBox2, LB_RESETCONTENT, 0, 0);
304: CopyMenuItem;
401..402: SortListBox;
403: SendMessage(hListBox3, LB_RESETCONTENT, 0, 0);
404: if MenuCheck(3, 4) = 0 then
SetWindowText(hEdit1, 'It was Checked');
405:
begin
RemoveMenu(MenuMain, 3, MF_BYPOSITION);
{RemoveMenu 将移除菜单项但是不销毁子菜单}
EnableMenuItem(menuFile, mID_m1Show, MF_BYCOMMAND or MF_ENABLED);
{"文件"菜单的"显示菜单"菜单项将可用}
DrawMenuBar(hForm1);
{DrawMenuBar 将重绘主菜单来显示变化}
end;
501: DoMessage;
502: MoveWindow(hWnd, 1, 1, Rect1.Right - Rect1.Left, Rect1.Bottom -
Rect1.Top, True);
503: MessageBox(hForm1, About, '关于', MB_OK or
MB_ICONINFORMATION);
504: PostMessage(hForm1, WM_CLOSE, 0, 0);
701..765:
begin
{ID 编号 701 到 765 是在 menuSubFolder1 中为 C 盘文件夹准备}
GetMenuStr(True);
Cfolder := 'C:\' + MenuInfo.dwTypeData;
GetShortPathName(@Cfolder[1], Buffer, 82);
Cfolder := Buffer + '\*.*';
if MessageBox(hForm1,
PChar('你希望显示'+ MenuInfo.dwTypeData + ' 内的文件和文件夹? ?'),
MenuInfo.dwTypeData, MB_YESNO or MB_ICONQUESTION) = IDYES then
begin
SendMessage(hListBox1, LB_RESETCONTENT, 0, 0);
SendMessage(hListBox1, LB_DIR, DDL_READONLY or DDL_DIRECTORY,
Integer(@Cfolder[1]));
end;
end;
801..865:
begin
{ID 编号 801 到 865 是在 menuSubFolder2 中为 C 盘文件夹准备}
GetMenuStr(False);
Cfolder := 'C:\' + MenuInfo.dwTypeData + '\';
DlgChk := True;
GetFiles(Cfolder);
end;
end; // case LOWORD(wParam)
end;
WM_INITMENUPOPUP: if wParam = menuSubFolder2 then
begin
{在子菜单显示前会发送 WM_INITMENUPOPUP 消息,你可以修改这个子菜单使之
在显示前符合要求。}
SetSubMenu(wParam);
end
else if wParam = hSysMenu then
SetWindowText(hEdit1, PChar('系统菜单 lParam 为 ' + Int2Str(lParam)));
WM_CTLCOLORLISTBOX: if lParam = hListBox3 then
begin
{WM_CTLCOLORLISTBOX 获取列表框使用的颜色}
SetTextColor(wParam, $0000FF);
SetBkColor(wParam, $FFFF00);
Result := GetStockObject(LTGRAY_BRUSH);
Exit;
end;
WM_DESTROY: ShutDown;
end; // case Msg
Result := DefWindowProc(hWnd, Msg, wParam, lParam);
end;

begin // * * * * * * * 主程序开始
CopyNum := mID_m1New;
wClass.hInstance := hInstance;
with wClass do
begin
Style := 0;
hIcon := LoadIcon(hInstance, 'MAINICON');
lpfnWndProc := @MessageFunc;
hbrBackground := COLOR_BTNFACE + 1;
lpszClassName := 'Text Class';
hCursor := LoadCursor(0, IDC_ARROW);
cbClsExtra := 0;
cbWndExtra := 0;
lpszMenuName := nil;
end;
RegisterClass(wClass);
{这里将在创建主菜单之前创建菜单栏的子菜单,因为它们必须被加入主菜单。第一个子
菜单为"文件"菜单,但是本程序不涉及任何文件操作,因此这个子菜单仅仅用于演示。}
menuFile := CreateMenu;
{CreateMenu 函数将创建一个空菜单,在使用前必须加入菜单项。这里使用了三个函数
添加菜单项:AppendMenu、 InsertMenu 和 InsertMenuItem 。}
{这个 menuFile 菜单将使用 AppendMenu 添加菜单项,它有四个参数。第三个参数
uIDNewItem 是 ID 编号,它将在菜单单击时通过 WM_COMMAND 消息的 LOWORD(wParam)
发送。AppendMenu 按照调用次序顺次添加菜单项,类似于 Delphi 的"Add" 过程。}
AppendMenu(menuFile, MF_STRING, mID_m1New, '&N新建');
AppendMenu(menuFile, MF_STRING or MF_GRAYED, mID_m1Open, '&O打开');
AppendMenu(menuFile, MF_STRING or MF_CHECKED, mID_m1Save, '&S保存');
{MF_CHECKED 将会勾选菜单项}
AppendMenu(menuFile, MF_STRING, mID_m1SaveAs, '另存为(&A)');
AppendMenu(menuFile, MF_STRING or MF_GRAYED, mID_m1Show, '显示菜单');
AppendMenu(menuFile, MF_SEPARATOR, 1, nil);
{MF_SEPARATOR 将在菜单中添加分隔线,后两个参数不使用}
AppendMenu(menuFile, MF_STRING, mID_m1Exit, 'E&退出');
{MF_STRING 参数将会添加文本菜单项,MF_BITMAP 参数将会添加位图,MF_OWNERDRAW
将会指定一个自定义绘制的菜单项。}
EnableMenuItem(menuFile, mID_m1New, MF_GRAYED);
{这里使用 EnableMenuItem 使"新建"菜单项变灰并禁用它,"打开"菜单也会变灰,因为
它使用了 MF_GRAYED 参数。}
SetMenuDefaultItem(menuFile, mID_m1Exit, 0);
{SetMenuDefaultItem 将会使默认菜单项变粗显示,在双击菜单时会执行此默认菜单项。}
menuSubFolder1 := CreateMenu();
{menuSubFolder1 是在后面创建的 menuListB1 的子菜单。这个 menuSubFolder1 将会
在程序运行时列出 C:\ 盘的所有文件夹。}
SetSubMenu(menuSubFolder1);
{SetSubMenu 只在创建永不更新的 menuSubFolder1 过程中使用,menuSubFolder2 则是
每次子菜单显示的时候都更新。}
menuListB1 := CreateMenu;
{menuListB1 将使用 AppendMenu 添加菜单项。另一个菜单项将在最后使用 InsertMenu
不按照前面的次序添加。}
AppendMenu(menuListB1, MF_STRING, mID_m2NewFolder, '&N编辑框指定的新文件夹');
AppendMenu(menuListB1, MF_STRING, mID_m2AddSel, '加入所选项列表框3 ');
AppendMenu(menuListB1, MF_STRING, mID_m2Clear, '清空');
AppendMenu(menuListB1, MF_SEPARATOR, 1, nil);
AppendMenu(menuListB1, MF_STRING, mID_m2ChangeItem, '改变 菜单项');
AppendMenu(menuListB1, MF_STRING, mID_m2Item, '菜单项');
{下面的 InsertMenu( ) 将在菜单的第二个位置放置一个子菜单项。uPosition 为 1,
如果 Count 大于 0,你不能为空的菜单项添加子菜单。}
if Count > 0 then
InsertMenu(menuListB1, 1, MF_BYPOSITION or MF_POPUP or MF_STRING,
menuSubFolder1, 'C 盘文件夹');
{使用 MF_POPUP 标志在 menuListB1 添加一个子菜单,句柄在第四个参数。}
menuSubFolder2 := CreateMenu();
{这里创建的 menuSubFolder2 只有一个菜单项,菜单项将会在菜单显示使用目录填充,
参见上面的 WM_INITMENUPOPUP 消息部分。}
AppendMenu(menuSubFolder2, MF_STRING, 799, ' ');
{子菜单必须有一个菜单项,才能成功加入到另一个菜单的菜单项。}
menuListB2 := CreateMenu;
{利用 TMenuItemInfo 记录,使用功能强大的 InsertMenuItem() 函数,菜单项将被
加入到这个 menuListB2 菜单。}
MenuInfo.cbSize := SizeOf(MenuInfo);
{在使用 TMenuItemInfo 前注意设置 cbSize }
MenuInfo.fMask := MIIM_ID or MIIM_TYPE;
{第一个菜单项是标准的字符串菜单项,ID 编号为 301 ,因此你需要设置
MIIM_ID or MIIM_标志。}
MenuInfo.fType := MFT_STRING;
{设置 MFT_STRING 标志为菜单项放入字符串}
MenuInfo.dwTypeData := '&N编辑框指定的新文件夹';
//MenuInfo.cch := 21;
{如果 fType 标志设置为 MFT_STRING ,那么 dwTypeData 将被读取为 PChar 字符串,
你不必设置 MenuInfo.cch 为字符串长度,因为它不会从 MenuInfo.cch 读取数据。cch
将在写入字符并且不会读入 dwTypeData 时使用。}
MenuInfo.wID := 301;
{如果设置 MIIM_ID 标志,那么 wID 会被作为 ID 编号使用。注意这里是 wID,暗示这
是 WORD 类型,最大值为 65534。}
//MenuInfo.fState := 0;
//MenuInfo.hSubMenu := 0;
//MenuInfo.hbmpChecked := 0;
//MenuInfo.hbmpUnchecked := 0;
{不需要设置 MenuInfo 的其他域成员因为它们会被忽略}
InsertMenuItem(menuListB2, 0, False, MenuInfo);
{如果第三个参数设置为 False 那么第二个参数被作为 ID 使用,但是如果设置第二个
参数为 0,它就像 AppendMenu( ) 函数一样使用,将会把菜单项加入到最后位置。}
MenuInfo.fMask := MIIM_SUBMENU or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.dwTypeData := 'C 盘文件夹';
MenuInfo.hSubMenu := menuSubFolder2;
InsertMenuItem(menuListB2, 1, False, MenuInfo);
MenuInfo.fMask := MIIM_ID or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.dwTypeData := '加入所选项列表框3 ';
MenuInfo.wID := 302;
InsertMenuItem(menuListB2, 2, False, MenuInfo);
{如果第三个参数设置为 True 那么第二个参数被作为菜单项位置使用,
类似于 InsertMenu( ) 函数。}
MenuInfo.fMask := MIIM_ID or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.dwTypeData := '清空';
MenuInfo.wID := 303;
InsertMenuItem(menuListB2, 3, False, MenuInfo);
MenuInfo.fMask := MIIM_TYPE;
MenuInfo.fType := MFT_SEPARATOR;
{使用 MFT_SEPARATOR 则不需要其他成员}
InsertMenuItem(menuListB2, 4, True, MenuInfo);
MenuInfo.fMask := MIIM_ID or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.dwTypeData := '复制 菜单项';
MenuInfo.wID := 304;
InsertMenuItem(menuListB2, 5, True, MenuInfo);
MenuInfo.fMask := MIIM_ID or MIIM_TYPE;
MenuInfo.fType := MFT_STRING;
MenuInfo.dwTypeData := '尚未复制';
MenuInfo.wID := 305;
InsertMenuItem(menuListB2, 6, True, MenuInfo);
TempDC := GetDC(0);
BmpDC := CreateCompatibleDC(TempDC);
{准备在 menuListB3 菜单使用位图菜单项,这里创建位图并在上面标注"清空"。}
Bitmap1 := CreateCompatibleBitmap(TempDC, 39, 18);
SelectObject(BmpDC, Bitmap1);
SetRect(Rect1, 0, 0, 39, 18);
FillRect(BmpDC, Rect1, GetStockObject(BLACK_BRUSH));
SelectObject(BmpDC, GetStockObject(WHITE_BRUSH));
SetBkColor(BmpDC, $FFFFFF);
Ellipse(BmpDC, 0, 0, 39, 18);
SelectObject(BmpDC, GetStockObject(ANSI_VAR_FONT));
SetTextColor(BmpDC, $000000FF);
TextOut(BmpDC, 7, 2, '清空', 5);
DeleteDC(BmpDC);
ReleaseDC(0, TempDC);

menuListB3 := CreateMenu;
AppendMenu(menuListB3, MF_STRING, 401, '&S排序');
AppendMenu(menuListB3, MF_STRING, 402, '允许拖放');
AppendMenu(menuListB3, MF_BITMAP, 403, PChar(Bitmap1));
{使用 MF_BITMAP 需要把 Bitmap 句柄强制转化为 PChar}
AppendMenu(menuListB3, MF_SEPARATOR, 1, nil);
AppendMenu(menuListB3, MF_STRING, 404, '勾选');
AppendMenu(menuListB3, MF_STRING, 405, '隐藏此菜单');
CheckMenuRadioItem(menuListB3, 0, 1, 1, MF_BYPOSITION);
{CheckMenuRadioItem 将会设置一组菜单项为单选按钮风格,这组菜单项只有一个能被
用圆点形式选中。这里放置菜单项第 0 和 1 位置到分组中。}
CanDrag := True;
menuMain := CreateMenu;
{这里创建了主菜单}
{TMenuItemInfo 记录包含所有需要创建的菜单项的信息,这里还有比 AppendMenu 更
丰富的可用选项。}
MenuInfo.fMask := MIIM_SUBMENU or MIIM_TYPE;
{fMask 域你需要设置标志告知系统产生什么样的菜单属性}
MenuInfo.fType := MFT_STRING;
MenuInfo.dwTypeData := '&F文件';
MenuInfo.hSubMenu := menuFile;
InsertMenuItem(menuMain, 0, True, MenuInfo);
MenuInfo.dwTypeData := '列表框&1';
MenuInfo.hSubMenu := menuListB1;
InsertMenuItem(menuMain, 1, True, MenuInfo);
MenuInfo.dwTypeData := '列表框&2';
MenuInfo.hSubMenu := menuListB2;
InsertMenuItem(menuMain, 2, True, MenuInfo);
MenuInfo.dwTypeData := '列表框&3';
MenuInfo.hSubMenu := menuListB3;
InsertMenuItem(menuMain, 3, True, MenuInfo);
SetRect(Rect1, 0, 0, 536, 321);
if not AdjustWindowRect(Rect1, WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU,False) then
SetRect(Rect1, 0, 0, 542, 347);

hForm1 := CreateWindow(wClass.lpszClassName, '菜单与列表框',
WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU,
(GetSystemMetrics(SM_CXSCREEN) div 2) - 276,
(GetSystemMetrics(SM_CYSCREEN)div 2) - 212,
Rect1.Right - Rect1.Left, Rect1.Bottom - Rect1.Top, 0,
menuMain, // handle to main menu
hInstance, nil);
{SendMessage(CreateWindow('Static', '菜单与列表框',
WS_VISIBLE or WS_CHILD, 6, 3, 300, 20, hForm1, 0, hInstance, nil),
WM_SETFONT,GetStockObject(ANSI_VAR_FONT),0);}

{通过 WS_EX_CLIENTEDGE 风格 CreateWindowEx( ) 可以获取这些列表框的 3D 风格外观,
使用 LBS_HASSTRINGS or LBS_NOTIFY 标志在列表框使用字符串并通知父窗体消息。}
hListBox1 := CreateWindowEx(WS_EX_CLIENTEDGE, 'LISTBOX', 'C:\',
WS_VISIBLE or WS_CHILD or LBS_HASSTRINGS or LBS_NOTIFY or WS_VSCROLL,
8, 30, 150, 220, hForm1, 101, hInstance, nil);
SendMessage(hListBox1, WM_SETFONT, GetStockObject(ANSI_VAR_FONT), 0);
SendMessage(hListBox1, LB_DIR, DDL_READONLY or DDL_DIRECTORY,
Integer(PChar('C:\*.*')));
{这里使用发送 LB_DIR 消息的老办法在列表框1 中列出文件夹项,它以短文件名形式
显示,LB_DIR 主要针对过时的 Windows 3.x ,对于显示 32 位的长文件名的程序则
没有太大用处。}

PListbox1Proc := Pointer(SetWindowLong(hListBox1, GWL_WNDPROC,
Integer(@Listbox1Proc)));
{列表框1 和列表框3 被子类化,所以可以通过处理它们的消息进行很多操作。}

hListBox2 := CreateWindowEx(WS_EX_CLIENTEDGE, 'LISTBOX', nil,
WS_VISIBLE or WS_CHILD or LBS_HASSTRINGS or LBS_NOTIFY or WS_VSCROLL,
168, 30, 160, 220, hForm1, 0, hInstance, nil);
SendMessage(hListBox2, WM_SETFONT, GetStockObject(ANSI_VAR_FONT), 0);

hListBox3 := CreateWindowEx(WS_EX_CLIENTEDGE, 'LISTBOX',
'ListBox 3 selected is ',
WS_VISIBLE or WS_CHILD or LBS_HASSTRINGS or LBS_NOTIFY or WS_VSCROLL,
338, 30, 188, 220, hForm1, 0, hInstance, nil);
SendMessage(hListBox3, WM_SETFONT, GetStockObject(ANSI_FIXED_FONT), 0);
SendMessage(hListBox3, LB_INSERTSTRING, 0, Integer(PChar('列表框 3')));
{使用 LB_INSERTSTRING 添加文本到一个列表框,你需要强制转化 LParam 为 PChar,
再转化为 Integer 类型。}
PListbox3Proc := Pointer(SetWindowLong(hListBox3, GWL_WNDPROC,
Integer(@Listbox1Proc)));
{列表框1 和列表框3的子类化函数都设置为 Listbox1Proc ,这样一个列表框函数就
可以处理这两个列表框的消息。}

hEdit1 := CreateWindowEx(WS_EX_CLIENTEDGE, 'Edit', 'Wacky',
WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL,
16, 272, 400, 21, hForm1, 0, hInstance, nil);
SendMessage(hEdit1, WM_SETFONT, GetStockObject(ANSI_VAR_FONT), 0);

if PListbox1Proc = PListbox3Proc then
SetWindowText(hEdit1, 'C:\WINDOWS');
{如果你测试 - if PListbox1Proc = PListbox3Proc - 它是相等的,因为系统只有
一个列表框消息处理过程,它区分不同的列表框的不同设置是通过发送给系统的消息
处理过程的列表框句柄来实现的。}

DlgChk := True;
GetFiles('C:\');
{和列表框1 不一样,在列表框2 中我们使用 GetFiles 中的 FindFirstFile,这样可以
获取长文件名和文件列表,这样你可以更好控制列出的文件。}
ShowWindow(hForm1, SW_SHOWDEFAULT);
{GetSystemMenu( ) 将会获取系统菜单句柄,你可以利用菜单相关 API 函数处理系统菜单。}
hSysMenu := GetSystemMenu(hForm1, False);
InsertMenu(hSysMenu, 0, MF_BYPOSITION or MF_STRING, 901, 'Added Item');
InsertMenu(hSysMenu, 4, MF_BYPOSITION or MF_STRING, 902, 'MOVE WINDOW');
{两个菜单项被加入系统菜单}

while GetMessage(MainMsg, 0, 0, 0) do
begin
TranslateMessage(MainMsg);
DispatchMessage(MainMsg);
end;
DlgEditText := '';
{由于 menuListB3 可以被移除,所以记得销毁它。一旦某个子菜单被移除,它就没有
Owner 来自动销毁。}
DestroyMenu(menuListB3);
end.

来源:http://blog.tom.com/jdzmc_wanqing/article/1632.html

标签: , ,

星期二, 十一月 11, 2008

Delphi与字符编码(实战篇)

本文目标:

* 了解Delphi的字符串类型
* 字符编码的检测与转换
* 简体繁体转换

0. 导言
看完“.Net与字符编码(理论篇)”,我们明白了字符是自然语言中的最小单位,在存储和传输的过程中可以使用三种编码方法:ASCII、DBCS以及Unicode。常见的DBCS编码有GB2312、GBK和BIG5,而UTF-8、UTF-16和UTF-32则是最常用的Unicode编码类型。

http://www.cnblogs.com/baoquan/archive/2008/01/05/1027371.html

标签: , ,

星期二, 十月 21, 2008

EXE图标替换

杂志文章作者:牵着蜗牛去散步

HINSTANCE hInstance=LoadLibrary("D:\\dd.exe");//载入图标源文件 5~8FZ-x
HRSRC hRsrc = FindResource(hInstance,(LPCSTR)1,(LPCSTR)RT_ICON); //查找源文件中的图标文件 -!_\4
LPVOID lpRes = LockResource(LoadResource(hInstance,hRsrc)); //锁定资源 GTYCNi66
HANDLE hUpdateRes = BeginUpdateResource("D:\\dd2.exe", FALSE); //更新dd2文件图标为dd的 *aem5 E`c
UpdateResource(hUpdateRes,(LPCSTR)RT_ICON, (LPCSTR)1,0,lpRes,SizeofResource(hInstance,hRsrc)); //更新图标资源 }253Q!f
EndUpdateResource(hUpdateRes,FALSE); //结束更新资源 WF#3'"I
CloseHandle(hRsrc); //关闭句柄 y"bSn5B[
CloseHandle(hUpdateRes);//关闭句柄 l(�Y U9dp
FreeLibrary(hInstance); //释放载入的源文件 85{2TXQ^%=

http://www.nn4a.com/bbs/read.php?tid=9818

再来一段Delphi写的:

给你一段读写自身icon的程序。写别的程序的,只需要loadlibrary,用它的句柄代替hinstance.

PCursorOrIcon = ^TCursorOrIcon;
TCursorOrIcon = packed record
Reserved: Word;
wType: Word;
Count: Word;
end;
//This has been defined in DELPHI9. But not the definition of IconEntry.
PIconEntry = ^TIconEntry;
TIconEntry= packed record
bWidth : Byte; // Width, in pixels, of the image
bHeight : Byte; // Height, in pixels, of the image
bColorCount: Byte; // Number of colors in image (0 if >=8bpp)
bReserved: Byte; // Reserved ( must be 0)
wPlanes : word; // Color Planes
wBitCount : word; // Bits per pixel
dwBytesInRes : dword; // How many bytes in this resource?
dwImageOffset : dword;
end;

var
hRes,hMem:HRSRC;
lpMem : Pointer;
lp1 : PBYTE;
n : integer;
ts : TMemoryStream;
IconHeader : TCursorOrIcon;
IconEntry : TIconEntry;

begin
ts:=TMemoryStream.Create;
hRes:=FindResource(hInstance,'small',rt_group_icon);
hMem:=LoadResource(hInstance,hRes);
lpMem:=LockResource(hMem);
IconHeader.Reserved:=PWord(lpMem)^; //usually be $0.
IconHeader.wType:=$01; //$01 for ICON
IconHeader.Count:=$01; // we just want lookup a single icon.
//ts.Write(pbyte(lpMem)^,sizeof(TCursorOrIcon));
ts.Write(IconHeader,sizeof(IconHeader));

n := LookUpIconIDFromDirectoryEx(PBYTE(lpMem),True,16,SM_CYSMICON,LR_DEFAULTCOLOR);
hRes:=FindResource(hInstance,MakeIntResource(n),rt_icon);
hMem:=LoadResource(hInstance,hRes);
lpMem:=LockResource(hMem);

IconEntry.bWidth:= TBitmapInfoHeader(lpMem^).biWidth;
IconEntry.bHeight:=TBitmapInfoHeader(lpMem^).biHeight div 2;
n:=TBitmapInfoHeader(lpMem^).biPlanes * TBitmapInfoHeader(lpMem^).biBitCount;
if n>=8 then IconEntry.bColorCount:=0
else IconEntry.bColorCount:= 1 shl n;

IconEntry.bReserved:=$0;
IconEntry.wBitCount:=TBitmapInfoHeader(lpMem^).biBitCount;
IconEntry.wPlanes:=TBitmapInfoHeader(lpMem^).biPlanes;
IconEntry.dwBytesInRes:= sizeofResource(hInstance,hRes);
IconEntry.dwImageOffset:=sizeof(TCursorOrIcon)+sizeof(TIconEntry);

ts.Write(IconEntry,sizeof(IconEntry));
ts.Write(pbyte(lpMem)^,IconEntry.dwBytesInRes);
ts.SaveToFile('test.ico');
ts.Free;
end;

http://zhidao.baidu.com/question/33643445.html

还有:http://www.180it.com/read.php?32

标签: , , ,

星期三, 五月 14, 2008

;)

C/C++还是最棒的

Object Pascal也不错,至少目前Free Pascal的发展比Delphi的命运好像好一点

Python易学易用,语法太灵活了,缩进还是没有;号爽

UML 2.0还没有达到易用,易懂的程度,也许以后描述问题不用它了吧

PHP做网站很不错,CodeIgniter框架也不错,就是对XHTML的支持,特别是UTF-8的支持不是很理想。

标签: , , , , , , ,

星期二, 五月 13, 2008

Lazarus Unicode说明

Lazarus對Unicode的支援還需要進一步開發,尤其是在Windows平台上。以下提供一些基本的資訊,讓想要加強Lazarus對Unicode支援的人參考,如果您發現這些資訊有誤、不足或過時了,請您不吝修正、補充或更新它,謝謝。

如果您已經初步了解Unicode的標準,且您已經在Delphi上面有使用過WideString這個型別來撰寫程式,會有助於您理解Lazarus對Unicode支援的加強工作。如果您使用過非Latin編碼的字元集來撰寫腳本語言,也會有些幫助的。

請注意: 實作的細節部分目前還在討論中,這部分的文件隨時都有可能更新。


http://wiki.freepascal.org/LCL_Unicode_Support/zh_TW

标签: , , , ,

星期一, 五月 05, 2008

Web Site inside a Delphi EXE

This is the third article in the series about storing more than just executable code inside a Delphi application.
In the introductory article we saw how Delphi uses standard Windows resource files like icons, bitmaps and cursors. As explained, resource files that store such kind of data can be created with Delphi's Image Editor. The second article explained how to use sound files, video clips, animations and more generally any kind of binary files in a Delphi executable - we placed a mp3 file inside a Delphi exe. As stated, we use Borland Resource Compiler (BRCC32.exe) to create a resource file that gets linked with an executable file.

Many of you have asked how your application can be a container for any Web-style content, including HTML resources and pictures that are part of your project.
This articles will show you how HTML and associated files (pictures) can easily be included within a Delphi application. As a result, you simply have to distribute an EXE file that includes HTML pages, as it would do with icons and cursors.

Creating a HTML page
For the start we have to assemble a (simple) html page. Use your favorite HTML editor and create one page with one associated picture. I'll name mine aboutindex.htm.
Note that when you add a picture tag inside a htm page it looks something like:

We have to alter the IMG tags so that the SRC attribute equals the name we are to give to a picture in a resource:

My HTML code looks like:

HTML inside a Delphi exe
This is a HTML Delphi resource test:


Creating and compiling a resource file
Remember that to create a new resource script file, you have to:
1. Create a new text file in your projects directory.
2. Rename it to AHTMLDelphi.rc.
3. Write down the following two lines of text in the AHTMLDelphi.rc file.

DELPHIINDEX HTML "c:\Delphi\projects\aboutindex.htm"
ABOUTDP GIF "c:\library\graphics\adp.gif"

Note: the resource type "HTML" is RT_HTML, predefined as the resource type "23". This is the default resource type for the RES protocol.

In this way we have prepared one HTML page and one GIF picture to be included in the binary code of our EXE module.

The next step is to compile the .rc file. To compile the AHTMLDelphi.rc file to a .res file execute this command at the command prompt (in the projects directory):

BRCC32 AHTMLDelphi.RC

The final step is to add the following compiler directive to a unit in your project. RES file must be included in the program's build by adding a line like this:

{$R AHTMLDelphi.RES}

Displaying inside a Web browser
When you have the application's exe (let's call it: myhtmldelphi.exe) the HTML resource contained within can be accessed via the RES: protocol. Run Internet Explorer and, in the Address bar, type the following:

res://c:\myhtmldelphi.exe/RT_HTML/DELPHIINDEX

This should result in:

HTML page from a Delphi resource

That's it. If you have any questions; like how use the HREF tag inside a html resource, or how to display the html page inside a Delphi form; please post them on the Delphi Programming Forum!

标签: ,

星期二, 四月 29, 2008

TRegExpr正则表达式

DELPHi中的REGEXPR
[ 2006-03-29 11:33:46 am | Author: Admin ]
其实这个Pascal单元我在几个论坛上面都推荐过,也是我唯一会用的DELPHI下面的正则表达式实现。
  正则表达式是个极其繁琐和强大的东西,小生才疏学浅,也不准备写正则表达式的教程,借着对这个单元的介绍,会有一些浅显且有用的例子。
  首先介绍的是这个单元的主角:TRegExpr类,这个类包括很多成员,这里仅简单的介绍一下一般匹配的过程。下面是一段在文本中提取邮件地址的代码:

Procedure GetName(TextToCheck:String;aList:TStringList);
Var
myExpr: TRegExpr;
begin
myExpr := TRegExpr.Create;
Try
myExpr.Expression := 'name="(.*?)"';
if myExpr.Exec(TextToCheck) then
repeat
aList.Add(myExpr.Match[1]);
until not MyExpr.ExecNext;
finally
myExpr.Free;
end;
end;

  下面对这段代码进行一点简要的说明.
  首先是myExpr.Expression := 'name="(.*?)"';这个语句用以匹配name="XXXXX"形式的字符串。
“.*?”是很常见的一段,表示对任意字符串的“非贪婪匹配”,代表符合匹配条件的最短字符串,关于贪婪非贪婪的问题,会在后面说明。
  括号表示对这段文字的引用,匹配中出现符合该模式的字符串将会存储在TRegExpr的Match数组中。
  接下来是if myExpr.Exec(TextToChceck)这一句,这一语句就是开始利用上文提到的正则表达式对TextToCheck进行匹配。Exec方法有三个重载:
function Exec (const AInputString : AnsiString) : boolean; //对AInputString参数进行匹配
function Exec : boolean; overload; //对InputString成员进行匹配
function Exec (AOffset: integer) : boolean; overload; //对InputString成员,从AOffset位置开始进行匹配
  该方法返回一个布尔型的值,如果为真,则表明InputString中包含表达式所匹配的模式,例如'Name="Hello.Gif"'作为参数,就会返回True。

  接下来的语句中出现的myExpr.Match[1],则用以取出本次匹配结果

  最后的ExecNext其实是使用了上面提到的第三个重载,用来对重复出现的字符串进行连续匹配,返回结果的含义同Exec相同

  接下来谈谈Match成员,其中Match[0]表示整个表达式的匹配结果,之后的数组元素则代表括号中的匹配结果,元素编号按照括号从左到右的顺序递增,嵌套括号则以从内向外的顺序递增。例如一个简单的对E-Mail地址的匹配:
Quotes From ???
输入字符串:'"dirt@sina.com","v@d2g.com"'
正则表达式:'"((.*?)@(.*?))",'
执行结果如下:
0 "dirt@sina.com",
1 dirt@sina.com
2 dirt
3 sina.com
  从中即可看出Match数组中的结果排列顺序。


  而上文中出现的.*?经常用于不很严谨的场合,例如前面用到的邮件地址提取,有人就写出几百字符的的验证表达式。其中“.”表示任意单个字符,“*” 表示前面的字符(串)至少出现一次,而'?'在这里就是非贪婪限定符,举一个简单的例子:"aaa""bbb",这样一个字符串,如果用'" (.*?)"'进行匹配,则Match[1]的内容就是'aaa',如果去掉了其中的'?',则Match[1]就变成了'aaa""bbb',这就可以 看出贪婪和非贪婪的区别。

  一个基本的匹配过程就到这里,有空会再继续写一些其他的相关内容,敬请丢砖

转自:http://www.delphibbs.com/keylife/iblog_show.asp?xid=13902
作者:coolbaby

TRegExpr是正则表达式在delphi中的一个很好的实现。
是一个单独的单元,使用时直接引用即可。还自带了几个sample。

对其中的SelfTest例子加了几行注释如下:
{ basic tests }

r := TRegExpr.Create;

r.Expression := '[A-Z]';
r.Exec ('234578923457823659GHJK38');
Check (0, 19, 1);
//?在此处表示让*处于非贪婪模式
r.Expression := '[A-Z]*?';
r.Exec ('234578923457823659ARTZU38');
Check (0, 1, 0);

r.Expression := '[A-Z]+';
r.Exec ('234578923457823659ARTZU38');
Check (0, 19, 5);
//和上面的+方式,功能一样
r.Expression := '[A-Z][A-Z]*';
r.Exec ('234578923457823659ARTZU38');
Check (0, 19, 5);
//?这里表示匹配[A-Z]0次或者一次
r.Expression := '[A-Z][A-Z]?';
r.Exec ('234578923457823659ARTZU38');
Check (0, 19, 2);
// \d代表数字,^代表非,总得来说就是一个或者多个非数字字符
r.Expression := '[^\d]+';
r.Exec ('234578923457823659ARTZU38');
Check (0, 19, 5);

半小时精通正则表达式
作者:Web应用网 来源:Web应用网

跟我学正则表达式!
想必很多人都对正则表达式都头疼.今天,我以我的认识,加上网上一些文章,希望用常人都可以理解的表达方式.来和大家分享学习经验.
开篇,还是得说说 ^ 和 $ 他们是分别用来匹配字符串的开始和结束,以下分别举例说明

"^The": 开头一定要有"The"字符串;
"of despair$": 结尾一定要有"of despair" 的字符串;

那么,
"^abc$": 就是要求以abc开头和以abc结尾的字符串,实际上是只有abc匹配
"notice": 匹配包含notice的字符串

你可以看见如果你没有用我们提到的两个字符(最后一个例子),就是说 模式(正则表达式) 可以出现在被检验字符串的任何地方,你没有把他锁定到两边
接着,说说 '*', '+',和 '?',
他们用来表示一个字符可以出现的次数或者顺序. 他们分别表示:
"zero or more"相当于{0,},
"one or more"相当于{1,},
"zero or one."相当于{0,1}, 这里是一些例子:

"ab*": 和ab{0,}同义,匹配以a开头,后面可以接0个或者N个b组成的字符串("a", "ab", "abbb", 等);
"ab+": 和ab{1,}同义,同上条一样,但最少要有一个b存在 ("ab", "abbb", 等.);
"ab?":和ab{0,1}同义,可以没有或者只有一个b;
"a?b+$": 匹配以一个或者0个a再加上一个以上的b结尾的字符串.
要点, '*', '+',和 '?'只管它前面那个字符.

你也可以在大括号里面限制字符出现的个数,比如

"ab{2}": 要求a后面一定要跟两个b(一个也不能少)("abb");
"ab{2,}": 要求a后面一定要有两个或者两个以上b(如"abb", "abbbb", 等.);
"ab{3,5}": 要求a后面可以有2-5个b("abbb", "abbbb", or "abbbbb").

现在我们把一定几个字符放到小括号里,比如:
"a(bc)*": 匹配 a 后面跟0个或者一个"bc";
"a(bc){1,5}": 一个到5个 "bc."

还有一个字符 '│', 相当于OR 操作:

"hi│hello": 匹配含有"hi" 或者 "hello" 的 字符串;
"(b│cd)ef": 匹配含有 "bef" 或者 "cdef"的字符串;
"(a│b)*c": 匹配含有这样多个(包括0个)a或b,后面跟一个c
的字符串;

一个点('.')可以代表所有的单一字符,不包括"\n"
如果,要匹配包括"\n"在内的所有单个字符,怎么办?
对了,用'[\n.]'这种模式.

"a.[0-9]": 一个a加一个字符再加一个0到9的数字
"^.{3}$": 三个任意字符结尾 .


中括号括住的内容只匹配一个单一的字符

"[ab]": 匹配单个的 a 或者 b ( 和 "a│b" 一样);
"[a-d]": 匹配'a' 到'd'的单个字符 (和"a│b│c│d" 还有 "[abcd]"效果一样); 一般我们都用[a-zA-Z]来指定字符为一个大小写英文
"^[a-zA-Z]": 匹配以大小写字母开头的字符串
"[0-9]%": 匹配含有 形如 x% 的字符串
",[a-zA-Z0-9]$": 匹配以逗号再加一个数字或字母结尾的字符串

你也可以把你不想要得字符列在中括号里,你只需要在总括号里面使用'^' 作为开头 "%[^a-zA-Z]%" 匹配含有两个百分号里面有一个非字母的字符串.
要点:^用在中括号开头的时候,就表示排除括号里的字符
为了PHP能够解释,你必须在这些字符面前后加'',并且将一些字符转义.
不要忘记在中括号里面的字符是这条规路的例外—在中括号里面, 所有的特殊字符,包括(''), 都将失去他们的特殊性质 "[*\+?{}.]"匹配含有这些字符的字符串.
还有,正如regx的手册告诉我们: "如果列表里含有 ']', 最好把它作为列表里的第一个字符(可能跟在'^'后面). 如果含有'-', 最好把它放在最前面或者最后面, or 或者一个范围的第二个结束点[a-d-0-9]中间的‘-’将有效.
看了上面的例子,你对{n,m}应该理解了吧.要注意的是,n和m都不能为负整数,而且n总是小于m. 这样,才能 最少匹配n次且最多匹配m次. 如"p{1,5}"将匹配 "pvpppppp"中的前五个p
下面说说以\开头的
\b 书上说他是用来匹配一个单词边界,就是...比如've\b',可以匹配love里的ve而不匹配very里有ve
\B 正好和上面的\b相反.例子我就不举了
.....突然想起来....可以到http://www.phpv.net/article.php/251 看看其它用\ 开头的语法

好,我们来做个应用:
如何构建一个模式来匹配 货币数量 的输入
构建一个匹配模式去检查输入的信息是否为一个表示money的数字。我们认为一个表示money的数量有四种方式: "10000.00" 和 "10,000.00",或者没有小数部分, "10000" and "10,000". 现在让我们开始构建这个匹配模式:
^[1-9][0-9]*$
这是所变量必须以非0的数字开头.但这也意味着 单一的 "0" 也不能通过测试. 以下是解决的方法:
^(0│[1-9][0-9]*)$
"只有0和不以0开头的数字与之匹配",我们也可以允许一个负号在数字之前:
^(0│-?[1-9][0-9]*)$
这就是: "0 或者 一个以0开头 且可能 有一个负号在前面的数字." 好了,现在让我们别那么严谨,允许以0开头.现在让我们放弃 负号 , 因为我们在表示钱币的时候并不需要用到. 我们现在指定 模式 用来匹配小数部分:
^[0-9]+(\.[0-9]+)?$
这暗示匹配的字符串必须最少以一个阿拉伯数字开头. 但是注意,在上面模式中 "10." 是不匹配的, 只有 "10" 和 "10.2" 才可以. (你知道为什么吗)
^[0-9]+(\.[0-9]{2})?$
我们上面指定小数点后面必须有两位小数.如果你认为这样太苛刻,你可以改成:
^[0-9]+(\.[0-9]{1,2})?$
这将允许小数点后面有一到两个字符. 现在我们加上用来增加可读性的逗号(每隔三位), 我们可以这样表示:
^[0-9]{1,3}(,[0-9]{3})*(\.[0-9]{1,2})?$
不要忘记 '+' 可以被 '*' 替代 如果你想允许空白字符串被输入话 (为什么?). 也不要忘记反斜杆 ’\’ 在php字符串中可能会出现错误 (很普遍的错误).
现在,我们已经可以确认字符串了, 我们现在把所有逗号都去掉 str_replace(",", "", $money) 然后在把类型看成 double然后我们就可以通过他做数学计算了.

再来一个:
构造检查email的正则表达式
在一个完整的email地址中有三个部分:
1. 用户名 (在 '@' 左边的一切),
2.'@',
3. 服务器名(就是剩下那部分).
用户名可以含有大小写字母阿拉伯数字,句号 ('.'), 减号('-'), and 下划线 ('_'). 服务器名字也是符合这个规则,当然下划线除外.
现在, 用户名的开始和结束都不能是句点. 服务器也是这样. 还有你不能有两个连续的句点他们之间至少存在一个字符,好现在我们来看一下怎么为用户名写一个匹配模式:
^[_a-zA-Z0-9-]+$
现在还不能允许句号的存在. 我们把它加上:
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*$
上面的意思就是说: "以至少一个规范字符(除了.)开头,后面跟着0个或者多个以点开始的字符串."
简单化一点, 我们可以用 eregi()取代 ereg().eregi()对大小写不敏感, 我们就不需要指定两个范围 "a-z" 和 "A-Z" – 只需要指定一个就可以了:
^[_a-z0-9-]+(\.[_a-z0-9-]+)*$
后面的服务器名字也是一样,但要去掉下划线:
^[a-z0-9-]+(\.[a-z0-9-]+)*$
好. 现在只需要用”@”把两部分连接:
^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$

这就是完整的email认证匹配模式了,只需要调用
eregi(‘^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$ ’,$eamil)
就可以得到是否为email了
正则表达式的其他用法
提取字符串
ereg() and eregi() 有一个特性是允许用户通过正则表达式去提取字符串的一部分(具体用法你可以阅读手册). 比如说,我们想从 path/URL 提取文件名 – 下面的代码就是你需要:
ereg("([^\\/]*)$", $pathOrUrl, $regs);
echo $regs[1];
高级的代换
ereg_replace() 和 eregi_replace()也是非常有用的: 假如我们想把所有的间隔负号都替换成逗号:
ereg_replace("[ \n\r\t]+", ",", trim($str));
最后,我把另一串检查EMAIL的正则表达式让看文章的你来分析一下.
"^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+'.'@'.'[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.'.'[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$"
如果能方便的读懂,那这篇文章的目的就达到了.

JScript 和 VBScript 正则表达式 的语法规则

一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

这里有一些可能会遇到的正则表达式示例:



JScript VBScript 匹配
/^\[ \t]*$/ "^\[ \t]*$" 匹配一个空白行。
/\d-\d/ "\d-\d" 验证一个ID 号码是否由一个2位数字,一个连字符以及一个5位数字组成。
/<(.*)>.*<\/>/ "<(.*)>.*<\/>" 匹配一个 HTML 标记。

下表是元字符及其在正则表达式上下文中的行为的一个完整列表:

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用、或一个八进制转义符。例如,'n' 匹配字符 "n"。'\n' 匹配一个换行符。序列 '\' 匹配 "\" 而 "\(" 则匹配 "("。
^ 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等价于。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 。
n 是一个非负整数。匹配确定的 n 次。例如,'o' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
n 是一个非负整数。至少匹配n 次。例如,'o' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o' 等价于 'o+'。'o' 则等价于 'o*'。
m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o" 将匹配 "fooooood" 中的前三个 o。'o' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, , , ) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。
. 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
(pattern) 匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 … 属性。要匹配圆括号字符,请使用 '\(' 或 '\)'。
(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern) 正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始
x|y 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
\W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,'\x41' 匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII 编码。.
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,'(.)' 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (©)。

2005-5-23 10:26:21 piao40993470 发表评论。
所有中文(不包括标点):
([\xB0-\xF7][\xA1-\xFE])+
所有GB2312-80编码
([\xA1-\xFE][\xA1-\xFE])+
所有中文空格
(\xA1\xA1)+

英文标点:[\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E]

2005-5-23 10:32:03 piao40993470 发表评论。
补充一下:
在delphi下使用TPerlRegEx也是不错的

http://hi.baidu.com/program8/blog/item/31800b0801b32030e824885f.html

标签: , , ,

星期四, 四月 17, 2008

Format的用法

Format是一个很常用,却又似乎很烦的方法,本人试图对这个方法的帮助进行一些翻译
,让它有一个完整的概貌,以供大家查询之用:

首先看它的声明:
function Format(const Format: string; const Args: array of const): string; overload;
事实上Format方法有两个种形式,另外一种是三个参数的,主要区别在于它是线程安全的,
但并不多用,所以这里只对第一个介绍:

function Format(const Format: string; const Args: array of const): string; overload;
Format参数是一个格式字符串,用于格式化Args里面的值的。Args又是什么呢,
它是一个变体数组,即它里面可以有多个参数,而且每个参数可以不同。
如以下例子:
Format('my name is %6s',['wind']);
返回后就是
my name is wind

现在来看Format参数的详细情况:
Format里面可以写普通的字符串,比如'my name is'
但有些格式指令字符具有特殊意义,比如"%6s"

格式指令具有以下的形式:
"%" [index ":"] ["-"] [width] ["." prec] type
它是以"%"开始,而以type结束,type表示一个具体的类型。中间是用来
格式化type类型的指令字符,是可选的。

先来看看type,type可以是以下字符:
d 十制数,表示一个整型值
u 和d一样是整型值,但它是无符号的,而如果它对应的值是负的,则返回时
是一个2的32次方减去这个绝对值的数
如:Format('this is %u',[-2]);
返回的是:this is 4294967294
f 对应浮点数
e 科学表示法,对应整型数和浮点数,
比如Format('this is %e',[-2.22]);
返回的是:this is -2.22000000000000E+000
等一下再说明如果将数的精度缩小
g 这个只能对应浮点型,且它会将值中多余的数去掉
比如Format('this is %g',[02.200]);
返回的是:this is 2.2
n 只能对应浮点型,将值转化为号码的形式。看一个例子就明白了
Format('this is %n',[4552.2176]);
返回的是this is 4,552.22
注意有两点,一是只表示到小数后两位,等一下说怎么消除这种情况
二是,即使小数没有被截断,它也不会也像整数部分一样有逗号来分开的
m 钱币类型,但关于货币类型有更好的格式化方法,这里只是简单的格式化
另外它只对应于浮点值
Format('this is %m',[9552.21]);
返回:this is ¥9,552.21
p 对应于指针类型,返回的值是指针的地址,以十六进制的形式来表示
例如:
var X:integer;
p:^integer;
begin
X:=99;
p:=@X;
Edit1.Text:=Format('this is %p',[p]);
end;
Edit1的内容是:this is 0012F548
s 对应字符串类型,不用多说了吧
x 必须是一个整形值,以十六进制的形式返回
Edit1.Text:=Format('this is %X',[15]);
返回是:this is F

类型讲述完毕,下面介绍格式化Type的指令:
[index ":"] 这个要怎么表达呢,看一个例子
Format('this is %d %d',[12,13]);
其中第一个%d的索引是0,第二个%d是1,所以字符显示的时候
是这样 this is 12 13

而如果你这样定义:
Format('this is %1:d %0:d',[12,13]);
那么返回的字符串就变成了
this is 13 12
现在明白了吗,[index ":"] 中的index指示Args中参数显示的
顺序

还有一种情况,如果这样Format('%d %d %d %0:d %d', [1, 2, 3, 4])
将返回1 2 3 1 2。
如果你想返回的是1 2 3 1 4,必须这样定:
Format('%d %d %d %0:d %3:d', [1, 2, 3, 4])
但用的时候要注意,索引不能超出Args中的个数,不然会引起异常
如Format('this is %2:d %0:d',[12,13]);
由于Args中只有12 13 两个数,所以Index只能是0或1,这里为2就错了
[width] 指定将被格式化的值占的宽度,看一个例子就明白了
Format('this is %4d',[12]);
输出是:this is 12
这个是比较容易,不过如果Width的值小于参数的长度,则没有效果。
如:Format('this is %1d',[12]);
输出是:this is 12
["-"] 这个指定参数向左齐,和[width]合在一起最可以看到效果:
Format('this is %-4d,yes',[12]);
输出是:this is 12 ,yes

["." prec] 指定精度,对于浮点数效果最佳:
Format('this is %.2f',['1.1234]);
输出 this is 1.12
Format('this is %.7f',['1.1234]);
输了 this is 1.1234000

而对于整型数,如果prec比如整型的位数小,则没有效果
反之比整形值的位数大,则会在整型值的前面以0补之
Format('this is %.7d',[1234]);
输出是:this is 0001234]

对于字符型,刚好和整型值相反,如果prec比字符串型的长度大
则没有效果,反之比字符串型的长度小,则会截断尾部的字符
Format('this is %.2s',['1234']);
输出是 this is 12

而上面说的这个例子:
Format('this is %e',[-2.22]);
返回的是:this is -2.22000000000000E+000
怎么去掉多余的0呢,这个就行啦
Format('this is %.2e',[-2.22]);

好了,第一个总算讲完了,应该对他的应用很熟悉了吧

///////////////////////////////////////////////////////////////
二 FormatDateTime的用法
他的声明为:
function FormatDateTime(const Format: string; DateTime: TDateTime): string;
overload;
当然和Format一样还有一种,但这里只介绍常用的第一种
Format参数是一个格式化字符串。DateTime是时间类型。返回值是一种格式化后的
字符串

重点来看Format参数中的指令字符
c 以短时间格式显示时间,即全部是数字的表示
FormatdateTime('c',now);
输出为:2004-8-7 9:55:40
d 对应于时间中的日期,日期是一位则显示一位,两位则显示两位
FormatdateTime('d',now);
输出可能为1~31
dd 和d的意义一样,但它始终是以两位来显示的
FormatdateTime('dd',now);
输出可能为01~31
ddd 显示的是星期几
FormatdateTime('ddd',now);
输出为: 星期六
dddd 和ddd显示的是一样的。
但上面两个如果在其他国家可能不一样。
ddddd 以短时间格式显示年月日
FormatdateTime('ddddd',now);
输出为:2004-8-7
dddddd 以长时间格式显示年月日
FormatdateTime('dddddd',now);
输出为:2004年8月7日
e/ee/eee/eeee 以相应的位数显示年
FormatdateTime('ee',now);
输出为:04 (表示04年)
m/mm/mmm/mmmm 表示月
FormatdateTime('m',now);
输出为:8
FormatdateTime('mm',now);
输出为 08
FormatdateTime('mmm',now);
输出为 八月
FormatdateTime('mmmm',now);
输出为 八月
和ddd/dddd 一样,在其他国家可能不同
yy/yyyy 表示年
FormatdateTime('yy',now);
输出为 04
FormatdateTime('yyyy',now);
输出为 2004
h/hh,n/nn,s/ss,z/zzz 分别表示小时,分,秒,毫秒
t 以短时间格式显示时间
FormatdateTime('t',now);
输出为 10:17
tt 以长时间格式显示时间
FormatdateTime('tt',now);
输出为10:18:46
ampm 以长时间格式显示上午还是下午
FormatdateTime('ttampm',now);
输出为:10:22:57上午

大概如此,如果要在Format中加普通的字符串,可以用双引号隔开那些
特定义的字符,这样普通字符串中如果含特殊的字符就不会被显示为
时间格式啦:
FormatdateTime('"today is" c',now);
输出为:today is 2004-8-7 10:26:58
时间中也可以加"-"或"\"来分开日期:
FormatdateTime('"today is" yy-mm-dd',now);
FormatdateTime('"today is" yy\mm\dd',now);
输出为: today is 04-08-07
也可以用":"来分开时间
FormatdateTime('"today is" hh:nn:ss',now);
输出为:today is 10:32:23

/////////////////////////////////////////////////////////////////
三.FormatFloat的用法

常用的声明:
function FormatFloat(const Format: string; Value: Extended): string; overload;
和上面一样Format参数为格式化指令字符,Value为Extended类型
为什么是这个类型,因为它是所有浮点值中表示范围最大的,如果传入该方法的参数
比如Double或者其他,则可以保存不会超出范围。

关键是看Format参数的用法
0 这个指定相应的位数的指令。
比如:FormatFloat('000.000',22.22);
输出的就是022.220
注意一点,如果整数部分的0的个数小于Value参数中整数的位数,则没有效果
如:FormatFloat('0.00',22.22);
输出的是:22.22
但如果小数部分的0小于Value中小数的倍数,则会截去相应的小数和位数
如:FormatFloat('0.0',22.22);
输出的是:22.2

也可以在整数0中指定逗号,这个整数位数必须大于3个,才会有逗号出句
FormatFloat('0,000.0',2222.22);
输出是:2,222.2
如果这样FormatFloat('000,0.0',2222.22);
它的输出还是:2,222.2
注意它的规律

# 和0的用法一样,目前我还没有测出有什么不同。
FormatFloat('##.##',22.22);
输出是:22.00

E 科学表示法,看几个例子大概就明白了
FormatFloat('0.00E+00',2222.22);
输出是 2.22E+03
FormatFloat('0000.00E+00',2222.22);
输出是 2222.22E+00
FormatFloat('00.0E+0',2222.22);
22.2E+2
明白了吗,全靠E右边的0来支配的。

这个方法并不难,大概就是这样子了。

上面三个方法是很常用的,没有什么技巧,只要记得这些规范就行了。
我把它写出来,方便大家参考而已,没有什么特别目的

http://codegear.cn/post/2008/03/13/Formate79a84e794a8e6b395.aspx

标签: ,

关于Delphi的四舍五入

在网上常有人说Delphi的四舍五入有Bug!?
相反,我认为Borland考虑得很全面,这不是Bug!

Delphi帮助里面写得清清楚楚!

SimpleRoundTo :四舍五入(不对称算数做法)
RoundTo:四舍六入,五入单(银行家做法)
RoundTo(1.235, -2) = 1.24
RoundTo(1.245, -2) = 1.24

RoundTo是银行家的 做法,
SimpleRoundTo才是我们平时说的四舍五入!

http://codegear.cn/post/2008/03/13/delphi-roundto.aspx
对4舍5入国家有标准的。但是很多人根本不清楚。

标签:

星期三, 四月 16, 2008

三个期待````

1. Delphi for AS/400
这个消息是从范路先生这里得知的,CodeGear将发布一个专用于IBM AS/400 服务器开发的Delphi版本
2. Eclipse for Delphi
据说是 IBM 的一个新计划,具体情况不得而知.就以往的Eclipse来看,应该是会方便一下Web应用的开发,并且也不会像原本的Delphi那样拥有很多的组件.这倒底是好事还是坏事呢
3. Delphi2008/RAD Studio2008
终于能上Unicode了,等这一天不知等了多久,还有泛型之类的新特性加入,值得期待

http://hi.baidu.com/rarnu/blog/item/0f48ffed9a58864b78f05597.html

标签:

一點Delphi2008的消息

昨晚和范路先生吃了一頓晚飯,相互間也談起了各自的工作,未來等等。有意無意的也問了一些delphi2008的情況,的確是狠出乎我的意料,也許VCL2的強大程度是我所不能預料的。

delphi2008的新特性:
1. 支持Unicode,這個是眾多delphi程序員期盼已久的了,這次終於要實現了
2. 支持編譯64位的應用程序,它將成為64位系統下,效率最高的開發工具
3. for Win32 版本支持泛型,原本只是在Delphi.NET中有此功能
4. for Win32 版本支持反射,同樣的,原本只在Delphi.NET中有
5. delphi2008應當能直接編譯以前版本的源碼,並且使用FastMM作為內存管理工具

另外,會有一些新的框架面世,范路先生所說的Application Factory實在是狠吸引人
它可以讓開發人員在開發過程中就記錄下自己的知識,在更換人員時,交接將變得異常簡單
並且Application Factory可以跟據以前的程序以及定下的規則,快速的生成新代碼
這對於經常要開發同一種系統,但又需要為不同用戶定製需求時,將非常有用

另外,delphi2008也將會有 for win32和for .NET的版本

最後,也談了下delphi2008的價格,買一個授權的話,大概是在人民幣2萬到3萬元之間,但是可以批量的買
買得越多,價格也會越低,如果買1千個以上授權,也許可以降到每個授權5千以下
如果有1萬個授權批量的買,每個授權100元都是有可能的,現在在CodeGear-CN上也有人提出了此想法
就等著它實現了。

delphi2008的內測就在眼前了,等內測時,我會拿出一個詳細的測試報告,敬請期待。

http://hi.baidu.com/rarnu/blog/item/e335cd17d41fb40dc93d6dbd.html

标签:

星期三, 四月 09, 2008

ADOConnect时如何根据返回信息判断

try
...
Except
if TADOconnection.Errors.Count>0 then
Case TADOconnection.Errors[0].NativeError of
xx:...
End;
End;
TADOconnection.Errors[0].NativeError中返回的是数据库原始错误编号,根据此编号查数据库帮助就可以得知具体的错误信息。比如Oracle的1005,1017号就是用户名或密码错,12154是服务器不存在。

TADOconnection.Errors[0].Description
TADOconnection.Errors[0].Number

http://topic.csdn.net/t/20011006/23/313923.html

标签: ,

Get text from the control at pos x,y on screen

From Zarko Gajic

This form has 3 labels and a timer component: ~~~~~~~~~~~~~~~~~~~~~~~~~
unit unit1;

interface

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

type
TForm1 = class(TForm)
Timer1: TTimer;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure FormCreate(Sender: TObject) ;
procedure Timer1Timer(Sender: TObject) ;
private
procedure ShowHwndAndClassName(CrPos: TPoint) ;
public
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ShowHwndAndClassName(CrPos: TPoint) ;
var
hWnd: THandle;
aName,
Text : array [0..255] of char;
begin
hWnd := WindowFromPoint(CrPos) ;
Label1.Caption := 'Handle : ' + IntToStr(hWnd) ;

if boolean(GetClassName(hWnd, aName, 256)) then
Label2.Caption := 'ClassName : ' + string(aName)
else
Label2.Caption := 'ClassName : not found';
SendMessage(hWnd, WM_GETTEXT,
SizeOf(Text), integer(@Text)) ;
Label3.Caption := 'Text :' + Text;
end;

procedure TForm1.FormCreate(Sender: TObject) ;
begin
Form1.FormStyle := fsStayOnTop;
Timer1.Interval := 50;
end;

procedure TForm1.Timer1Timer(Sender: TObject) ;
var
rPos: TPoint;
begin
if boolean(GetCursorPos(rPos))
then ShowHwndAndClassName(rPos) ;
end;
end.

http://delphi.about.com/cs/adptips2000/a/bltip1200_2.htm

标签:

星期五, 三月 28, 2008

WIN32下DELPHI中的多线程【变量存储】(三)

线程中的变量
由于每个线程都代表了一个不同的执行路径,因此,最好有一种只限于一个线程内部使用的数据,
要实现上述目的有以下几种方式:
1、局部变量(基于栈),很简单,在你的线程函数中你定义的变量既是如此。由于每个线程都在各自的栈中,各个线程将都有一套局部变量的副本,这样,就不会相互影响。对于那些只在过程或函数的生存期有意义的变量,应当把它们声明为局部变量。
2、存储在线程对象中。还记得createthread函数中的lpparameter参数吗,它可以接受一个无类型的指针。结合本文第一章的内容,你应 该还记得,它被存储在线程内核对象的上下文结构中,你可以通过context结构中的context_integer部分的ebx来读取它的地址。
下面是一段示例代码,用来演示读取context结构,这段代码一般用不到,但它可以说明cratethread函数中的lpparameter被存储的位置

{
作者:wudi_1982
联系方式:wudi_1982@hotmail.com
转载请著名出处,本代码为演示代码,只贴出了一些关键部分
}


type
//传递给线程函数的结构和指针的声明
tinfo = record
count : integer;
x : integer;
y : integer;
end;
pinfo
= ^tinfo;

var
mythreadhad : thandle;
//一个全局变量,用来保存线程的句柄

//线程函数
function mythread(info : pointer):dword; stdcall;
var
i : integer;
begin
//根据传递来信息决定在窗口的那个位置输出什么信息
for i := 0 to pinfo(info)^.count-1 do
form1.image1.canvas.textout(pinfo(info)
^.x,pinfo(info)^.y,inttostr(i));
//freemem(info);
result := 0;
end;

//创建一个线程
procedure tform1.button4click(sender: tobject);
var
ppi : pinfo;
mythreadid : dword;
begin
//分配空间并赋初值
ppi :=allocmem(sizeof(tinfo));
ppi
^.count := 1000000;
ppi
^.x := 10;
ppi
^.y := 10;
//创建
mythreadhad := createthread(nil,0,@mythread,ppi,create_suspended,mythreadid);
//在窗体上显示线程函数的地址和传递给它的参数的地址
labthreadaddr.caption := inttostr( integer(@mythread));
labthreadpvparam.caption :
= inttostr(integer(ppi));
end;

//读取context结构,注意context结构是和cpu有关的,我这里测试时,工作在intel的cpu上
procedure tform1.btnrcontextclick(sender: tobject);
var
con : _context;
begin
//初始化结构
con.contextflags := context_full;
//读取
getthreadcontext(mythreadhad,con);
//显示在窗体的listbox上
with lbxcontextinfo.items do
begin
// clear;
add(------------context--------------);
add(
);
add(