如鹏网 大学生计算机学习社区

CowNew开源团队

http://www.cownew.com 邮件请联系 about521 at 163.com

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  363 随笔 :: 2 文章 :: 808 评论 :: 0 Trackbacks

#

  这篇文章昨天怎么也贴不上去,今天贴一贴试试。今天的blog锻炼回来再写。
  今天早上起来不知怎么的感觉特别累。来深圳三个多月依来这是第一次感觉这么累,可能和这两天连续奋战有关系吧。忙过了这阵子要稍微修整一下了,否则身体垮了就太不值得了。不知道是产品延期发版了兄弟们有点放松警惕了,还是前两天市场部一个同事去世对同事们敲响了警钟了,大家下了班都早早的回家了。只有少数几个人仍在坚守岗位,我当然就是其中一个了。给现场支持的同事写了一个使用帮助文档,然后我就琢磨起DB2来。来这个公司最大的好处就是可以接触很多高级的东西,呵呵。
  不管你说DB2强大也好,稳定也好,但从一个开发者的角度来讲总感觉用着不舒服。比如它竟然不支持修改一个字段的类型,一旦你字段类型定义错了,那么就必须删掉重来,很恐怖呀。还有它的错误提示信息也很让人摸不到头脑,执行insert语句的时候如果某个字段不允许为空,它就提示你一个什么tableid=**,colId=**之类的,然后再告诉你怎么根据tableid=**,colId=**去查到底是哪个字段不允许为空。真是奇怪了,你帮我查出来,然后显示给我不好吗?在这一点上还是感觉微软的东西好用呀。所以在mssql上开发,然后到DB2上部署也是个不错的选择。各取所长呀。
  今天看了看HTC,也做了一个简单的例子。一开始怎么也无法运行,后来发现在PUBLIC:与ATTACH之间不能有空格,否则就无法出现预期的效果。又看了看网上对htc的评论并不是很好,主要就是集中在资源消耗、稳定性和微软以后将不再支持方面。特别是温少的评论更有权威呀,他是见证了EAS.NET成败的一个人,对HTC的优劣认识更深。抽时间和他聊聊,好在是一个Company的,只是不知道人家高手会不会有时间陪咱聊呀。呵呵。
  太阳走了,留下的是星光;
  云朵走了,留下的是蓝天;
  微笑走了,留下的是阴霾;
  你走了,留下的是回忆。
  风吹走了你,风吹干了泪,
  留下的是干枯的双眼。

posted @ 2005-10-27 21:04 CowNew开源团队 阅读(737) | 评论 (3)编辑 收藏

  继续数据导入中,呵呵,不过终于看到曙光了,是骡子是马周四提到客户现场就知道了。今天晚上又忙了一阵子,J2EE打包部署很是麻烦呀,害的我叫得快餐都凉了才囫囵吞枣的吃了两口。
  回到宿舍同宿舍的兄弟想通过网络邻居访问我的电脑,但是就是访问不了,于是乎上网查了一下网络邻居的原理。这一查不要紧呀,太搞笑了,微软的网络邻居实现的这么“民主”呀,竟然是谁先进来、谁更高级就推举谁当主浏览器,竟然还要选出一个“副手”做为备份,呵呵。不过不知道为什么微软当初这样设计,很容易就出现网上邻居不可用呀,不过好在大部分人用网络邻居用的不是很多。
  这两天对web的Rich client开发一直很感兴趣,翻了翻公司控件开发部的服务器,人家做的确实不错,用htc做的web前端太漂亮了,看来我要花一段时间研究研究htc了,虽然说htc是依赖IE6的,但是在企业级web开发中这也不是什么问题,我可不是那种敌视微软的pure***的程序员。只要能快速完美的满足客户各种“变态”的需求,我就认为它是好的技术。 
  下载了一些htc的教程和一些示例代码,我也不打算深入学习,毕竟我还是想多在java企业级开发上边下功夫,但是多接触点东西还是好的。在这行混的一个准则是你不必对什么都精通,但是必须什么都了解一点,其实业界更缺少的是这种“蜻蜓点水的专才”。话题扯远了,还是说说HTC吧。HTC确实是web界面开发的一种进步,但是我感觉进步还不是很快,呵呵。如果能象Delphi或者.net那样具有完全行为和属性的组件体系的话就更完美了,程序员只要在htm中输入类似于下面的代码就可以将控件引入。<MyComponent/>。听说微软正在将HTC做为web标准提向w3c,希望能得到批准,并且做的更完美,那样就能大大节省我们的开发时间了。
  好了,不早了,我要休息了,这两天我看看htc的教程和代码,我会及时与大家交流自己的心得体会的。
