相信许多公司虽然用上了tiptop erp系统,但是Excel在表格制作或者数据分析方面仍然起着举足轻重的作用。鼎新有自己的产生excel文件的方式,就是产生xml格式的excel文件,这种方式复杂,不直观,而且格式也不是微软默认的二进制格式的文件,要从excel文件中导入数据到tiptop数据库中就更无从谈起。
那么有没有其他的办法呢?
经过笔者对GDC的分析并且参考了4js官方提供的GDC手册,找到了实现的方法。通常在其他开发工具中(例如VB,Delphi),我们可以使用COM的方式来跟excel application进行通讯,那么,GDC也是透过同样的方式来实现。
因为GDC是一个客户端的工具,所以实现COM完全没有问题。它通过ui,interface.frontcall()这个函数来实现,此函数有以下的几种调用方法:
1:CALL ui.interface.frontcall("WinCOM","CreateInstance",[program],[handle] ##创建COM实例
1.program参数是在系统中注册的COM对象的类名。
2.handle是一个整型变量,用来接收函数返回的状态值。
3.如果函数调用时产生错误,则handle返回-1,如果没有错误,则此值可以在后续的API函数中使用。
2:CALL ui.interface.frontcall("WinCOM","CallMethod",[handle,method,arg1,...],[result]) OR [handle,method(arg1,...)],[result]) #调用对象指定的方法
1.handle是其他前端调用函数返回的句柄(比如:CreateInstance,CallMethod,GetProperty)。
2.method是调用的函数名字。
3.arg1...这些是传递给此方法的参数,对于我们本文说的excel来说,可以用宏的方式来确定参数是否正确,这个后面还会述及。
4.result是一个返回值,如果值为-1,表示有错误。
3.CALL ui.interface.frontcall("WinCOM","GetProperty",[Handle,member],[result] #获得属性
1.handle意义同上。
2.member是要获得的属性的名字。
3.result意义同上。
4.CALL ui.interface.frontcall("WinCOM","SetProperty",[handle,member,value],[result] #设置属性
1.handle意义同上。
2.member是要设置的属性的名字。
3.value是属性的值。
4.result意义同上。
5.CALL ui.interface.frontcall("WinCOM","GetError",[],[result] #获取错误信息
1.result是最后一次错误的描述。
2.如果没有错误,则返回NULL值。
6.CALL ui.interface.frontcall("WinCOM","ReleaseInstance",[handle],[result])
1.handle意义同上。
2.result为-1表示调用有错误,没有错误时,其值为0。
简单介绍完以上的函数之后,我们以一个例子来说明,这些函数的用法,代码如下:
define xlapp integer define xlwb integer main define result integer define str string define filename string let xlapp = -1 let xlwb = -1 ##### 创建excel实例 ##### call ui.interface.frontcall("WinCOM","CreateInstance",["Excel.Application"],[xlapp]) call checkError(xlapp,__LINE__) ##### 新建excel文件或者打开现有的excel文件 ##### --call ui.interface.frontcall("WinCOM","CallMethod",[xlapp,"WorkBooks.Add"],[xlwb]) #新建 let filename="c:\\temp\\test.xls" call ui.interface.frontcall("WinCOM","CallMethod",[xlapp,"WorkBooks.Open",filename],[xlwb]) #打开原来的 call checkError(xlwb,__LINE__) ##### 使excel实例可见 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlapp,"Visible",true],[result]) call checkError(result,__LINE__) ##### 设定sheet2为当前的sheet ##### call ui.interface.frontcall("WinCOM","CallMethod",[xlwb,'Sheets("Sheet2").Select'],[result]) call checkError(result,__LINE__) ##### 显示格线 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlapp,"ActiveWindow.DisplayGridlines",false],[result]) call checkError(result,__LINE__) ##### 填充单元格数据 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2").Value',"中国人民"],[result]) call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Cells(3,2).Value',"方法1"],[result]) call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Cells(4,2).Value',"方法2"],[result]) call checkError(result,__LINE__) ##### 单元格画线 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(7).LineStyle',1],[result]) #左边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(7).Weight',-4138],[result]) #左边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(8).LineStyle',1],[result]) #上边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(8).Weight',-4138],[result]) #上边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(9).LineStyle',1],[result]) #下边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(9).Weight',-4138],[result]) #下边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(10).LineStyle',1],[result]) #下边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(10).Weight',-4138],[result]) #下边 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(12).LineStyle',1],[result]) #内部水平线 call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("B2:B4").Borders(12).Weight',2],[result]) #内部水平线 call checkError(result,__LINE__) ##### 单元格合并 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("D2").Value',"此处为合并单元格"],[result]) call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("D2:F5").HorizontalAlignment',-4108],[result]) call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("D2:F5").VerticalAlignment',-4108],[result]) call checkError(result,__LINE__) call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Range("D2:F5").MergeCells',true],[result]) call checkError(result,__LINE__) ##### 设置列宽 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Columns("E:E").ColumnWidth',15],[result]) call checkError(result,__LINE__) ##### 设置行高 ##### call ui.interface.frontcall("WinCOM","SetProperty",[xlwb,'activesheet.Rows("1:1").RowHeight',25],[result]) call checkError(result,__LINE__) ##### 获取单元格的值 ##### call ui.interface.frontcall("WinCOM","GetProperty",[xlwb,'activesheet.Range("A1").Value'],[str]) call checkError(str,__LINE__) display "content of the cell is :" || str ##### 获取行数 ##### call ui.interface.frontcall("WinCOM","GetProperty",[xlwb,'activesheet.UsedRange.Rows.Count'],[result]) call checkError(result,__LINE__) display "Total Used Rows is :" || result ##### 获取列数 ##### call ui.interface.frontcall("WinCOM","GetProperty",[xlwb,'activesheet.UsedRange.Columns.Count'],[result]) call checkError(result,__LINE__) display "Total Used Cols is :" || result call freeMemory() end main function freeMemory() define res integer if xlwb != -1 then call ui.interface.frontcall("WinCOM","ReleaseInstance",[xlwb],[res]) end if if xlapp != -1 then #call ui.interface.frontcall("WinCOM",'CallMethod',[xlapp,'Quit'],[res]) #退出 call ui.interface.frontcall("WinCOM","ReleaseInstance",[xlapp],[res]) end if end function function checkError(res,lin) define res integer define lin integer define mess string if res = -1 then display "COM Error for call at line:", lin call ui.interface.frontcall("WinCOM","GetError",[],[mess]) display mess call freeMemory() display "Exit with COM Error." exit program (-1) end if end function
以上代码只是一个简单的例子,抛砖引玉而已,你可以将其扩充一下,使其可以导出tiptop erp的业务数据,而且可以加入业务逻辑,使excel作为一个报表工具;或者把excel的数据导入tiptop中做进一步的分析,减少用户输入的时间。
在控制excel的时候,有以下的说明供参考:
1.如何知道property的语法?
有个简单的办法,打开一个excel文件,选择录制宏,然后做相应的操作,然后结束录制,查看宏代码,这里的代码虽然是VBA的,但是拿来参考基本上没有问题的。
2.VBA代码中的常量(比如:xlThin,xlMedium等),在BDL代码中不认识怎么办?
可以去网上查,问问谷哥或者度娘,他们一定会告诉你的。
或者也可以来问我,我有完整的文档。(我的是borland工程师整理的,原本是用在delphi中的),如果用的特别多的,也可以把这些常量放在一个4gl文件中,作为global的方式使用在代码中,这样就比较方便了。比如上例中的activesheet.Range("B2:B4").Borders(10),为什么是10呢?这个就是VBA代码中翻译过来的。
后记:
理论上讲,用GDC可以控制所有的COM对象,比如:Word,Outlook等。当然这个大多限于微软的系统,因为COM本身就是微软所倡导的技术。这里的GDC,也只限于GDC for Windows.以上代码在GDC 2.02.04,GP5环境下测试成功,其他环境无法保证。作者参考的官方网址:http://www.4js.com/online_documentation/fjs-gdc-manual-html/User/WinCOM.html 有兴趣的可以深入研究一下。