在1998年前后,Powerbuilder6.5是比较流行的。 应用它开发企业数据库系统很顺手,既能充分发挥了面向对象编程的优点,同时又能兼顾了面向过程的快捷,在当时的市面上,基础类库比较很多很全,程序员只要熟悉用户想法写起程序来很快,用心的话今天你提出想法,明天就可以让用户使用程序。 当时开发网站还流行CGI,就是通用网关接口,Powerbuilder与HTML结合做网页也是个不错的选择,我当时做的动态网页就是用Powerbuider的CGI来实现的。 同时期还有VB5、Foxpro2.5B,这两个软件我也使用了很长时间,我使用VB5写了俄罗斯方块游戏,使用Foxpro2.5B写了好些数据库程序,可惜它们都无法与Powerbuilder相提并论。 Powerbuilder写程序实在是快,而且处理用户变更的代价也小一些,只要程序员有一点耐心就行。 Powerbuider的一些优点让开发者印象深刻,比如强大的数据窗口、灵活的动态游标、丰富的Windows API应用等等。 可惜,这么好的开发工具,到2005年以后就慢慢开始落后了,当时大家都转C#、Java或者Web开发。 现在看来,开发上选择C#、Java、C/C++、JavaScript+HTML+CSS+前端Web框架是一直跟上这个时代的。 所以,作为开发者选对一个适合自己的又跟上时代的开发工具太重要了。
现在要写一个Windows的C/S小程序,用户对开发不了解,也不清楚该具体的操作界面,想到哪儿就说到哪儿,临时搭建一个Powerbuider6.5的开发环境,展示我所理解的用户意图,再根据用户的建议进行快速修正,定型后再选择其他的开发工具进行开发。 用户需要小程序根据不同用户生成不同的Word文件(有模板,但是模板内的数据是不一样的,有文字、图片和表格)。
主要操作: 1、存储Word文件; Word文件为标书文件,里面有书签,书签名存入数据库。 将Word文件读入到Blob变量:
long L1,LLength,ILoop,IFileNum,LNewPos,ICOUNT,LBytes
string docname,SFileName
blob b_tmp
BlobDataOK=false
//提取文件
L1 = GetFileOpenName("请选择要上传的模板文件", docname, SFileName, "", "*.*" )
if L1=1 then
//提取文件内容
BlobFileData=blob('')
LLength=filelength(SFileName)
IFileNum=fileopen(SFileName,streammode!,read!,lockread!)
//计算读取文件的次数,一次不能读取大于32K的数据
if LLength>32765 then
if mod(LLength,32765)=0 then
ILoop=LLength/32765
else
ILoop=LLength/32765 +1
end if
else
ILoop=1
end if
LNewPos=0
//开始读取文件
for ICOUNT=1 to ILoop
LBytes=fileread(IFileNum,b_tmp)
BlobFileData=BlobFileData+b_tmp
LNewPos=LNewPos+LBytes
fileseek(IFileNum,LNewPos,frombeginning!)
next
fileclose(IFileNum)
BlobDataOK=true
else
wf_SetStatus("程序在读取文件的过程中遇到错误而停止读取!")
end if
存入数据库:
insert into httemplatefile values(:SItemName,:SServerUser,:DTServerNow,:SItemMemo,'') using HTDB;
HTDB.AutoCommit = true
updateblob httemplatefile
set c05=:BlobFileData
where c01=:SItemName using HTDB;
2、提取Word文件 根据不同用户提取不同的书签,针对书签一一写入不同的值。 创建读取Word的对象并操作:
oleobject o_word
o_word=create oleobject
if o_word.ConnectToNewObject("word.application")=0 then
//输出模板文件
selectblob c06 into :B_1 from HTDocxFile where c01="评分表模板" using HTDB;
gf_writedatatodisk(SFileTEMP,B_1)
//打开模板文件准备写操作
o_word.Documents.open(SFileTEMP)
SBookMark="商务小计"
o_word.selection.goto(true,0,0,SBookMark)
o_word.selection.typetext(string(ISWTJ))
......
o_word.ActiveDocument.SaveAs("c:\评分表模板1.doc")
o_word.ActiveDocument.close()
o_word.quit
o_word.DisconnectObject()
else
openwithparm(w_messagebox,"调用Word失败!")
end if
3、Word里面有表格怎么处理? 生成一个标准表格存入数据库,表格里面有书签,也像上面一样处理,生成最后文件后整体插入标书的Word文件中。
//删除多余的表格行
for IFOR=ISW to 8
SBookMark="商务0"+string(IJS)+"_A"
o_word.selection.goto(true,0,0,SBookMark)
o_word.selection.Rows.Delete
next
把用过的代码写下来。
//使用游标提取数据//
declare c1 cursor for select distinct c02 from StyleTable where c01=:SStyleType using HTDB;
open c1;
fetch c1 into :SName;
do while HTDB.sqlcode=0
......
fetch c1 into :SName;
loop
close c1;
//窗体动画代码//
long ll_handle
ll_handle = Handle ( This )
Randomize ( 0 )
Choose Case rand ( 6 )
Case 1
AnimateWindow ( ll_handle, 1000, AW_SLIDE + AW_VER_POSITIVE + AW_ACTIVATE )
Case 2
AnimateWindow ( ll_handle, 1000, AW_SLIDE + AW_VER_NEGATIVE+ AW_ACTIVATE )
Case 3
AnimateWindow ( ll_handle, 1000, AW_SLIDE + AW_HOR_POSITIVE + AW_ACTIVATE )
Case 4
AnimateWindow ( ll_handle, 1000, AW_SLIDE + AW_HOR_NEGATIVE + AW_ACTIVATE )
Case 6,5
AnimateWindow ( ll_handle, 1000, AW_SLIDE + AW_CENTER + AW_ACTIVATE )
End Choose
function boolean AnimateWindow ( long hwnd, long dwtime, long dwflags ) library "user32"
Function ulong GetCurrentDirectoryA(ulong BufferLen,ref string currentdir) LIBRARY "kernel32.dll"
Function long GetShortPathNameA( string lpLong, ref string lpShort, long lBuff ) library "kernel32"
integer i_cs
constant long AW_HOR_POSITIVE = 1
constant long AW_HOR_NEGATIVE = 2
constant long AW_VER_POSITIVE = 4
constant long AW_VER_NEGATIVE = 8
constant long AW_CENTER = 16
constant long AW_HIDE = 65526
constant long AW_ACTIVATE = 131072
constant long AW_SLIDE = 262144
constant long AW_BLEND = 524288
//Word文件处理//
API声明:
Function Long ShellExecuteA (Long hwnd, String lpOperation, String lpFile, String lpParameters, String lpDirectory, Long nShowCmd) Library "shell32.dll"
执行代码:
//查看应用程序当前目录下有无所需要的文件
string s_tempname1,s_tempname2, s_docname1,s_docname2
string s_1,s_false,s_psp //s_psp为模板文件
boolean cando=true
//从数据库中分别提出RTF的临时文件和WORD最终文件
//(分别对应试题卷和答案卷)的存放目录和具体文件名
select c03 into :s_tempname1 from sys_config where c02='RTF1' using now_gx;
....
//如果存在就删除
if fileexists(s_tempname1) then
filedelete(s_tempname1)
end if
if fileexists(s_tempname2) then
filedelete(s_tempname2)
end if
//将RTF控件中的内容另存为临时文件
ole_1.object.SaveFile(s_tempname1, 0)
ole_2.object.SaveFile(s_tempname2, 0)
//判断该文件在不在
if ole_1.object.text="" then
cando=false
s_false="考试卷内容为空!"
end if
//如果存在已经WORD最终文件就删除
if fileexists(s_docname1) then
if not filedelete(s_docname1) and not filedelete(s_docname2) then
cando=false
s_false="正在编辑,不能多次启动!请关闭编辑工具!"
end if
end if
//准备工作都正确
if cando then
oleobject o_word
o_word=create oleobject
if o_word.ConnectToNewObject("word.application")=0 then
show_message("正在对考试卷排版......")
//打开模板文件
s_psp=a_apppath+”\”+” gx_psp.doc”
o_word.Documents.Open(s_psp)
//在模板文件中执行插入文件
o_word.selection.InsertFile(s_tempname1)
//根据选择执行单面装订线和双面装订线的宏
if danmian then
o_word.Application.Run("装订线")
else
o_word.Application.Run("sm装订线")
end if
//将模板文件的内容全部拷贝出来
o_word.Selection.WholeStory()
o_word.Selection.Copy
//关闭模板文件
o_word.ActiveDocument.close()
//在WORD中新建一个文件,执行粘贴,
//再另存为试题卷后关闭活动文档。
o_word.documents.add
o_word.Selection.Paste
o_word.ActiveDocument.SaveAs(s_docname1)
o_word.ActiveDocument.close()
show_message("正在准备答卷......")
o_word.Documents.Open(s_psp)
o_word.selection.InsertFile(s_tempname2)
o_word.ActiveDocument.SaveAs(s_docname2)
o_word.quit
o_word.DisconnectObject()
ole_1.object.text=""
ole_2.object.text=""
//启动WORD,分别打开试题卷和答案卷
string s_tmp
setnull(s_tmp)
ShellExecuteA (handle(parent),s_tmp,s_docname2,s_tmp,s_tmp,1)
ShellExecuteA (handle(parent),s_tmp,s_docname1,s_tmp,s_tmp,1)
else
show_message("调用排版编辑器失败!")
end if
else
show_message(s_false)
end if
//参数说明:
// dec_top:纸张上边距 dec_bottom:纸张下边距
// dec_left:纸张左边距 dec_right:纸张右边距
// dec_width:纸张宽度 dec_height:纸张高度
// i_line_words:每行字符数 i_page_lines:每页行数
// dec_lm:栏目宽度 dec_mid:中缝宽度
//计算公式:每栏宽度=(纸张宽度-左边距-右边距-中缝宽度)/2
…… …
o_word.documents.add
show_message("正在设置排版参数......")
//设置页面属性
o_word.ActiveDocument.PageSetup.LineNumbering.Active=false
o_word.ActiveDocument.PageSetup.Orientation=1
o_word.ActiveDocument.PageSetup.TopMargin=dec_top
o_word.ActiveDocument.PageSetup.BottomMargin=dec_bottom
o_word.ActiveDocument.PageSetup.LeftMargin=dec_left
o_word.ActiveDocument.PageSetup.RightMargin=dec_right
o_word.ActiveDocument.PageSetup.Gutter=0
o_word.ActiveDocument.PageSetup.HeaderDistance=1.5
o_word.ActiveDocument.PageSetup.FooterDistance=1.75
o_word.ActiveDocument.PageSetup.PageWidth=dec_width
o_word.ActiveDocument.PageSetup.PageHeight=dec_height
o_word.ActiveDocument.PageSetup.DifferentFirstPageHeaderFooter=false
o_word.ActiveDocument.PageSetup.SuppressEndnotes=false
o_word.ActiveDocument.PageSetup.MirrorMargins=false
o_word.ActiveDocument.PageSetup.TwoPagesOnOne=false
o_word.ActiveDocument.PageSetup.GutterOntop=false
o_word.ActiveDocument.PageSetup.Charsline=i_line_words
o_word.ActiveDocument.PageSetup.LinesPage=i_page_lines
o_word.ActiveDocument.PageSetup.TextColumns.SetCount(2)
o_word.ActiveDocument.PageSetup.TextColumns.EvenlySpaced=true
o_word.ActiveDocument.PageSetup.TextColumns.LineBetween=false
o_word.ActiveDocument.PageSetup.TextColumns.Width=dec_lm
o_word.ActiveDocument.PageSetup.TextColumns.spacing=dec_mid
o_word.Selection.TypeParagraph()
show_message("正在对考试卷排版......")
o_word.selection.InsertFile(s_tempname1)
o_word.Selection.ParagraphFormat.LineSpacingRule = 0
//o_word.Selection.ParagraphFormat.LineSpacing=24
o_word.ActiveDocument.SaveAs(s_docname1)