posted @ 2005-10-26 00:55 CowNew开源团队 阅读(1153) | 评论 (2)编辑 收藏

  数据导入功能终于做的差不多了,服务器端导入模式也试了一下,临下班之前还有nullpointerexception错误没有解决,还有就是生成凭证有问题。总感觉项目中有太多将就的东西了,底层开发框架设计的很好,扩展性也很强。但是业务框架就差很多了,那个凭证生成平台竟然建立在源单据要建立一个名字为fivouchered字段的基础之上,否则根本跑不起来,耦合性太强了,而且这种耦合是很不容易被发现的。周四就要把做的这个Demo发到客户现场了,希望一切都平安,否则下周甚至下下……下周都不可能安心进入项目开发了。今天项目组开例会没有前一阵子那么忙碌了,产品延期发版了两个多月,战友们也感觉压力小了许多。但是风险是无处不在的,只希望需求、开发、测试合作更紧密一点,交流更通畅一些,多快好省的让产品发版,少点全员加班。
  忙是忙,总不能把自己困死在工作上的。毕竟还是要自己学点东西的。本想回来看一看hibernate的源代码的,但是同宿舍兄弟刚买了台电脑要用我的电脑做代理上网。生平第一次看到用双网卡实现共享上网,又学了一招,我那个兄弟可是个网络高手,以后要经常向他学习了,等有时间买个小路由,让他教教我怎么配置路由器。
  时间不多只能把我前一阵子研究的java中调用脚本语言的东西拿出来整理一下了。java中调用脚本语言有很广泛的用途,比如用户自定义公式,自定义单据转换规则,用户自定义工作流等等。java中调用脚本语言有很多中实现,比如Jython、Groovy、Beanshell等等。但是即使对于有一定开发经验的程序员学习它们是需要一段时间的。而提起脚本,无论是程序员还是有一定软件开发基础的客户(例如客户公司的网管、信息管理员等等)都会想起javascript和VBScript,如果我们的系统使用这些用户熟悉的脚本语言,必将降低系统学习的难度。VBScript是捆绑在windows平台下的,因此javascript就成了我们专注的对象。javascript引擎可以在NetScape的js.jar中找到,而现在这个包已经做为一个开源项目独立出来了,项目的名字是Rhino,项目网站:http://www.mozilla.org/rhino/。
  Rhino支持javascript标准的所有特性,如赋值、运算、判断语句、循环语句、甚至简单的io操作。Rhino很简单易用,我以一个例子来说明,这个例子就是允许用户设定一个使用x,y两个变量进行一定逻辑算术运算(运算规则用户用javascript定义),并允许用户对x,y赋值,然后运行得出计算结果。代码如下:
        Context ctx = Context.enter();
        Scriptable scope = ctx.initStandardObjects();
       
        scope.put("x", new Integer(20));
        scope.put("y", new Integer(30));
        try
        {
          ctx.evaluateString("if(x",1,null);
          System.out.println(scope.get("result", scope));
        }
        finally
        {
            Context.exit();
        }
很简捷吧。scope.put("x", new Integer(20))的意思是为变量x赋值,ctx.evaluateString("if(x",1,null); 则是运行javascript脚本,而scope.get("result", scope)则是得到运算结束后变量的值,我们采用result做为返回值,所以scope.get("result", scope)就表示得到返回值。不错吧。嘿嘿,很方便呀。
  好了,都凌晨一点钟了,该睡觉了,明天还要改bug呢,争取提前把任务搞定,周五调休。
posted @ 2005-10-25 22:58 CowNew开源团队 阅读(4739) | 评论 (5)编辑 收藏

  今天又搞了一天的数据导入程序,本以为今天会比较轻松,没想到有忙忙乎乎了一天。中午晚上都是叫得外卖(野生菌肉片饭,TNND香死了,嘻嘻!),而且都是用10分钟搞定入肚。不过感觉鲜粉人家的饭就是比桃源村那个布拉粉肠王的好吃,更别提冶金大厦下边那个嘉惠餐厅了,要不是俺口袋里银子不多,我才不去那个垃圾餐厅呢。不过更羡慕那些从家里带饭来的XDJM呀,有家的感觉真好,连饭都是热的,不像俺们,在盘子里是热的,吃到嘴里是凉的,进到肚子里是冰的,冰得人心痛。
  东软那帮人真垃圾,让他们提供个数据接口他们都故意为难你,让你得程序绕了八百个弯才把数据导进去,而且还有很小的精度误差。东软我真服了了你了,你怎么也算是国内有影响的大公司了吧,怎么这样的胸怀都没有呀,刘鸡人呀,I 他妈 服了 You!
  抽空给在济南兼职的时候那个项目经理打了个电话。年纪大了就是罗嗦了呀,今天又跟我说他在深圳的几个同学都没有结婚之类的话,言语中有一点不理解又有一些羡慕。想想也是呀,他都是一个7岁小丫头的爸爸了,而比他大的同学还在耍单,肯定羡慕死他呀。至于他们为什么还在耍单,他也没说。不过我听说过一句话,来深圳的女人分为三种:当过鸡的,正在当鸡的,将要当鸡的。应该还有下文吧,来深圳的男人分为三种:被伤害过的,正在被伤害的,将要被伤害的。被伤害的男人为了忘掉过去,为了自强,一堵气来深圳创自己的一片天下;正在被伤害人带着意思遗憾来深圳疗伤;而来了深圳的幸福男人总会有一天尝到来这的苦果,从此弄的遍体鳞伤,封闭自己的内心,从此落寞。
posted @ 2005-10-24 00:52 CowNew开源团队 阅读(517) | 评论 (4)编辑 收藏

    晕死,今天加了一天的班,还没有搞定,明天还要加班呀,不过还好,明天不用那么累了。工作再怎么累也不能让身体垮掉呀,再说那花了我七百块大洋的健身卡也不能浪费。进了健身房,冲前台的小MM抛了无限神情的媚眼以后就开始跑跑跳跳,上上下下,弯弯挺挺的,各种姿势的,每天不同而又相同的运动中了。今天精神不是太好,举重举到第30个就“不举”了。才跑了10分钟小跑已经大汗淋漓,索性不跑了。走出健身房的时候,前台小MM那句柔情万千的“bye bye”把我弄得浑身麻酥酥的,不过想想人家对会员都这样,你自作多情干什么,靠,犯贱!周末社区里的人不多,不过还是能看见或一对、或一家的在社区那散步。在深圳这个找不到家的感觉的地方,时常的在这个社区里散散步也许还能找回自己活着的感觉。可是那个“家的感觉”是人家的,你的“家”不照样是那个月租380的小房间吗?再次犯贱!
  回到宿舍把电脑打开,《大话西游》终于下完了,看来电信还没有完全屏蔽BT呀。你说我幼稚也好,说我低俗也好,说我落伍也好,但是《大话西游》我是百看不厌。也许我就是那个孙悟空转世吧,只是也许轮回太多了,当初的猴崽子已经变成了一只小胖娃娃。但是不变的是命运的安排。也许你曾自由飞翔、也许你是山贼、也许和紫霞轰轰烈烈、也许对晶晶眉来眼去,但命中注定你要被烙上那三棵痔,注定要被套上紧箍咒。曾经的爱你一万年的海誓山盟,曾经在你心中留下眼泪的女人,曾经帮你踩灭大火的兄弟,这些都将离你而远去。不要再回忆,不管它曾多么美好,命中注定前行才是你的方向。为你而被杀死的那些兄弟们是否已经投胎,被师傅折磨而自尽的两个小妖是否已经变回原型,盘丝洞是否会有新的主人,在城堡上拥抱的他们是否会幸福永远,这些都不用你再管,不用你再操心,他们都象你一样在命运定律的安排下有序的运转着。你需要的只是抹去紫霞在你唇边留下的香味,背起铁棒,象一条黄狗一样离开曾经的全部,然后扔掉香蕉皮,向命中注定的地方前行。
posted @ 2005-10-23 01:00 CowNew开源团队 阅读(350) | 评论 (0)编辑 收藏

   类似于Delphi的窗体设计器界面,用户可以自由拖放控件,并可以编辑控件的属性,支持Delphi的属性编辑器的概念。此阿用了反射机制和插件技术,使得增加新的控件非常容易。并可以把设计的窗体保存到文件中,还可以生成exe文件。由于采用的是xml格式保存,并且设计的时候充分考虑了可移植性,因此本程序可以很容易的用其他语言实现,而且生成的窗体文件可以以windows界面或者web界面展示。可以把此程序作为开发工作流引擎或二次开发平台的基础。我会继续开发,开发过程中的经验也将及时与大家分享。
fdesinger1.jpg
posted @ 2005-10-22 01:03 CowNew开源团队 阅读(1315) | 评论 (6)编辑 收藏

 

  近日(呵呵,这篇文章是去年写的)用了两个月开发了一个物流信息系统,这个系统是两层、三层相结合,C/SB/S相结合的系统。虽然限于时间的紧张和人手的原因,系统规模不是很大,但是其中涉及的技术却很全面。在这个《开发技术篇》中我们将讲解我在开发系统中遇到的技术问题及解决方案,希望对大家有帮助。对于物流信息系统的分析设计问题,我将在另一篇文章《物流信息系统开发手记――系统构架篇》中讲解。

 

一、Midas的安全问题。

    Midas技术是Delphi中进行三层开发的首选技术,它不仅有纯DCOM/COM+(COM+技术是.NET技术的基础)的优点,而且也结合了Delphi的快速开发特性,可以快速开发出想要的系统,其开发速度是用VC,PB等开发DCOM的数十倍,把程序员从烦杂的代码中解脱出来,从而将更多的精力投入到业务逻辑的设计中去。

    但是Midas技术的一个最令人担忧的就是它的安全问题:

远端只要知道应用服务器的端口号即可访问到应用服务器,而一旦访问到应用服务器,TClientDataSet即可获得ProviderNames列表。一旦知道了ProviderNames列表,这就相当于将数据库暴露在外了。

关于可轻易获得ProviderNames列表的问题,我使用下面的方法解决:

 在服务器端定义一个

LoginMTS(const AUserId, APassword: WideString): WordBool;

方法。初始状态下,所有的DataSetProvider和数据集的连接断开。用户必须调用LoginMTS并传递用户名和密码,登陆成功才将DataSetProvider和数据集的连接打开。这样如果用户验证没有通过,即使它获得了ProviderNames列表也没法调用接口中的方法对数据库进行操作。

二、Midas中主从表的实现

主从表的应用在信息系统中应用很广。在两层开发中我们可以通过直接建立两个数据集之间为主从关系来实现主从表;在三层中虽然我们仍然可以通过直接建立两个数据集之间为主从关系来实现主从表,但是这样就要求把数据库中所有相关的数据行都下载到本地,丧失了三层开发的优势。我在实际中使用下面的方法实现。这里我以实现入库单查询、添加、修改、删除(CRUD)为例来讲解:

1)新建一个MTS Data Module,命名为TmtsStockInListBiz,增加如下方法:

    function QueryStockInListMasterById(const AId: WideString;

      var ADatas: OleVariant): WordBool; safecall;

    function QueryStockInListSlaveByMasterId(const AId: WideString;

      var ADatas: OleVariant): WordBool; safecall;

    procedure UpdataStockInListMaster(var ADatas: OleVariant); safecall;

    procedure UpdataStockInListSlave(var ADatas: OleVariant); safecall;

    function GenerateStockInListId: WideString; safecall;

 

QueryStockInListMasterById作用是根据入库单单号查询入库单的基本信息(入库日期、负责人等),Aid为入库单单号,Adatas为返回值,其格式就是Midas的数据包,可以将其附给ClientDatSetData属性。

QueryStockInListSlaveByMasterId作用是根据入库单单号查询入库单的详细信息(商品条码,数量)

UpdataStockInListMaster是对入库单主表进行删除、添加、修改操作。只要将ClientDataSetDelta属性做为传递即可。

UpdataStockInListSlave是对入库单从表进行删除、添加、修改操作。

GenerateStockInListId是产生一个唯一的入库单号。

下面是几个方法的代码,都很简单,就不多解释了,可以查看Delphi的帮助。

function TmtsStockInListBiz.QueryStockInListMasterById(

  const AId: WideString; var ADatas: OleVariant): WordBool;

begin

  result := false;

  ADatas := null;

  try

    cdsQuery.Close;

    cdsQuery.CommandText := 'select * from t_StockInListMaster where Id=:Id';

    cdsQuery.Params.ParamByName('Id').AsString := AId;

    cdsQuery.Open;

    if cdsQuery.RecordCount > 0 then

    begin

      result := true;

      ADatas := cdsQuery.Data;

    end;

  finally

    cdsQuery.Close;

  end;

end;

 

procedure TmtsStockInListBiz.UpdataStockInListMaster(

  var ADatas: OleVariant);

var

  eCount: Integer;

  OwnerData: OleVariant;

begin

  DCOMConStockInList.GetServer.AS_ApplyUpdates('dspStockInListMaster',

    ADatas, -1, eCount, OwnerData);

end;

 

function TmtsStockInListBiz.GenerateStockInListId: WideString;

var

  LPrior: string;

  i: Integer;

begin

  cdsQuery.Close;

  cdsQuery.CommandText := 'select top 1 id from t_StockInListMaster order by id desc';

  cdsQuery.Open;

  LPrior := cdsQuery.FieldByName('Id').AsString;

  i := StrToIntDef(RightStr(LPrior,8),0);

  Inc(i);

  result := 'RK' + FormatFloat('00000000',i);

  cdsQuery.Close;

end;

 

2)、新建一个应用程序,通过DCOMConnectionSocketConnection等连接到MTS组件,然后就可以调用MTS的相应的方法实现客户端功能了。

放入cdsStockInListMastercdsStockInListSlave两个ClientDataSet控件,在控件上点击右键,选择“FieldsEditor”新建于服务器中的字段同样的字段,然后再次在控件上单击右键,选择“CreateDataSet”,建立一个本地数据库。

3

根据入库单号查询入库单的方法实现:

procedure TFormStockInList.BtnFindClick(Sender: TObject);

var

  v,vs: OleVariant;

begin

  if SocketConStockInList.AppServer.QueryStockInListMasterById(Trim(LEdtId.Text), v) then

  begin

    cdsStockInListMaster.Data := v;//显示入库单主表(主要信息)

 

    if SocketConStockInList.AppServer.QueryStockInListSlaveByMasterId(Trim(LEdtId.Text), vs) then

      cdsStockInListSlave.Data := vs; ;//显示入库单从表(明细信息)

  end

  else

    ShowMessage('此单不存在!');

end;

4)新建入库单的实现

procedure TFormStockInList.BtnNewClick(Sender: TObject);

var

  LId: string;

begin

  ClearCDSRecord;

  cdsStockInListMaster.Open;

  cdsStockInListMaster.Insert;

  LId := SocketConStockInList.AppServer.GenerateStockInListId;

  LEdtId.Text := LId;

  cdsStockInListMaster.FieldByName('Id').AsString := LId;

  cdsStockInListMaster.FieldByName('GenerateDate').AsDateTime := Now();

end;

5)提交功能的实现

procedure TFormStockInList.BtnPostClick(Sender: TObject);

var

  LQuerymts: ImtsQueryObjDisp;

  LBar: string;

begin

  SetSocketConnectionConnect(SocketConQuery);

  LQuerymts := ImtsQueryObjDisp(SocketConQuery.GetServer);

 

  SocketConQuery.Close;

 

  if cdsStockInListMaster.RecordCount > 0 then

    SocketConStockInList.AppServer.UpdataStockInListMaster(cdsStockInListMaster.Delta);

  if cdsStockInListSlave.RecordCount > 0 then

  SocketConStockInList.AppServer.UpdataStockInListSlave(cdsStockInListSlave.Delta);

end;

注:本文中ClientDataSet控件的名称开头一般为cdsTsocketConnection控件的名称开头一般为SocketCon

三、动态设置TsimpleObjectBroker的服务器列表

procedure SetSocketConnectionConnect(AValue: TSocketConnection);

  procedure FillAppServerList(ABroker: TSimpleObjectBroker);

  var

    sl: TStringList;

    i, n: Integer;

  begin

    sl := TStringList.Create;

    从配置文件中读取服务器列表,并保存到sl;

    n := sl.Count - 1;

    ABroker.ServerData := null;

    for i := 0 to n do

    begin

      ABroker.Servers.Add;

      ABroker.Servers[i].ComputerName := sl.Strings[i]

    end;

    sl.Free;

  end;

var

  LBroker: TSimpleObjectBroker;

begin

  LBroker := TSimpleObjectBroker.Create(nil);

    FillAppServerList(LBroker);

    AValue.ObjectBroker := LBroker;

    try

      AValue.Connected := true;

    except

      raise Exception.Create('应用服务器连接错误!');

    end;

    LBroker.Free;

end;

posted @ 2005-10-22 00:51 CowNew开源团队 阅读(2260) | 评论 (1)编辑 收藏

     摘要:   凌科网页精灵开发手记 杨中科 现在网上有大量的网页特效软件供网页制作者使用,但是大多数网页特效软件只是罗列了如果将网页特效代码添加到html文档中,比如: “ 第一步:把如下代码加入<body>区域中:   <span id=liveclock style=position:absolute;left:250px;top:122px> ...  阅读全文
posted @ 2005-10-22 00:50 CowNew开源团队 阅读(714) | 评论 (0)编辑 收藏

 

《网络吸管》开发手记

网络确实是个好东西,文章呀,图片呀什么的都很吸引人。每次上网都能满载而归,但是这些资料的收集过程却很麻烦。对于好文章,每次都要复制、粘贴地在记事本和IE之间切换多次才能保存下来,而且说不定什么时候遇到那种怎么复制也复制不下来的防复制网页;对于图片也要点右键,选择“图片另存为”,再点确定才可以,遇到文件重名问题还要重命名。上网的兴致全被打乱了。网上虽然也有“网文快捕”之类的小软件,但是由于不是为自己“量身定做”的,所以用起来也不是很顺手。既然这样,就自己动手做一个吧,“自己动手丰衣足食”嘛!说干就干!

设计思想很简单:监视剪贴板,当发现剪贴板中有新内容时,就根据内容是文字还是图片来决定不同的保存方式。

如何监视剪贴板呢?很自然地想到放一个定时器,每隔一段时间检测一个剪贴板,将剪贴板地内容于上次检测地内容相比较,如果不同,就说明剪贴板的内容有变化。但是这样效率太低了,并且定时器的时间间隔也不好把握,间隔太短会降低系统的效率,而间隔太长就有可能漏掉复制的内容。这让我想起了CPU与外设之间通讯方式中的查询方式,那么有没有一种像CPU与外设之间的中断方式的东西呢?启动MSDN,搜索ClipBoard,呵呵!终于找到了!是什么呢?听我慢慢道来!

为了使应用程序能自动感知剪贴板的变化,windows提供了两个API函数。使用SetClipBoard可以将窗体注册到剪贴板观测链中,然后程序就能响应剪贴板的变化消息。剪贴板观察器是一个显示剪贴板当前内容的窗口。剪贴板观察链是一系列相互独立的剪贴板观察窗口,它们都能够接受当前发送到剪贴板的内容。

SetClipBoard的原型是:

function SetClipBoard(hwndNewViewer:HWND):HWND;

hwndNewViewer为要注册的窗体句柄。如果注册成功,则返回剪贴板观测链中下一个窗体的句柄;如果发生错误或无其他窗体,则返回NULL

如果剪贴板发生变化,windows会向窗体发送WM_CHANGECCHAINWM_DRAWCLIPBOARD消息,观测链中每个窗体都会调用SendMessage将该消息传送给下一个窗体。当应用程序退出时,要利用API函数ChangeClipboardChain将窗体从剪贴板观测链中移去。其原型为:

function ChangeClipboardChain(hWndRemove, hWndNewNext:HWND):boolean;

hWndRemove将要删除的窗口的句柄, hWndNewNextSetClipBoard返回的窗体的句柄。

这样我们只要在程序中等待剪贴板变化的消息即可。当消息到来时,我们应该怎样得到剪贴板中的内容呢?Delphiclipbrd.pas单元中定义了一个类TClipboard,它封装了Windows剪贴板,简化了大量复杂的处理过程。我们在程序中可以直接调用全局函数Clipboard,该函数用于返回TClipboard对象实例,使用这个实例对剪贴板进行剪切、复制和粘贴等操作。下面是TClipboard对象的几个常用的方法和属性的简单介绍:

方法:

procedure Clear; 清空剪贴板。

function HasFormat(Format: Word): Boolean; 查询剪贴板中是否有指定格式的内容。可以有三种取值:CF_TEXT(文字)CF_BITMAP(位图)CF_METAFILEPICT(元文件)

属性:

AsText:用于读写剪贴板文字内容。

 

如何给用户保存下来的图片文件命名也是个问题。我们可以设置一个全局整型变量,每当保存一个图片文件时,就令这个变量增加1,将这个整型变量转换成字符串做为文件名。如果指定的文件名已经存在,就要给文件重命名。最简单的办法就是在文件名之前(或之后)加上一个字符串(比如'new'),如果加上这个字符串后还是存在重名的文件呢?这就要用到学编程的人在一开始就学到的一个小技巧:递归。这个问题的解决办法见下面的代码:

procedure SaveToPic(APic: TJPegImage; AFileName: string);

Const PICPLUSSTR = 'new';

begin

  if FileExists(AFileName) then

    savetopic(ABmp, PICPLUSSTR+AFileName)

  else

      SaveBmpAsJpg(APic, AFileName);

end;

 

在实际应用的时候,还应该加上异常处理(如磁盘空间已满,文件名过长等)。图片的保存的基本问题已经解决,我们再来看看文字的保存。为了增强程序的灵活性,我们应该使用用户能方便地将不同地文字保存到不同的文件。继续沿用上面保存图片的方式用数字做文件名吗?当然不可以。一是因为文本文件不像图片那样在资源管理器中可以预览,用户必须打开文件才能知道文件中保存的是什么内容,如果用户想在一大堆“1.txt”、“2.txt”……中找自己想要的内容就太麻烦了;二是因为用户并不要求每次复制下来的内容都保存到单一的文件中,而是要将相关的内容保存到一个文件中。我对这个问题的解决方法是这样的:

用户可以先复制一段文字,然后再按一个热键(比如Ctrl+Alt+S,为什么要选Ctrl+Alt+S做热键呢?后面再说!),这样用户以后复制下的文字就保存到以用户复制的文字做为文件名的文件中。

记得无数位大师说过:“要将用户界面与业务逻辑分开。”好吧,就将上面的东西封装一下,也算是我向OO迈进的第一步吧!(下面之列出了类的部分成员)

  TWebPageSaver = class(TObject)

  private

    FImagePath: string;

    FTextPath: string;

    FImageCount: Integer;

    FTextFileName: string;

    procedure SetImagePath(const Value: string);

    procedure SetTextPath(const Value: string);

  public

    function Save: Boolean;//result is whether the content is saved

    procedure NewTextFile(AFileName:string);

    property ImagePath: string read FImagePath write SetImagePath;

    property TextPath: string read FTextPath write SetTextPath;

  end;

在用户界面中,当用户按下热键Ctrl+Alt+S时,就调用TWebPageSaver.NewTextFile更改文字保存的文件名FTextFileName;当收到剪贴板变化的消息时就调用TWebPageSaver.Save保存剪贴板中的内容。另外还有ImagePathTextPath等属性,可以由用户来更改图片、文字的保存路径。

 

核心代码已经完成,来做一下用户界面吧!仿照着“windows优化大师”我做了如下的界面:

ns1.jpg

 

 

 

 

 

 

很漂亮吧?左边我用的是TSpeedButton组件,右边是TNotePage组件。当用户点击一个TSpeedButton时,调用TNotePage.ActivePage := '页面的代号'就可以激活相应的配置界面。这个软件需要在后台运行,那么就让它在平时缩小到系统托盘吧!将程序缩小到系统托盘很容易做到,网上有很多这样的示例代码。我手头有一个控件cooltray4.3可以用来实现系统托盘的功能,我就懒得自己再去写代码了。

软件运行一切良好。不过一直令我耿耿于怀的就是网上那种防复制的网页:不管你怎么拖动鼠标,那些文字就是无法被选定。仔细想一想,既然文字能够在IE上显示就一定可以得到它们。在MSDN中找了半天,才找到解决方法。可以通过ShellWindows集合来代表属于shell 的当前打开的窗口的集合,而IE就是属于shell的一个应用程序。用CoShellWindows.Create得到当前打开的shell的接口(IShellWindows),调用接口的Count属性得到当前打开的shell的数量,然后遍历这些窗口,尝试从接口中取出IWebbrowser2接口(通过ShellWindow.Item(I) as IWebbrowser2这样的接口类型转换方式),如果结果不为nil说明这个窗口是IE窗口。之后只要调用IWebBrowser2接口的相应方法即可得到窗口中的文字、URL、标题等内容了。

示例代码如下:

{需要使用mshtml,SHdocvw两个单元}  

var

 ShellWindow : IShellWindows;

 WebBrowser : IWebBrowser2;

 I, ShellWindowCount: integer;

 HTMLdocument : IHTMLdocument2;

 URL, Title, Text:string;

begin

  ShellWindow := CoShellWindows.Create;

  ShellWindowCount := ShellWindow.Count;

  for I := 0 to ShellWindowCount-1 do

  begin

    WebBrowser := ShellWindow.Item(I) as IWebbrowser2;

    if WebBrowser <> nil then

        begin

            HTMLDocument := WebBrowser.Document as IHtmlDocument2;

            URL := URL;

            Title := HTMLDocument.title;

            Text := HTMLDocument.body.outerText ;

            ShowMessage(URL+Title+Text);

        end;

  end;

  ShellWindow := nil;

end;

 

我们定义一个记录类型:

  TWebPageRecord = record

    URL: string;  //保存网页的URL

    Title: string;//保存网页的标题

    Text: string; //保存网页的文字

  end;

 

然后定义一个TWebPageRecord类型的数组FWebPageRecordArray,大小定位20吧(我想一般人不会打开20个以上的IE吧):

Const  MAXPAGECOUNT = 20;

……

FWebPageRecordArray : array [0..MAXPAGECOUNT-1] of TWebPageRecord;

在遍历IE窗口时,向数组中的元素的相应字段复制即可。

对这个复制防复制(好拗口呀:))网页的功能也封装成一个类吧!

type

  TWebCracker = class(TObject)

  private

    FWebPageRecordArray : array [0..MAXPAGECOUNT-1] of TWebPageRecord;

    FWebPageCount: Integer;

  public

    procedure SnapShot;

    function GetWebText(AIndex:integer): string;

    function GetWebTitle(AIndex:integer): string;

    function GetWebURL(AIndex:integer): string;

    procedure Clear;

    procedure Refresh;

    function GetWebPageCount: Integer;

  end;

在用户界面中,可以通过调用TWebCracker.SnapShot;来对打开的IE窗口进行遍历,并保存到FWebPageRecordArray这个数组中。通过TWebCracker.GetWebPageCount方法可以得到FWebPageRecordArray中保存的页面的个数,通过GetWebTextGetWebTitleGetWebURL就可以得到指定页面的文字、标题或是URL

一切都已经搞定了!爽!

 

通过编写这个小软件,我是收获颇丰呀!除了学到了上边这些技巧外,我还有一些小的经验,愿意与大家分享:

1、为用户着想,让用户舒服

用户是上帝嘛!以那个Ctrl+Alt+S热键来说吧:一般用户上网都是右手握鼠标,空下来的只有左手。小拇指按Ctrl,大拇指按Alt,食指刚好能按到S键,不费一点力气!

2 良好的编码习惯

1)不要出现魔术数

TWebCracker定义的那个FWebPageRecordArray数组来说:

Const  MAXPAGECOUNT = 20;

……

FWebPageRecordArray : array [0..MAXPAGECOUNT-1] of TWebPageRecord;

别人一看MAXPAGECOUNT就知道是什么意思,而如果你写成:

FWebPageRecordArray : array [0..19] of TWebPageRecord;

估计除了你自己没有人能够知道19到底是什么意思。

2)用sender的方式增强代码的健壮性

procedure TMainfrm.CBAutoRunClick(Sender: TObject);

Const

  SIGNINREGISTRY = 'WebSuction';

begin

  if (Sender as TCheckBox).Checked then 

     AddToAutoRun(Application.ExeName,SIGNINREGISTRY)

  else DelAutoRun(SIGNINREGISTRY);

end;

这样即使Checkbox1改了名字也不怕。

又如:

procedure TMainfrm.N1Click(Sender: TObject);

begin

  if (Sender as TMenuItem).Caption = '暂停(&S)' then

    begin

      (Sender as TMenuItem).Caption := '开始(&R)';

      FWebPageSaver.Pause;

    end

  else

    begin

      (Sender as TMenuItem).Caption := '暂停(&S)';

      FWebPageSaver.ReStart;

    end;

end;

3)不要直接使用Tform2单元的全局Form2变量,那样就破坏了封装性

procedure TMainfrm.SBNextClick(Sender: TObject);

var

  LSelectedIndex : integer;

  FormDisplay : Tform2;

begin

  LSelectedIndex := LBWebPage.ItemIndex;

  if LSelectedIndex <> -1 then

  begin

    FormDisplay := Tform2.Create(self);

    FormDisplay.SetContent(FWebCracker.GetWebText(LSelectedIndex));

    FormDisplay.Show;

  end;

end;

TForm2中定义 SetContent方法

procedure TWebCrackfrm.SetContent(AText:string);

begin

  Memo.Clear;

  Memo.Lines.Add(AText);

end;

posted @ 2005-10-22 00:45 CowNew开源团队 阅读(466) | 评论 (0)编辑 收藏

     摘要:   现在网上有很多提供主页空间的站点,但是大部分低价位的站点只提供静态HTML文档的功能,不支持ASP、PHP等动态网页技术。如果您像在您的主页上放上您喜欢的文章,那么需要一个一个链接的做。如果您删除了某篇文章或者想添加某篇文章,那么需要做很多改动,牵一发而动全身。   凌科文章动态发布系统就是为你解决这个问题而开发的软件。使用本软件后您可以轻易生成下面效果的网页。 //...  阅读全文
posted @ 2005-10-22 00:42 CowNew开源团队 阅读(925) | 评论 (0)编辑 收藏

仅列出标题
共30页: First 上一页 22 23 24 25 26 27 28 29 30 下一页