delphi2007 教程

delphi2007 教程

首页 新随笔 联系 聚合 管理
  1013 Posts :: 0 Stories :: 28 Comments :: 0 Trackbacks

#

如何让IdTCPServer&IdTCPClient的应用穿透NAT? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiNetwork/html/delphi_20061217114600108.html
IdTCPServer拥有公网IP和开放的端口,  
  IdTCPClient位于NAT之后,没法端口映射,  
  但是由IdTCPClient主动发起连接,连接之后互相传递文件.  
  请问:这样的应用是否能够实现,并说明原理,谢谢!

强烈关注,貌似Tcp穿透Nat网上很难搜到实质性的东西

顶!我也想知道相关方法.

在IdTCPClient的属性里BoundIP和BoundPort不用填,使用如下代码就能穿透NAT连接IdTCPServer:  
   
      IdTCPClient.Host   :=   ‘0.0.0.0’;//IdTCPServer公网IP  
      IdTCPClient.Port   :=   0;                     //IdTCPServer的端口  
      try  
          IdTCPClient.Connect();  
      except  
          IdTCPClient.Disconnect;  
          exit;  
      end;  
   
  要注意的是,IdTCPServer一定要在拥有公网IP的机子上运行,这样可以使得世界任何地方的电脑用上述代码就能跟IdTCPServer相连接,连接上后,可以用IdTCPServer的OnConnect取得IdTCPClient经过NAT转换后的IP和Port,代码如下:  
   
  procedure   TForm1.IdTCPServer1Connect(AThread:   TIdPeerThread);  
  begin  
      IP       :=   AThread.Connection.Socket.Binding.PeerIP   ;  
      Port   :=   AThread.Connection.Socket.Binding.PeerPort;  
  end;  
   
  使用IdTCPServer的OnConnect获得的IP和Port才能与IdTCPClient通讯。  
  你会发现OnConnect里获得的IP和Port和未经过NAT转换后的IdTCPClient的机子的IP和Port大不一样。

典型的Client/Server结构,由Client向Server发出TCP/IP连接,此连接是可以双向传输数据。

chenzhechenge()   的方法能行????是不是有点搞笑了  
   
  用UDP吧

"IdTCPServer拥有公网IP和开放的端口"  
  既然服务器有固定IP,那Client直接连就可以了。  
   
 

楼主可能想问的是在两个不同的内网中,各自的客户端都可以访问公网服务器,现在想在这两个内网机之间穿透NAT建立连接。。。  
  关注,UDP的实现可以在晚上找到,TCP的还没有看到过。。。

看到没,楼上说了,udp的晚上可以找到,楼主晚上再来吧。  
  ^_^

TCP穿透需要RAW   Socket,XP以上系统不支持  
  需要进入驱动模式才OK  
   
  那个复杂~~

Server端在公网里,Client无论处在公网还是处在NAT之后,均能建立连接.连接一旦建好,可以相互通信.我用DELPHI6里的SOCKET控件(分别为服务端和客户端)实现过.SERVER端可以不必知道CLIENT端的地址和端口,只要CLIENT知道SERVER   的IP:PORT即可.SERVER端通过CONNECTION[n].SENDBUF向客户端通信.

两个都在NAT后面的客户端,如果使用UDP可以借助具有公网的服务器,双向打洞就可以穿透NAT了。

我也在找相关的代码,但好像楼上说的都是理论?  
  谁有相关的源码发一下?

楼主的情况根本不需要考虑NAT什么的麻烦事.  
   
  服务器既然有公网IP,客户端只要主动连接得上,这时候建立的TCP连接就是一条双向链路.  
  通常很多应用都是单向发起的问答式应用协议,  
  但这条TCP连接始终是可以双向的!  
   
  INDY控件组大多使用阻塞方式SOCKET,在阻塞方式,多半是另创建工作线程专用于接收数据.  
  楼主设计通讯协议的时候,注意区分一下数据是对方主动数据还是回应数据.  
   
 

chenzhechenge()   的方法能行????是不是有点搞笑了  
   
   
  可以,我老早就已经实现过了,现在还在运行中~~~

IdTCPServer拥有公网IP和开放的端口,  
   
   
  ---------------  
  那就不存在穿透NAT   了。

[转帖]NAT的完全分析及其UDP穿透的完全解决方案作者:陈敏  
  一:基本术语  
  防火墙  
  防火墙限制了私网与公网的通信,它主要是将(防火墙)认为未经授权的的包丢弃,防火墙只是检验包的数据,并不修改数据包中的IP地址和TCP/UDP端口信息。  
  网络地址转换(NAT)  
  当有数据包通过时,网络地址转换器不仅检查包的信息,还要将包头中的IP地址和端口信息进行修改。以使得处于NAT之后的机器共享几个仅有的公网IP地址(通常是一个)。网络地址转换器主要有两种类型.  
  P2P应用程序  
  P2P应用程序是指,在已有的一个公共服务器的基础上,并分别利用自己的私有地址或者公有地址(或者两者兼备)来建立一个端到端的会话通信。  
  P2P防火墙  
  P2P防火墙是一个提供了防火墙的功能的P2P代理,但是不进行地址转换.  
  P2P-NAT  
  P2P-NAT   是一个   P2P代理,提供了NAT的功能,也提供了防火墙的功能,一个最简的P2P代理必须具有锥形NAT对Udp通信支持的功能,并允许应用程序利用Udp打洞技术建立强健的P2P连接。  
  回环转换  
  当NAT的私网内部机器想通过公共地址来访问同一台局域网内的机器的时,NAT设备等价于做了两次NAT的事情,在包到达目标机器之前,先将私有地址转换为公网地址,然后再将公网地址转换回私有地址。我们把具有上叙转换功能的NAT设备叫做“回环转换”设备。  
  二:NAT分类  
  可以分为基础NAT与网络地址和端口转换(NAPT)两大类  
  (一):基础NAT  
  基础NAT   将私网主机的私有IP地址转换成公网IP地址,但并不将TCP/UDP端口信息进行转换。基础NAT一般用在当NAT拥有很多公网IP地址的时候,它将公网IP地址与内部主机进行绑定,使得外部可以用公网IP地址访问内部主机。(实际上是只将IP转换,192.168.0.23   <->   210.42.106.35,这与直接设置IP地址为公网IP还是有一定区别的,特别是对于企业来说,外部的信息都要经过统一防火墙才能到达内部,但是内部主机又可以使用公网IP)  
  (二):网络地址和端口转换   (NAPT)  
  这是最普遍的情况,网络地址/端口转换器检查、修改包的IP地址和TCP/UDP端口信息,这样,更多的内部主机就可以同时使用一个公网IP地址。  
  请参考[RFC1631]和[RFC2993]及[RFC2663]这三个文档了解更多的NAT分类和术语信息。另外,关于NAPT的分类和术语,[RFC2663]做了更多的定义。当一个内部网主机通过NAT打开一个“外出”的TCP或UDP会话时,NAPT分配给这个会话一个公网IP和端口,用来接收外网的响应的数据包,并经过转换通知内部网的主机。这样做的效果是,NAPT在   [私有IP:私有端口]   和[公网IP:公网端口]之间建立了一个端口绑定。  
  端口绑定指定了NAPT将在这个会话的生存期内进行地址转换任务。这中间存在一个这样的问题,如果P2P应用程序从内部网络的一个[私有IP地址:端口]对同时发出多条会话给不同的外网主机,那么NAT会怎样处理呢?这又可以分为锥形NAT   (CONE   NAT)与对称NAT   (SYMMTRIC   NAT)两大类来考虑:    
  A.锥形NAT  
  (为什么叫做锥形呢?请看以下图形,终端和外部服务器,都通过NAT分派的这个绑定地址对来传送信息,就象一个漏斗一样,筛选并传递信息)  
                                                                   
      当建立了一个   [私有IP:端口]-[公网IP:端口]   端口绑定之后,对于来自同一个[私有IP:端口]会话,锥形NAT服务器允许发起会话的应用程序   重复使用这个端口绑定,一直到这个会话结束才解除(端口绑定)。  
      例如,假设   Client   A(IP地址信息如上图所示)通过一个锥形NAT   同时发起两个外出的连接,它使用同一个内部端口(10.0.0.1:1234)给公网的两台不同的服务器,S1和S2。锥形NAT   只分配一个公网IP和端口(155.99.25.11:62000)给这个两个会话,通过地址转换可以确保   Client使用端口的“同一性”(即这个Client只使用这个端口)。而基础NATs和防火墙却不能修改经过的数据包端口号,它们可以看作是锥形NAT的精简版本。  
  进一步分析可以将CONE   NAT受限制锥形NAT   (RESTRICT   CONE)   与端口受限锥形NAT   (PORT   RESTRICT   CONE)   三大类,以下是详细论述:   分为全双工锥形NAT   (FULL   CONE)   ,  
  1.全双工锥形NAT  
  当内部主机发出一个“外出”的连接会话,就会创建了一个公网/私网   地址,一旦这个地址对被创建,全双工锥形NAT会接收随后任何外部端口传入这个公共端口地址的通信。因此,全双工锥形NAT有时候又被称为"混杂"NAT。  
  2.受限制锥形NAT  
  受限制的锥形NAT会对传入的数据包进行筛选,当内部主机发出“外出”的会话时,NAT会记录这个外部主机的IP地址信息,所以,也只有这些有记录的外部IP地址,能够将信息传入到NAT内部,受限制的锥形NAT   有效的给防火墙提炼了筛选包的原则——即限定只给那些已知的外部地址“传入”信息到NAT内部。  
  3.端口受限锥形NAT  
  端口受限制的锥形NAT,与受限制的锥形NAT不同的是:它同时记录了外部主机的IP地址和端口信息,端口受限制的锥形NAT给内部节点提供了同一级别的保护,在维持端口“同一性”过程中,将会丢弃对称NAT传回的信息。  
  B.对称NAT  
  对称NAT,与Cone   NAT是大不相同的,并不对会话进行端口绑定,而是分配一个全新的公网端口   给每一个新的会话。  
  还是上面那个例子:如果   Client   A   (10.0.0.1:1234)同时发起两个   "外出"   会话,分别发往S1和S2。对称Nat会分配公共地址155.99.25.11:62000给Session1,然后分配另一个不同的公共地址155.99.25.11:62001给Session2。对称Nat能够区别两个不同的会话并进行地址转换,因为在   Session1   和   Session2中的外部地址是不同的,正是因为这样,Client端的应用程序就迷失在这个地址转换边界线了,因为这个应用程序每发出一个会话都会使用一个新的端口,无法保障只使用同一个端口了。  
  在TCP和UDP通信中,(到底是使用同一个端口,还是分配不同的端口给同一个应用程序),锥形NAT和对称NAT各有各的理由。当然锥形NAT在根据如何公平地将NAT接受的连接直达一个已创建的地址对上有更多的分类。这个分类一般应用在Udp通信(而不是Tcp通信上),因为NATs和防火墙阻止了试图无条件传入的TCP连接,除非明确设置NAT不这样做。

三:NAT对session的处理  
  以下分析NAPT是依据什么策略来判断是否要为一个请求发出的UDP数据包建立Session的.主要有一下几个策略:    
  A.   源地址(内网IP地址)不同,忽略其它因素,   在NAPT上肯定对应不同的Session  
  B.   源地址(内网IP地址)相同,源端口不同,忽略其它的因素,则在NAPT上也肯定对应不同的Session  
  C.   源地址(内网IP地址)相同,源端口相同,目的地址(公网IP地址)相同,目的端口不同,则在NAPT上肯定对应同一个Session  
  D.   源地址(内网IP地址)相同,源端口相同,目的地址(公网IP地址)不同,忽略目的端口,则在NAPT上是如何处理Session的呢?  
  A,B,C三种情况的都是比较简单的,可以很容易的实现.而D的情况就比较复杂了.所以D情况才是我们要重点关心和讨论的问题。  
  四:完全解决方案  
  以下针对四种SESSION与四种NAT的完全解决方案,为了方便将使用以下缩写形式:  
  C代表   CONE   NAT  
  S代表SYMMETRIC   NAT,  
  FC代表   FULL   CONE   NAT,  
  RC代表   RESTRICT   CONE   NAT,  
  PC   代表   PORT   RESTRICT   CONE   NAT.  
  首先依据CLIENT   (客户)端在NAT后   的个数不同可以分为两大类:  
  TYPE   ONE   :一个在NAT后   +   一个在公网中.  
  这种情况下可以分为两大类:  
  A.   S   VS   公网:此种情况下,由于公网的地址在一个SESSION内是不变的,所以可以打洞是可以成功的.  
  B.   C   VS   公网:   与上面类似,这种情口下打洞是可以成功的.  
  TYPE   TWO:两个客户都在NAT后面.  
  这种情况下也可以细分为两大类:  
  A.   其中一个NAT   是   S(SYMMETRIC   NAT)   型的,既:S   VS   C或者是S   VS   S   .  
  下面论证这种情口下按照常规打洞是行不通的,在常规打洞中,所有的客户首先登陆到一个服务器上去.服务器记录下每个客户的[公网IP:端口],然后在打洞过程中就使用这个记录的值,然而对于S型的NAT来说,它并不绑定[私网IP:端口]和[公网IP:端口]的映射.所以在不同的SESSION中,NAT将会重新分配一对[公网IP:端口].这样一来对于S型的NAT来说打洞的[公网IP:端口]与登记在服务器上的[公网IP:端口]是不同的.而且也没有办法将打洞的[公网IP:端口]通知到另一个位于NAT下的客户端,   所以打洞是不会成功的.然而如果另一个客户端是在公网时,打洞是可以的.前面已经论证了这种情况.  
  这种情况下的解决方案是只能通过端口预测来进行打洞,具体解决方法如下:例如(以两个都是S型的为例)   NAT   A   分配了它自己的UDP端口62000,用来保持   客户端A   与服务器S的通信会话,   NAT   B   也分配了31000端口,用来保持客户端B与服务器S   的通信会话。通过与   服务器S的对话,客户端A   和   客户端B都相互知道了对方所映射的真实IP和端口。  
      客户端A发送一条UDP消息到138.76.29.7:31001(请注意到端口号的增加),同时客户端B发送一条UDP消息到155.99.25.11:62001。如果NAT   A   和NAT   B继续分配端口给新的会话,并且从A-S和B-S的会话时间消耗得并不多的话,那么一条处于客户端A和客户端B之间的双向会话通道就建立了。  
      客户端A发出的消息送达B导致了NAT   A打开了一个新的会话,并且我们希望NAT   A将会指派62001端口给这个新的会话,因为62001是继62000后,NAT会自动指派给   从服务器S到客户端A之间的新会话的端口号;类似的,客户端B发出的消息送达A导致了   NAT   B打开了一个新的会话,并且我们希望   NAT   B将会指派31001这个端口给新的会话;如果两个客户端都正确的猜测到了对方新会话被指派的端口号,那么这个   客户端A-客户端B的双向连接就被打通了。其结果如下图所示:  
  明显的,有许多因素会导致这个方法失败:如果这个预言的新端口(62001和31001)   恰好已经被一个不相关的会话所使用,那么NAT就会跳过这个端口号,这个连接就会宣告失败;如果两个NAT有时或者总是不按照顺序来生成新的端口号,那么这个方法也是行不通的。  
  如果隐藏在NATA后的一个不同的客户端X(或者在NAT   B后)打开了一个新的“外出”UDP   连接,并且无论这个连接的目的如何;只要这个动作发生在客户端A   建立了与服务器S的连接之后,客户端A   与   客户端B   建立连接之前;那么这个无关的客户端X   就会趁人不备地“偷”   到这个我们渴望分配的端口。所以,这个方法变得如此脆弱而且不堪一击,只要任何一个NAT方包含以上碰到的问题,这个方法都不会奏效。  
  在处于   cone   NAT   系列的网络环境中这个方法还是实用的;如果有一方为   cone   NAT   而另外一方为   symmetric   NAT,那么应用程序就应该预先发现另外一方的   NAT   是什么类型,再做出正确的行为来处理通信,这样就增大了算法的复杂度,并且降低了在真实网络环境中的普适性。  
          最后,如果P2P的一方处在两级或者两级以上的NAT下面,并且这些NATS   接近这个客户端是SYMMETRIC   NAT的话,端口号预言是无效的!  
  因此,并不推荐使用这个方法来写新的P2P应用程序,这也是历史的经验和教训!  
  B.   两个都是CONE   NAT型的.  
  这种情况下可以分为六大类型:  
  A:   FC   +   FC  
  B:   FC   +   RC  
  C:   FC   +   PC    
  D:   PC   +   RC    
  E:   PC   +   PC    
  F:   RC   +   RC    
  虽然有这么多种情况,但是由于CONE   NAT   的特性,所以还是很好办的,因为对于CONE   NAT   来说,在同一个SESSION中它会绑定一对[私网IP:端口]和[公网IP:端口]的映射,所以它们打洞用的[公网IP:端口]与登记在服务器上的[公网IP:端口]是一致的,所以打洞是可以行的通的.  
  综上所述,就已经完全的概括了所有类型的NAT之间的可能的通信情况了.并且都提供了可行的解决方案.  
  五:对前一阶段的总结  
  1.前一阶段使用的打洞方法是有缺陷的,它只适应于两个都是FULL   CONE   NAT的类型的CLIENT(客户端).以下论证它不适应于两个都是CONE   NAT的类型中的  
  B:   FC   +   RC  
  C:   FC   +   PC    
  D:   PC   +   RC    
  E:   PC   +   PC    
  F:   RC   +   RC    
  这五种情况.  
  因为对于受限的NAT它登记了外出包的[IP地址&端口],它仅仅接受这些已登记地址发过来的包,所以它们报告服务器的端口只能接受来自服务器的包.不能接受来自另一客户端的包.所以前一阶段的打洞方法是不可行的.  
  六:   存在的问题  
  按照理论.NAT将在一定时间后关闭UDP的一个映射,所以为了保持与服务器能够一直通信,服务器必须要发送UDP心跳包,来保持映射不被关闭.这就需要一个合适的时间值.

代码到处都是!

要注意的是,IdTCPServer一定要在拥有公网IP的机子上运行,这样可以使得世界任何地方的电脑用上述代码就能跟IdTCPServer相连接,连接上后,可以用IdTCPServer的OnConnect取得IdTCPClient经过NAT转换后的IP和Port,代码如下:  
   
  procedure   TForm1.IdTCPServer1Connect(AThread:   TIdPeerThread);  
  begin  
      IP       :=   AThread.Connection.Socket.Binding.PeerIP   ;  
      Port   :=   AThread.Connection.Socket.Binding.PeerPort;   //!!!!!根本得不到   peerport  
  end;                                                                                                     //   不信大家试试,,,编译出错!  
   
  使用IdTCPServer的OnConnect获得的IP和Port才能与IdTCPClient通讯。  
  你会发现OnConnect里获得的IP和Port和未经过NAT转换后的IdTCPClient的机子的IP和Port大不一样。  
 

算了,,,,大家不要试了,,,,,  
   
  上面我说明一下,可以编译成功,,,有AThread.Connection.Socket.Binding.PeerPort   这个属性  
   
   
  listbox1.Items.Add(athread.Connection.Socket.Binding.PeerIP+':'+inttostr(athread.Connection.Socket.Binding.peerPort));  
  但是,,,加了这一句后,,,,,程序一运行就"程序无法响应",,,,直接死机了!

athread.Connection.Socket.Binding.PeerIP    
  athread.Connection.Socket.Binding.IP  
   
  athread.Connection.Socket.Binding.PeerPort  
  athread.Connection.Socket.Binding.Port  
   
  加个peer在前面是什么意思啊,,     两者有什么区别哦???

athread.Connection.Socket.Binding.PeerIP    
  athread.Connection.Socket.Binding.IP  
   
  也想知道有什么区别?

posted @ 2008-10-28 09:56 delphi2007 阅读(470) | 评论 (0)编辑 收藏

使用IdHttp获取网页代码出现的问题,只能得到部分代码,为什么,请大家帮忙 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiNetwork/html/delphi_20061217111113109.html
content   :=   idhttp.get('http://search.hrbanlv.com/job.do?action=search&orderby=updatedate&page=1&pagesize=50&pubarea=&keyword_job=&keyword_company=&workarea=9999&jobsort=9999&updatedate=14&keyword=');  
   
  获取其它网页的代码都正常,就是这个网页每次都只能获取到  
  <td   height="108"     colspan="2"   valign="top"><table   width="100%"   >  
  这个位置就结束了,后面的都获取不到,不知道为什么,请大家帮忙看看!

.....   下载的时候好像你没有把网页保存到文件流或则内存流中吧    
   
  定义一个内存流,下载之前创建一下     写到异常保护里面    
  GET的时候把这个内存流的参数加进去    
  LZ试试

不行,其他网页都正常,就只有我上面提到的这个网址不能下载全,到那个地方后面就没了。  
  使用流的方式也不行!

...靠   你耍我啊  
  你说的那个网络地址根本都打不开   如何能下载的到呢

本来就打不开  
 

我这里能打开,青岛人才网

噢   那是否是你输入的网络地址输错了?   打不开是下载不到的啊    
  indy组件好象也无这样的bug啊~~

首先感谢zuoansuifeng对我的问题的关注,不过,这个网址是能打开的,我用人头保证,用ie浏览很正常,用idhttp可以采集到信息,只是采集到一半左右的代码,后面的代码就没有了,我确认不是网页本身有问题,网址也没有搞错,我的程序下载别的网页,不管多长多慢的都是正常的。只是这个页面有问题,所以我把这个网址贴出来了,  
  我还没有那么白痴,一个不能访问的页面我拿出来问问题。  
  我再次声明我不是白痴

你说的能打开是因为先登录了才能打开的,而我们用ie直接打不开这个地址,所以直接用idhttp这个控件取得这个页面的内容也是不行的

算了吧,结贴,怎么说也说不清楚!  
  zuoansuifeng:这个网址能打开  
  dabaicai(不再做菜鸟):这个网址不需要登录可以直接浏览  
  就这样谢谢大家!  
 

不知道是否还可以发言!  
  上面的网址我去试了,不用登陆可以打开!  
  但是页面加载不完全,使用IE也只能页面开一半,查看源代码也是到楼主所得到的那个地方!  
  应该是网页有问题吧,IE只能做到这样,idhttp也就这样了。

posted @ 2008-10-28 09:56 delphi2007 阅读(316) | 评论 (0)编辑 收藏

COM+中怎么公用一个数据层接口 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiNetwork/html/delphi_20061216191901110.html
在COM+开发中,我想做一个公用的数据服务层组件,由一个MtsDataModule及ADO等数据访问控件组成,各业务对象通过它与数据库交互。但当业务对象访问这个数据访问组件时,都会创建一个MtsDataModule的对象实例,这样的话,当有多个业务对象访问时就会产生多个MtsDataModule对象,这样的话会占用较多的数据库资源。  
  问题:  
  1。在用COM+开发时,数据访问层能否只产生一个公用的MtsDataModule(上面放多个ADOCONNECT,及数据访问控件),业务对象都只调用这一个MtsDataModule对象,而不是产生MtsDataModule的多个实例?  
  2。用上述想法实现数据库连接池怎么做。  
  3。线程模型问题。有两个COM+对象BO1(STA),BO2(STA),客户端调用BO1时,在服务端产生一个单线程套件,BO1也放在同一个单线程套件中,在BO1中存在一个方法将创建BO2对象并调用BO2的方法,此时BO2是否和BO1在同一个套件中?(如果BO2为MTA,是否一样)  
   
  请各位帮忙,小弟对此问题一直迷惑中。谢谢  
 

没有遇到过这种问题吗?各位出出招吧

posted @ 2008-10-28 09:56 delphi2007 阅读(167) | 评论 (0)编辑 收藏

间隔定时扫描特定星期 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225170151111.html
每隔x周(0<x<53),逢星期一、星期二、星期三、星期四、星期五.在8:30执行。  
  如开始执日期为:2006-12-25,每隔3周执行,第一次执行时间为:  
  2006-12-25   8:30  
  2006-12-26   8:30  
  2006-12-27   8:30  
  2006-12-28   8:30  
  2006-12-29   8:30  
  下一次执行时间为:  
  2007-1-15   8:30  
  2007-1-16   8:30  
  2007-1-17   8:30  
  2007-1-18   8:30  
  2007-1-19   8:30  
   
  请问该如何设计此表,及如何定时描述。(需考虑不开机情况。如:2006-12-26   8:30前关机了,到第二天才开,过期未执行的将不再执行。)  
   
   
   
 

 
  一种想法:  
   
  aDate=StrToDateTime("2006-12-25")+7*3;  
   
  if   Now-aDate<1   then   Begin  
   
      if   DayOfTheWeek(aDate)=1   then   Begin     //星期1  
   
      End   Else   if   DayOfTheWeek(aDate)=2   then   Begin     //星期2  
   
      End;  
   
  end;  
       
  --------------------------------------------------------------  
  程序,犹如人生。  
 

最好把任务执行时间单独放到一个如下的数据结构中,结构如下:(可以用表的形式,也可以用结构文件等形式)  
  日期时间                   是否执行操作  
  2006-12-25   8:30            
  2006-12-26   8:30  
  2006-12-27   8:30  
  2006-12-28   8:30  
  2006-12-29   8:30  
   
  这样系统启动后,扫描此表,对于日期在当前日期之前的,不予操作(可以在是否执行操作的字段内填写某个标志),对于大于当前日期的,取出第一项,然后设置一个等待计时器(设置绝对时间和间隔报时时间),配合等待函数,当时间到代后,执行操作。  
   
  只所以建议使用这种扫描任务计划表的形式,是因为这样容易扩展,哪怕有一天你的任务计划需要改成其他形式,只要是按照时间执行,就可以不改代码,如果在代码中写死了时间计算的部分,那么以后要扩展,还要改代码。麻烦。  
   
   
   
   
 

谢谢大家的宝贵意见,wudi_1982所说也许是一种好的方法,但这样设计的话,数据量会过大,如果间隔周期为1,星期一到星期天每天都执行,开始时间为2006-12-26,无结束日期(或结束日期很大),这样的话,数据量就会太大。我想要的是不把数据分解出来。不管如何设计,只保存一条数据。

好办好办,简单简单。如果你做过交通客运系统的话,你这个问题和车辆调度计划是一模一样的。

晚上给你一个完整的表设计和处理语句。(如果你可以等待的话)

我可以等,那先谢谢了。

if   exists   (select   *   from   dbo.sysobjects   where   id   =   object_id(N'[dbo].[TScheduleInfo]')   and   OBJECTPROPERTY(id,   N'IsUserTable')   =   1)  
  drop   table   [dbo].[TScheduleInfo]  
  GO  
   
  CREATE   TABLE   [dbo].[TScheduleInfo]   (  
  [FScheduleID]   [varchar]   (50)   COLLATE   Chinese_PRC_CI_AS   NOT   NULL   ,  
  [FScheduleIntervalDays]   [int]   NOT   NULL   ,  
  [FScheduleOriginalDate]   [datetime]   NOT   NULL   ,  
  [FScheduleTime]   [Char]   (5)   NOT   NULL    
  )   ON   [PRIMARY]  
  GO  
   
  Insert   TScheduleInfo   Values('001',   21,   '2006-12-25',   '08:30')  
  Insert   TScheduleInfo   Values('002',   21,   '2006-12-26',   '08:30')  
  Insert   TScheduleInfo   Values('003',   21,   '2006-12-27',   '08:30')  
  Insert   TScheduleInfo   Values('004',   21,   '2006-12-28',   '08:30')  
  Insert   TScheduleInfo   Values('005',   21,   '2006-12-29',   '08:30')  
   
   
  Select   *   From   TScheduleInfo   Where   DateDiff(Day,   FScheduleOriginalDate,   GetDate())%(FScheduleIntervalDays)   =   0  
   
  ---------------------------------------------  
   
  如有什么不清楚的地方,   请留言。

学习!!

posted @ 2008-10-20 10:33 delphi2007 阅读(101) | 评论 (0)编辑 收藏

数据统计问题? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225165424112.html
数据库的记录:  
   
  编号         姓名           日期               星期         时间  
  10043     李俊龙     2006-12-15     星期五     21:30:00  
  10043     李俊龙     2006-12-16     星期六     21:34:00  
  10043     李俊龙     2006-12-17     星期日     21:35:00  
   
  A:如何统计为:  
  编号         姓名                                     时间                                                                         次数  
  10043     李俊龙     星期五21:30:00,2006-12-16星期六21:34:00,星期日21:35:00   3次  
   
  B:或者统计为:  
  编号         姓名     次数  
  10043     李俊龙     3次  
   
  各位帮帮忙,正在为这个烦恼~~

up

up~~too

B:  
  select   编号,姓名,Count(编号)   as   次数  
  from   表名  
  group   by   编号,姓名  
  A:的方式要复杂一些,你可能需要做表的旋转

A方法我用了临时表但插入的时候  
  Sql.Add('insert   into   tj_too(编号,姓名,时间,次数)   values(:tmpno,:tmpname,:allsj,:i)');  
  ADOQuery4.Parameters.ParamByName('tmpno').Value:=tmpno;  
  ADOQuery4.Parameters.ParamByName('tmpname').Value:=tmpname;  
  ADOQuery4.Parameters.ParamByName('allsj').Value:=allsj;  
  ADOquery4.Parameters.ParamByName('i').Value:=inttostr(i);  
  提示出错~~~~

错误信息是什么?

各位帮我看一下,为什么这样插入出错~

select   编号,姓名,Count(编号)   as   次数  
  from   表名  
  group   by   编号,姓名  
  三楼的B方案试过了,比A好用多了!顶三楼的

posted @ 2008-10-20 10:33 delphi2007 阅读(85) | 评论 (0)编辑 收藏

在Delphi中判断用户是否有超期未还的书本 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225162553113.html
我使用了BDE来连接数据库,想判断一下数据库表中的用户是否有借阅超期未还的书本,应该怎样写哦~~(我使用了query,table,database,DBGrid,DataSource,表中已经有了所借时间,超过30天就过期)

使用query,然后查询select   *   from   yourtable   where   borrowdate+30>=getdate   把结果显示在dbgrid中就可以了!

 
  借阅时间   :   TDateTime;//如果是其它类型,就需要转换,如:   借阅时间:=varToDateTime('2006-12-2')  
   
        if   now   <   incday(借阅时间,30)   then  
              showmessage('在借阅期中')  
              else  
              showmessage('过期了!');  
 

忘记说:  
  1、需要引用sysUtils单元(uses   sysUtils;)  
  2、把   <     换成   <=

select   *   from   yourtable   where   borrowdate+30>=getdate   中的borrowdate和getdate格式如何写哦~~能举个例子吗~~

getdate如何写哦~~我要getdate是现在系统时间哦~~格式要yyyy-mm-dd哦

with   Query2   do  
  begin  
  close;  
  sql.Clear;  
  sql.add('select   借书证号码,所借日期   from   lend   where   借书证号码=:qame   and   所借日期>现在时间+30天   ');  
  ParambyName('qame').AsString   :=   edit14.Text;  
  open;  
  ShowMessage(IntToStr(RecordCount));  
  end;  
  现在时间+30天应该如何写哦~~

我替一楼回答一下吧:  
   
  'select   借书证号码,所借日期   from   lend   where   借书证号码=:qame   and   所借日期>dateadd("d",30,现在日期)   '  
 

我没有试验哦~~     一起测试一下吧~~     其实查一下VBScript函数大全应该会找到这样的函数的

我已经测试了,完全可以!    
   
  SQL.text   :=   '   select   *   from   lend   where   日期   >   dateadd("d",30,now)   '   ;  
   
  具体是用>   还是用   <   ,由楼主自己决定吧!反正   dateadd("d",30,now)   就等于今天+30天!  
                                                                                                          ~~注意单位是天(d)  
   
  楼主遇到这类的SQL语句不会写的问题,一是可以从网上找SQL相关资料,再是可以找VBScript函数。

posted @ 2008-10-20 10:33 delphi2007 阅读(128) | 评论 (0)编辑 收藏

如何用filter过滤出query的空字段 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225155329114.html
想过滤出某字段值为空的记录  
  paradox   表,使用query  
  设置filter:=   '字段名=NUll'  
  不能执行?  
 

filter:=   '字段名   in   NUll'

filter   =   'FieldName   is   null'吧

 
   
  在access中,这么写     fieldname=null

好像is也不行     ^-^!!!

用=  
  给你做了一个例子:  
  数据表结构如下:表名,temp  
  a   数值类型    
  b   文本  
   
  代码如下:  
        with   Query1   do  
        begin  
              Close;  
              SQL.Clear;  
              SQL.Add('select   *   from   temp');  
   
              Filter   :=   'b=null';  
              Filtered   :=   true;//估计你是没写这个  
              Open;  
        end;

B如果是文本类型,在SQLSERVER中是不行的  
  用这个判断:Datalength(B)>0

Filter   :=   'b=null';  
              Filtered   :=   true;//估计你是没写这个  
              Open;  
  不行的,我试过   filtered:=true   ,我已写了  
  b   为char型,   Filter:='b=''   '''都可以,但一用到null   就报错  
  capbility   can   not   supported  
    is,   in   都不行  
  paradox   表  
 

 
  按照我例子中的,新建一个表,  
   
  数据表结构如下:表名,temp  
  字段名   a   数值类型   主键  
  字段名   b   文本  
  数据库是paradox   表  
   
  输入一些测试数据  
  然后在DELPHI新建工程,不要用你以前那个,用下面代码,看看行不行。不过在我机器上是没有任何问题的。  
  代码如下:  
        with   Query1   do  
        begin  
              Close;  
              SQL.Clear;  
              SQL.Add('select   *   from   temp');  
   
              Filter   :=   'b=null';  
              Filtered   :=   true;//估计你是没写这个  
              Open;  
        end;

新建一个表可以的,  
  我再找找原因,  
  另外如何过滤出为null   或者为trim(filed.value)=''的记录

楼上飞哥,   就是用的   field   is   null,   这个可以

找到原因,当sql   加入where   条件且条件是date型,并且使用了query的paramByName()做为传递参数的方式,则使用null   出错,改为不用   sDate=:sd1的方式,直接加入,则过滤时用null就不会出错.

posted @ 2008-10-20 10:33 delphi2007 阅读(467) | 评论 (0)编辑 收藏

窗体自动适应分辨率!与大家共同分享! Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225145914115.html
经过了一个上午折腾,终于搞定了,其实代码很简单!  
  与大家分享:  
   
    const  
   
      ScreenWidth:   LongInt   =   1024;   {I   designed   my   form   in   800x600   mode.}  
   
      ScreenHeight:   LongInt   =   768;  
   
   
  var  
      Form1:   TForm1;  
   
  implementation  
   
  {$R   *.dfm}  
  Function   TForm1.BigToSmall():double;  
  begin  
        BigToSmall:=Screen.Width/ScreenWidth     ;  
  end;  
  Function   TForm1.SmallToBig():double;  
  begin  
        SmallToBig:=Screen.Width/ScreenWidth;  
  end;  
  Function   TForm1.initWindowsPosition():boolean;  
  var  
    SizeDiv:double;  
    i:integer;  
  begin  
        if   Screen.Width<=     ScreenWidth   then  
              begin  
                    SizeDiv:=     BigToSmall  
              end  
        else  
              begin  
                    SizeDiv:=     SmallToBig    
              end;  
   
        //============================================  
      for   i:=ComponentCount-1   downto   0   do  
      begin  
          if(Components[i]   is   TSpeedButton)   then  
            begin  
                TSpeedButton(Components[i]).Top:=Round(SizeDiv*(TSpeedButton(Components[i]).Top));  
                TSpeedButton(Components[i]).left:=Round(SizeDiv*(TSpeedButton(Components[i]).left));  
                TSpeedButton(Components[i]).Width:=Round(SizeDiv*(TSpeedButton(Components[i]).Width));  
                TSpeedButton(Components[i]).Height:=Round(SizeDiv*(TSpeedButton(Components[i]).Height));  
            end;  
          If   (Components[i]   is   TPanel)   then  
            begin  
                TPanel(Components[i]).Top:=Round(SizeDiv*(TPanel(Components[i]).Top));  
                TPanel(Components[i]).left:=Round(SizeDiv*(TPanel(Components[i]).left));  
                TPanel(Components[i]).Width:=Round(SizeDiv*(TPanel(Components[i]).Width));  
                TPanel(Components[i]).Height:=Round(SizeDiv*(TPanel(Components[i]).Height));  
            end;  
      end;  
  end;  
  procedure   TForm1.FormCreate(Sender:   TObject);  
  var  
  i:   integer;  
   
  begin  
          Form1.Width:=990;  
          Form1.Height:=724;  
          initWindowsPosition;  
  end;

有觉悟。  
   
 

有沒有更好的辦法????

嗯,谢谢了。

DELPHI的窗体不是自动适应分辨率变化的吗?

DELPHI的窗体自动适应?  
  问题是窗体上的控件能不能随着自动适应才是重要的吧?

也可以啊,DELPHI上的控件都有ALIGN属性,可以设为ALTOP,ALBOTTOM等,这样应该可以满足要求啊。

同意黑鹰说的,你这个样子窗体控件都变大了,字体大小怎么解决?还是用altop,alclient等方式解决比较好。

呵呵,其实有不用写代码的方法

to     whbo(王红波(年轻人,要有所作为))    
   
   
  什么方法

字体是自动适应的,你同样的字体,分辨率低时大,分辨率高时小。  
  for   i:=ComponentCount-1   downto   0   do  
  begin  
  if(Components[i]   is   TSpeedButton)   then  
  begin  
  If   (Components[i]   is   TPanel)   then  
  begin  
  TPanel(Components[i]).Top:=Round(SizeDiv*(TPanel(Components[i]).Top));  
  TPanel(Components[i]).left:=Round(SizeDiv*(TPanel(Components[i]).left));  
  TPanel(Components[i]).Width:=Round(SizeDiv*(TPanel(Components[i]).Width));  
  TPanel(Components[i]).Height:=Round(SizeDiv*(TPanel(Components[i]).Height));  
  end;  
  end;  
  可以改成  
  for   i:=ControlCount-1   downto   0   do  
  with   Controls[i]   do  
  begin  
      Top:=Round(SizeDiv*Top);  
      left:=Round(SizeDiv*left);  
      Width:=Round(SizeDiv*Width);  
      Height:=Round(SizeDiv*Height);  
  end;

使用控件的Anchors属性,全部搞定,还是要多读书啊

Alclient+Anchors最好了,自动缩放无用。

估计楼主郁闷死了……

mark

mark

有没有用过form的scaled属性?  
   
  把它设为true,   你所需要的一切就都有了

什么都不用设啊,我调了好几遍哦,难道是我眼神不好?????

Scaled属性默认就是true的

呵呵,这样方法是不错

posted @ 2008-10-20 10:33 delphi2007 阅读(375) | 评论 (0)编辑 收藏

高手大家帮忙啊!看看这个值怎么取出来判断? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225142811116.html
self.LJBQuery.Close;  
  self.LJBQuery.SQL.Clear;  
  self.LJBQuery.SQL.Text   :='select   distinct   count(*)   from   LJB   where   教师姓名=:xingming';  
  self.LJBQuery.ParamByName('xingming').Value:=(self.JSXMDBLookupComboBox.Text);  
  count:=self.LJBQuery.Fields[0].AsInteger;  
  self.LJBQuery.ExecSQL;  
  if   count>0   then  
      ShowMessage('教师姓名已经存在!');  
   
  高手帮我看看!  
  这段代码提示错误!我想判断当前输入的教师姓名是否已经存在,怎么办?  
  这个方法不对   吗?高手给个正确的方法!我以前做C#的,现在研究下Delphi!  
  谢谢高手!

self.LJBQuery.Close;  
  self.LJBQuery.SQL.Clear;  
  self.LJBQuery.SQL.Text   :='select   distinct   count(*)   from   LJB   where   教师姓名=:xingming';  
  self.LJBQuery.ParamByName('xingming').Value:=(self.JSXMDBLookupComboBox.Text);  
  self.LJBQuery.Open;  
  count:=self.LJBQuery.Fields[0].AsInteger;  
   
  if   count>0   then  
      ShowMessage('教师姓名已经存在!');  
 

还没执行查询就去读它的值,当然会有问题的。同意楼上。

为什么要加   distinct   做什么用?

我觉得您的这段SQL代码是在增加开销,如楼上所说为什么要用distinct呢,   相同名,你只要Select   教师姓名   from   L_JB   where   教师姓名=:xingming  
  然后通过   query.RecordCount>0(不稳定)     或者   query.IsEmpty=true     或者   if   (query.bof=query.eof)   then   //none!   else     //有记录

同意maozefa(阿发伯)  
  建议多使用with   写的代码又快又好看

posted @ 2008-10-20 10:33 delphi2007 阅读(75) | 评论 (0)编辑 收藏

求Delphi中数据库记录统计方法. Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225142747117.html
我使用了BDE来连接数据库,想统计一下数据库表中的记录和满足一定条件的记录,语句怎么写哦~~~(我使用了query,table,database,DBGrid,DataSource)

方法一:(Query.RecordCount)  
   
        with   Query   do  
                  begin  
                  close;  
                  sql.Clear;  
                  sql.Text   :=   'select   *   from   表名';   //所有记录  
                  open;  
                  ShowMessage(IntToStr(RecordCount));//显示记录数  
                  end;  
  如果把SQL字串换成'select   *   from   表名   where   条件'   那么RecordCount返回符合条件的记录数  
   
  方法二:  
   
        Query.SQL.Text   :=   'select   count(*)   from   表名   where   条件';  
                                                                                                  ~~~~~~~~~~可选

楼上的方式就是统计的方式,通常你要查一些记录,就列出条件写出SQL的语言.而当你想知道这条语句有多少满足条件的记录的时候.只需将所有的原来的字段列表换成   count(*)   其它不变.查出的就一条记录一个字段就是符合条件的记录.

多谢你啦~~~

posted @ 2008-10-20 10:33 delphi2007 阅读(103) | 评论 (0)编辑 收藏

如何节省数据库的存储空间 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225141940118.html
比如用Byte是否会比Integer更节省空间?  
   
  查询速度是不是会有影响?

可以,不会影响你的速度。

影响大小的因素很多啊,和你库结构设计也有很大关系。不仅仅是几个字段

尽量做到最优化就可以了     难免有点遗憾

数字类型字段一般不会用来与其他字段对比或作为连接条件;  
  所以使用byte或者integer都应该不会影响你的查询速度;  
   
  另外,你可以在查询分析器中打开执行计划;然后对两种字段分别作查询;来验证具体的查询速度和时间参数。

谢谢楼上几位。  
   
  也就是说byte在数据存储的时候的确是只存了一个字节,而不是以4字节对齐的?

posted @ 2008-10-20 10:33 delphi2007 阅读(122) | 评论 (0)编辑 收藏

怎么样实现打印stringGrid中的数据 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225135512119.html
怎么样才能实再打印stringGrid中的数据啊,那位高人指点一下,谢谢了

用PRINTER对象!

能不能详细的说一下啊  
   
   
 

给你代码  
  ===========================  
  打印StringGrid内容  
  Procedure   TACDListerMain.PrintTable;  
  Var  
  margins:   TRect;  
  spacing:   Integer;  
  Cols:   TList;  
  Dlg:   TPrintProgressDlg;  
   
  Procedure   SetColumnWidth;  
  Var  
  i,   k,   w:   Integer;  
  Begin  
      Printer.Canvas.Font.Style   :=   [   fsBold   ];  
      For   i   :=   0   To   Pred(   Grid.ColCount   )   Do  
       
      Cols.Add(   Pointer(   Printer.Canvas.TextWidth(   Grid.Cells[   i,0   ]   )));  
       
      Printer.Canvas.Font.Style   :=   [];  
      For   i   :=   1   To   Pred(   Grid.RowCount   )   Do  
      For   k   :=   0   To   Pred(   Grid.ColCount   )   Do   Begin  
          w:=   Printer.Canvas.TextWidth(   Grid.Cells[   k,   i   ]   );  
          If   w   >   Integer(   Cols[   k   ]   )   Then  
          Cols[   k   ]   :=   Pointer(   w   );  
          End;   {   For   }  
           
          w   :=   2   *   Printer.Canvas.Font.PixelsPerInch   div   3;  
          margins   :=  
          Rect(   w,   w,   Printer.PageWidth-w,   Printer.PageHeight   -   w   );  
          spacing   :=   Printer.Canvas.Font.PixelsPerInch   div   10;  
           
          w   :=   0;  
          For   i   :=   0   To   Pred(cols.Count)   Do  
          w   :=   w   +   Integer(   cols[   i   ]   )   +   spacing;  
          w   :=   w   -   spacing;  
          If   w   >   (margins.right-margins.left   )   Then   Begin  
              w   :=   w   -   (margins.right-margins.left   );  
              cols[   cols.Count-2   ]   :=  
              Pointer(   Integer(   cols[   cols.Count-2   ]   )   -   w   );  
              End;   {   If   }  
               
              w:=   0;  
              For   i   :=   0   To   Pred(cols.Count)   Do  
              w   :=   w   +   Integer(   cols[   i   ]   )   +   spacing;  
              margins.right   :=   w   -   spacing   +   margins.left;  
              End;   {   SetColumnWidth   }  
               
              Procedure   DoPrint;  
              Var  
              i:   Integer;  
              y:   Integer;  
              Procedure   DoLine(lineno:   Integer);  
              Var  
              x,   n:   Integer;  
              r:   TRect;  
              th:   Integer;  
              Begin  
                  If   Length(Grid.Cells[0,lineno])   =   0   Then   Exit;  
                   
                  x:=   margins.left;  
                  With   Printer.Canvas   Do   Begin  
                          th   :=   TextHeight(   '膟'   );  
                          For   n   :=   0   To   Pred(   Cols.Count   )   Do   Begin  
                              r   :=   Rect(   0,   0,   Integer(Cols[   n   ]),   th);  
                              OffsetRect(   r,   x,   y   );  
                              TextRect(   r,   x,   y,   Grid.Cells[   n,   lineno   ]   );  
                              x   :=   r.right   +   spacing;  
                              End;   {   For   }  
                              End;   {   With   }  
                              y   :=   y   +   th;  
                              End;   {   DoLine   }  
                              Procedure   DoHeader;  
                              Begin  
                                  y:=   margins.top;  
                                  With   Printer.Canvas   Do   Begin  
                                          Font.Style   :=   [   fsBold   ];  
                                          DoLine(   0   );  
                                          Pen.Width   :=   Font.PixelsPerInch   div   72;  
                                          Pen.Color   :=   clBlack;  
                                          MoveTo(   margins.left,   y   );  
                                          LineTo(   margins.right,   y   );  
                                          Inc(   y,   2   *   Pen.Width   );  
                                          Font.Style   :=   [   ];  
                                          End;   {   With   }  
                                          End;   {   DoHeader   }  
                                          Begin  
                                              y:=   0;  
                                              For   i   :=   1   To   Pred(   Grid.RowCount   )   Do   Begin  
                                                  Dlg.Progress(   i   );  
                                                  Application.ProcessMessages;  
                                                  If   FPrintAborted   Then   Exit;  
                                                   
                                                  If   y   =   0   Then  
                                                  DoHeader;  
                                                  DoLine(   i   );  
                                                  If   y   >=   margins.bottom   Then   Begin  
                                                      Printer.NewPage;  
                                                      y:=   0;  
                                                      End;   {   If   }  
                                                      End;   {   For   }  
                                                      End;   {   DoPrint   }  
                                                       
                                                      Begin  
                                                          FPrintAborted   :=   False;  
                                                          Dlg   :=   TPrintProgressDlg.Create(   Application   );  
                                                          With   Dlg   Do  
                                                              try  
                                                                  OnAbort   :=   PrintAborted;  
                                                                  Display(   cPrintPreparation   );  
                                                                  SetProgressRange(   0,   Grid.RowCount   );  
                                                                  Show;  
                                                                  Application.ProcessMessages;  
                                                                  Printer.Orientation   :=   poLandscape;  
                                                                   
                                                                  Printer.BeginDoc;  
                                                                  Cols:=   Nil;  
                                                                  try  
                                                                      Cols:=   TLIst.Create;  
                                                                      Printer.Canvas.Font.Assign(   Grid.Font   );  
                                                                      SetColumnWidth;  
                                                                      Display(   cPrintProceeding   );  
                                                                      Application.ProcessMessages;  
                                                                      DoPrint;  
                                                                      finally  
                                                                          Cols.Free;  
                                                                          If   FPrintAborted   Then  
                                                                          Printer.Abort  
                                                                          Else  
                                                                          Printer.EndDoc;  
                                                                      end;  
                                                                      finally  
                                                                          Close;  
                                                                          End;   {   With   }  
                                                                          End;   {   TACDListerMain.PrintTable   }

var  
      TextF:Textfile;  
      S:String;  
      I:integer;  
  begin  
      try  
          AssignFile(TextF,'D:\PrintText.txt');  
          reWrite(TextF);  
          For   i:=0   to   StringGrid1.RowCount-1   do  
          begin  
                S:=StringGrid1.Rows[I].Text;  
                S:=StringReplace(S,#$D#$A,',     ',[rfReplaceAll,rfIgnoreCase]);  
                Showmessage(S);  
                writeln(TextF,S);  
          end;  
      finally  
          CloseFile(TextF);  
      end;  
  end;

在给你一个导入到EXCEL的代码,我自己写的!   仅供参考  
  function   GetExcelCoulmnCaption(num:   Cardinal):   string;  
  var  
      mod_num,div_num:Cardinal;  
  begin  
        if   num=0   then   exit;  
        if   (num   mod   26=0)   then   mod_num:=26  
        else   mod_num:=num   mod   26;  
        div_num:=num   div   26;  
        if   mod_num=26   then   DEC(div_num);  
        if   div_num=0   then  
        Result:=Chr(64+mod_num)  
        else   Result:=Chr(64+div_num)+Chr(64+mod_num);  
  end;  
   
  procedure   PrintSqlDataToExcel;  
  var  
      I:integer;  
      Range,ExcelApp,V:variant;  
  begin  
          Try  
              ExcelApp:=CreateOleObject('Excel.application');  
          Except  
              MessageDlg('没有安装Office   办公软件Excel!',mtinformation,[MBOK],0);  
              exit;  
          End;  
   
          try  
          ExcelApp.WorkBooks.add(Null);  
          V:=ExcelApp.WorkBooks[1].WorkSheets[1];  
   
          //*开始设计标题*/  
          Range:=V.Range['A1',GetExcelCoulmnCaption(DataSet.Fields.Count)+'1'];  
          Range.MergeCells:=true;  
          Range.RowHeight:=24;  
          Range.HoriZontalAlignMent:=xlCenter;  
          Range.VerticalAlignMent:=xlCenter;  
          Range.Font.Name:='新宋体';  
          Range.Font.size:=16;  
          Range.Font.FontStyle:='加粗';  
          Range.Value:=ExcelTitle;         //定义EXCEL的标题是什么?   EXCELTitle是字符型,需要自己定义  
          Range.Borders.LineStyle:=xlContinuous;     //边框  
          Range.Borders.Weight:=xlThin;  
          Range.Borders.ColorIndex:=xlAutomatic;  
   
          //显示标题  
            For   i:=0   To   DataSet.Fields.Count-1   Do  
            begin  
                Range:=V.Range[GetExcelCoulmnCaption(I+1)+'2',GetExcelCoulmnCaption(I+1)+'2'];  
                Range.RowHeight:=24;  
                Range.HoriZontalAlignMent:=xlCenter;  
                Range.VerticalAlignMent:=xlCenter;  
                Range.Font.Name:='新宋体';  
                Range.Font.size:=9;  
                Range.Font.FontStyle:='加粗';  
                Range.Columns.AutoFit;  
                Range.Value:=DataSet.Fields[I].FieldName;  
                Range.Borders.LineStyle:=xlContinuous;     //边框  
                Range.Borders.Weight:=xlThin;  
                Range.Borders.ColorIndex:=xlAutomatic;  
            end;  
            //显示内容  
            //set  
              Range:=V.Range['A3',GetExcelCoulmnCaption(DataSet.FieldCount)+IntToStr(DataSet.recordcount+2)];  
              Range.NumberFormatLocal:=   '@';  
              Range.RowHeight:=20;  
              Range.HoriZontalAlignMent:=xlCenter;  
              Range.VerticalAlignMent:=xlCenter;  
              Range.Borders.LineStyle:=xlContinuous;     //边框  
              Range.Borders.Weight:=xlThin;  
              Range.Borders.ColorIndex:=xlAutomatic;  
              Range.Font.Name:='新宋体';  
              Range.Font.size:=9;  
              Range.Columns.AutoFit;  
   
            DataSet.First;  
            While   (Not   DataSet.Eof)   do  
            begin  
                  For   i:=0   To   DataSet.Fields.Count-1   Do  
                  begin  
                            Range:=V.Range[GetExcelCoulmnCaption(I+1)+IntToStr(DataSet.RecNo+2),GetExcelCoulmnCaption(I+1)+IntToStr(DataSet.RecNo+2)];  
                            if     DataSet.Fields[I].IsNull   then  
                            Range.Value:='   '  
                            else  
                            Range.Value:=DataSet.Fields[I].AsString;  
                            Range.Borders.LineStyle:=xlContinuous;     //边框  
                            Range.Borders.Weight:=xlThin;  
                            Range.Borders.ColorIndex:=xlAutomatic;  
                  end;  
                  DataSet.next;  
            end;  
             
          //显示Excel文档界面  
          ExcelApp.visible:=true;  
          V.Activate;  
          finally  
                //释放接口对象  
                  ExcelApp:=unassigned;  
                  V:=   unassigned;  
                  Range:=unassigned;  
          end;  
  end;

posted @ 2008-10-20 10:33 delphi2007 阅读(308) | 评论 (0)编辑 收藏

求WIN32的打印函数 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225134915120.html
请问win32的哪个函数可以控制打印区域啊?  
  就是打印的时候能够自动换行。

一般如果想通过底层控制打印机,可以到官方网站下载打印机的指令!  
  直接通过指令输出打印字符和控制换行!

谢谢  
   
  我从帮助里面找到了

贴子回复次数大于跟给分次数  
   
  给不了你50   啊  
  晕了  
   
   
  我给我自己1分  
  也不可以

posted @ 2008-10-20 10:33 delphi2007 阅读(169) | 评论 (0)编辑 收藏

审核问题 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225130139121.html
现在客户有个特殊的需求,就是一笔数据要入两次帐进行审核,即第一次入帐后,审核人在审核的时候要重新再录入一遍.系统要把两次录入的数据进行比对,完全相同责审核通过,否则给出提示.在数据比对这块大家有没有方便快捷的方法?先谢各位了!

问题比较笼统

保存第一遍的数据,第二遍录入时,在Field.OnValidate事件中比较,比较不相同时,显示错误对话框后,Abort.

maozefa(阿发伯)  
  您说的Field.OnValidate事件应该在哪里写啊?

在DataSet中建立永久字段表,每个字段都有这么个事件。

posted @ 2008-10-20 10:33 delphi2007 阅读(79) | 评论 (0)编辑 收藏

怎么给Unit动态添加注释? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225123529122.html
我想把Unit注释,Procedure注释,写成类似模板的东西,然后遍历文件夹下面的pas文件,自动添加注释,请问如何实现,主要是为了提高注释的效率.  
  例如:  
   
  Unit   utlTest  
   
  interface  
   
  uses  
  **,**,**  
  Type    
          TestClass=Class  
  procedure   testFunction();  
   
  end;  
   
  implements  
  ////////////  
   
  /////注释的模版加在这里  
  ////////////////////  
  function   TestClass.testFunction();  
  begin  
  ***********************  
  end;  
  end.  
 

自己对.pas   逐行分析吧  
       
  --------------------------------------------------------------  
  程序,犹如人生。  
 

如果一行一行分析,效率一定比较低.能给个参考代码看看,分不是问题.

想到一个方法,需要移动很多的行数,不知道有没有跟简单的方法。

posted @ 2008-10-20 10:33 delphi2007 阅读(148) | 评论 (0)编辑 收藏

还是RAVE5的问题! Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225115313123.html
到底该怎么办来着,我实在是受不了了,本人水平实在不行,DELPHI7中装RAVE7出现DUPLICATE   LICENSE   FIND   ,PLEASE   INSTALL   A   SEPARATELY     LICENSED   VERSION!

自己编译Rave7.03源码版本,绝对无此问题  
  卸载原来的Rave,用Delphi自己的安装程序!

posted @ 2008-10-20 10:33 delphi2007 阅读(88) | 评论 (0)编辑 收藏

问一个简单的问题 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225100617124.html
初学delphi  
  需要时间不明确的情况下(循环体次数不定),怎么用一个动画来让用户知道程序还在执行  
  具体用什么控件,代码如何写呢   谢谢  
 

sf

你可以在循环开始之前将光标设置成漏斗状,然后在结束时恢复原来的箭头状!

代码怎么写呢??

显示一个非模态对话框,使用TAnimate控件,设置其CommonAVI或者FileName属性可播放动画。

我想问一下鼠标那个怎么写

Cursor   :=   crHourGlass;

我试了下   没有变啊

谁说不能变?  
   
  procedure   TForm1.Button1Click(Sender:   TObject);  
  begin  
      if   Cursor   =   crHourGlass   then  
          Cursor   :=   crDefault  
      else  
          Cursor   :=   crHourGlass;  
  end;  
 

变了   循环体次数太少   没变来的及就结束了

posted @ 2008-10-20 10:33 delphi2007 阅读(96) | 评论 (0)编辑 收藏

居然出错.谁能帮我解决一下. Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225053606125.html
我写了一段程序.如下:  
  A_DATABASE.ADOQuery2.Close;  
  A_DATABASE.ADOQuery2.SQL.Clear;  
  A_DATABASE.ADOQuery2.SQL.Add('SELECT   XULH,XIMNG   FROM   LXR   ORDER   BY   XULH');  
  A_DATABASE.ADOQuery2.Open;  
  A_DATABASE.ADOQuery2.Locate('xulh',TRIM(f_changj_lxr.Edit1.Text),[locaseinsensitive]);  
  编译的时候系统说我这个错误的位置是:  
  A_DATABASE.ADOQuery2.Locate('xulh',TRIM(f_changj_lxr.Edit1.Text),[locaseinsensitive]);  
  而在系统框的提示这样说的:  
  [Error]   f_cj_lxr.pas(262):   Undeclared   identifier:'lseinsensitive'  
  [Error]   f_cj_lxr.pas(262):   Incompatible   types:'TlocateOption'   and   'Integer'  
  [Fatal   Error]jinchjl.dpr(13):Could   not   compile   used   unit   'f_cj_lxr.pas'  
  我不明白的是,同样的写法在其它地方就通过了,这里就不行.谁能指导指导.谢谢.

是否模块中没包括DB.pas?  
   
  uses   DB;  
   
 

with   ADOQuery2   do  
          begin  
          Close;  
          SQL.Clear;  
          SQL.Add('SELECT   XULH,XIMNG   FROM   LXR   ORDER   BY   XULH');  
          Open;  
          Locate('xulh',TRIM(f_changj_lxr.Edit1.Text),[]);

>>Undeclared   identifier  
  >>Incompatible   types  
   
   
  非常常见的错误提示,通常是马虎所致  
   
   
  :)  
   
 

单元未包含进来

zhengsq007(实习实习)   :最仔细,并且提供了详细方法,我按他的方法做了就成了.所以决定大部分分给他.其它人参与者少点.谢谢大家

谢谢施舍。  
 

posted @ 2008-10-20 10:33 delphi2007 阅读(91) | 评论 (0)编辑 收藏

DIPHI与SQL连接的安全问题 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061224211925126.html
我想问各位大虾若用DEPHI的ADO连接SQL时,如何防止他人通过企业管理器查看相关的TABLE,设置密码可以吗?但装SQL时想输入密码与自设用户名,但失败!还可以用DEPHI编写人码,谢谢各位能提供相关的资料,!

你这问的是两个问题:解决问题的方法也只有分两步:  
  1.装SQL的时候将SA密码和装数据库的计算机的ADMINISTRATOR的密码全部收归自己,别人不能使用,并且把其它用户删除.确保别人不能使用你装SQL的那台计算机的企业管理器.  
  2.SQL装好以后,在企业管理器中设置访问你制订的数据库特殊用户和密码.将此密码放给DELPHI的ADO.那么可以确定知道第二步密码的人也可以用其它电脑上的SQL的企业管理器访问你的数据库.但是你可以使用权限限制他的工作能力范围.

posted @ 2008-10-20 10:33 delphi2007 阅读(111) | 评论 (0)编辑 收藏

数据库连接异常问题 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061224200748127.html
try  
                    AdoTable1.Active:=true;  
                    except  
                    begin  
                        MessageBox(handle,'数据库连接有问题请与管理员联系!','错     误',MB_ok   or   MB_ICONERROR);  
                        application.Terminate;  
                    end;  
                    end;  
  数据库关闭时候为什么不执行application.terminate,过了2分钟后才结束进程这个问题怎么解决?????我想让它,立马结束进程。

因为AdoTable1还在查找和连接计算机``~这是需要时间的`~大概也就是2分钟左右

这个时间可以减少呢。。好像要改动注册表来减少?

posted @ 2008-10-20 10:33 delphi2007 阅读(172) | 评论 (0)编辑 收藏

关于ini读取错误问题? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061224190355128.html
Filename:=ExtractFilePath(Paramstr(0))+'SET.INI';  
   
            Sid:=ini.ReadString('SETCONFIG','SERVERUSER','sa');  
            Sname:=ini.ReadString('SETCONFIG','SERVERNAME','yyjys');  
            SDname:=ini.ReadString('SETCONFIG','SERVERDBNAME','sims');  
            ini.Free;  
   
  会出现一个内存错误对话框?

ini:=TRegIniFile.Create;   //你做了吗?

你回复之前,我已经找到错误拉。  
  try  
                    AdoTable1.Active:=true;  
                    except  
                    begin  
                        MessageBox(handle,'数据库连接有问题请与管理员联系!','错误',MB_ok   or   MB_ICONERROR);  
                        application.Terminate;  
                    end;  
                    end;  
  在无法连接时候  
  这个代码为什么不执行application.terminate呢???

gz

var  
      tempIni:   TIniFile;  
  begin  
      tempIni   :=TIniFile.Create(extractfilepath(ParamStr(0))+'sys.ini');  
      SQLServerName   :=   tempIni.ReadString('SYSTEM',   'SERVER',   '');  
      SQLDBName   :=   tempIni.ReadString('SYSTEM',   'DBNAME',   '');  
      Password   :=     tempIni.ReadString('SYSTEM',   'Password','');  
      tempIni.Free;  
   
      ConnString     :='Provider=SQLOLEDB.1;Password='+password  
                                      +';Persist   Security   Info=True;User   ID=sa;Initial   Catalog='  
                                      +SQLDBName+';Data   Source='+SQLServerName;  
      try  
            sysdm.DBConnect.connected   :=   false;  
            sysdm.DBConnect.ConnectionString   :=   ConnString;  
            sysdm.DBConnect.connected   :=   true;  
      except  
            on   e:EoleException   do          
            begin  
                if   e.Errorcode   =   -2147217843   then  
                    begin  
                        MsShow('数据库密码不对!');  
                     
                    end  
                else   if   e.Errorcode   =   -2147467259   then  
                    begin  
                        showmessage('数据库服务器名或数据库名不对!');  
                        application.Terminate;  
                    end;  
            end;  
      end;  
 

posted @ 2008-10-20 10:33 delphi2007 阅读(149) | 评论 (0)编辑 收藏

进销存中加权价在有负数这种情况下怎么处理 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061224180508129.html
按正常的计算方法加权价应该是  
  新加权价=(库存*加权价   +   新增数量*单价)/(库存+新增数量)  
  可有时库存出现负数时还是这样计算的话,新加权值似乎跳动很大,有时用户也希望新增数量可以写成负数,表示是退货,这样计算出来也似乎有问题,大家遇到这种情况是怎么处理的?

价格不应该为负数的,可以这样  
   
  新加权价=(库存*加权价   +   新增数量绝对值*单价)/(库存+新增数量绝对值)  
 

这是你感觉可以这样计算的还是在实际使用时就是这样计算的?我没有学过财务,拿不定注意。库存是负数的时候要不要把库存取个绝对值再计算呢?

按正常公式计算没问题的,正常公式  
  新加权价=(库存*加权价   +   新增数量*单价)/(库存+新增数量)  
  实际上是  
  新加权价=(库存总额   +   新增商品总额)/(库存数量+新增数量)  
  正常情况下,库存总额不应该为负数,如果出现负数,说明管理有问题,也就是库存商品出现短缺或者损毁,正常计算可如实反映这一问题。至于退货情况,新增商品为负数很正常啊,如果库存商品不足以退货,那么实物帐务也无法处理(没那多库存商品,怎么退?),只能等待,这并不矛盾。取绝对数肯定是错误的。

补充:在财务上,如果确实出现库存商品严重短缺或者损毁,财务上可通过盘点审计后正常报损,并重新调整帐务的。  
 

如按楼上说的那样做,那是不是在退货时要判断库存是不是满足退货数量、销售出单时是不是要判断销售数量是否不超过库存数量?如果不满足就提示停止操作吗,能不能让用户先出单回头再来补上进货单呢?

如按楼上说的那样做,那是不是在退货时要判断库存是不是满足退货数量、销售出单时是不是要判断销售数量是否不超过库存数量?如果不满足就提示停止操作吗,能不能让用户先出单回头再来补上进货单呢?  
  ===================================================================================  
          在实际操作中,不会出现你说的情况。  
          如果是购进商品,企业购进100件商品,发现有问题或不适用,显然是企业要找供货方退货,如果因使用或者损毁只剩下80,那么肯定只能退掉80,其它就没法退了,只能索赔等;如果是销售商品,拿来退的是客户,新增商品只能是增加。

补充:所以出现负数的情况一般只能是商品损毁、丢失或者商品串户造成的,企业财务会通过定期或不定期盘点解决的。  
 

谢谢阿发伯,看来我可以放心用  
          新加权价=(库存*加权价   +   新增数量*单价)/(库存+新增数量)  
  来计算了。  
 

posted @ 2008-10-20 10:33 delphi2007 阅读(221) | 评论 (0)编辑 收藏

如下这段代码怎么传递动态参数比较合适?(问题有点长~谢谢) Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061224164816130.html
源代码如下(不用细看):  
  代码在SQL的查询分析器中运行是成功的,改动语法方面的细节后得到以下代码!  
  select   a.company   AS   company   ,b.total_suttle   AS   last_left,this_in   ,this_p   ,this_t   ,e.total_suttle   AS   this_left  
  from   gongsi   a    
  left   join    
                  (  
                    SELECT   kehe,total_suttle                                                  
                    FROM    
                            (  
                              SELECT   kehe   as   lcompany,maxdate=MAX(c_date)      
                              FROM   storagetotal    
                              WHERE   c_date<=:starttime    
                              GROUP   BY   kehe  
                            )Kehe_and_Date,storagetotal    
                    WHERE   kehe=lcompany   AND   c_date=maxdate  
                  )   b    
  on   a.company=b.kehe    
  left   join  
                  (                                                                                                
                    SELECT   kehe,SUM(s_weight)   AS   this_in                        
                    FROM   total    
                    WHERE   s_time   BETWEEN   :starttime   and   :endtime    
                    GROUP   BY   kehe  
                  )c    
  on   a.company=c.kehe  
  left   join    
                (                                                                                            
                    SELECT   kehe,SUM(p_weight)   AS   this_p,SUM(t_weight)   AS   this_t  
                    FROM   total  
                    WHERE   alter_time   BETWEEN   :starttime   and   :endtime    
                    GROUP   BY   kehe    
                )d      
  on   a.company=d.kehe  
  left   join                                                                                        
              (    
                  SELECT   kehe,total_suttle  
                  FROM  
                            (  
                              SELECT   kehe   as   lcompany,maxdate=MAX(c_date)    
                              FROM   storagetotal    
                              WHERE   c_date<=:endtime    
                              GROUP   BY   kehe  
                            )Kehe_and_Date,storagetotal    
                  WHERE   kehe=lcompany   AND   c_date=maxdate  
              )e  
  on   a.company=e.kehe  
   
  其中的动态参数是:startime和endtime,他们分别来自界面上的两个TDateTimePicker控件starttime1和endtime1。  
  我试过好几种方法  
  1、把以上代码写到存储过程中,用ADOStoredProc组件连接,然后的的代码是:  
  with   ADOStoredProc1   do  
          begin  
                  Paramaters.ParamByName('@starttime').Value=DateTimePicker1.date;  
                  Paramaters.ParamByName('@endtime').Value=DateTimePicker2.date;  
                  ExecProc;  
          end;  
  这个方法的结果是程序成功运行,但是在DBGrid中却什么都没有。有人说存储过程可以返回数据集,有人又说不行,到底行还是不行啊?行的话又该如何返回显示呢?  
  2、在Object   inspector下使用ADOQuery控件的SQL属性,直接在其下的List   editor下粘贴以上代码,从其Parameters属性下看到了六个变量参数  
  starttime  
  starttime  
  endtime  
  starttime  
  endtime  
  endtime  
  然后我在程序中写入了  
  with   ADOQuery2   do  
          begin  
            Parameters.ParamByName('starttime').Value:=starttime1.date;  
            Parameters.ParamByName('endtime').Value:=endtime1.date;  
            ExecSQL;  
          end;  
  运行启动该程序的按钮后系统报错,说“不正常的定义参数对象,提供了不一致或不完整的信息”  
            然后我又按Parameters属性中六个参数的排列顺序又写了一遍,即写了六条之前的传递参数值的语句,得到的结果还是一样!  
  3、我把以上查询语句全部以字符串形式给一个SQLstr的字符型变量的参数,然后用ADOquery控件的SQL.Add方法加载,然后运行得到的结果仍然是那样~  
   
  我还试了其他方法,很多时候又报错说找不到starttime这个参数!  
   
  我所以现在的疑问是:这么长而又复杂的一段select查询语句,还有动态参数,要用什么样的方法来实现最后的显示数据集的功能比较合适?因为复杂,所以细节都比较琐碎,不容易注意到,所以能找尽量直接的方法!  
 

希望能得到一些具体的建议吧~因为这个问题困扰了我几天了,总找不到合适的解决方法~  
  存储过程能解决的话,用存储过程是比较方便的。但是具体怎么用呢?  
 

你的问题只有一个:  
  :starttime   和   :endtime   不能重复使用在同一个adoquery的参数表里。  
   
  处理办法:  
  重新命名:  
  :starttime1~:starttime3  
  :endtime1~:endtime3  
  重新赋值  
   
  再运行  
   
   
 

谢谢,我试一下看看!

果然如你所说!!  
  万分感谢了!!  
  呵呵~~  
  八十分请您笑纳~~

posted @ 2008-10-20 10:33 delphi2007 阅读(110) | 评论 (0)编辑 收藏

ADO组件连接MSSQL数据库的奇怪问题。。 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225211308101.html
使用ADO组件连接SQL数据库后,查询的到的结果(数值型)和在服务器端直接使用MSSQL工具查询的结果不一样???  
  比如字段1在服务器查询出来是100.123,使用ADO查询出来会变成99.23  
   
  是不是ADO的connection设置有问题。我使用的是默认设置。。

1、升级ADO看看  
  2、确定你的SQL和查询分析器的一模一样吗?

SQL是一样的  
   
  ADO是xp2自带的。   开发环境是delphi7

应该不会这么大的误差,100.123   <-->   99.23   ???  
  显然有点不对劲,比如,显示的是同一条记录吗?

差的太离谱....  
 

是。连日期型的数值都会改变。。  
  差在哪里。

日期型会变是正常的,两个对起始的日期定义的不一样,大概差2天吧  
   
  数值型变的这么厉害,就有问题了。

可是在服务器端查询正常。  
   
  我查看时间,发现都是相差几秒钟。  
   
  在企业管理器中查看数值为:17:58:06,  
  在Delphi中看到为17:58:00。  
   
  数据库比较大,大概有2G。  
   
  开发的时候使用会出现有的数值变成0。

能有人解释这个问题吗/?

一般情况下不会碰到这种问题的,所以只能你自己进行调试。  
  1)跟踪Sql语句,然后把跟踪的Sql语句在查询分析器上执行,看结果的异同;  
  2)建议增加一台机器,把数据库和程序换到另一台机器上测试,或者两台机器进行交叉测试。  
 

这是开玩笑么  
  肯定是sql语句的问题

闹鬼了?

SQL语句正常。  
  在两边用同一个语句。

1在服务器查询出来是100.123,使用ADO查询出来会变成99.23  
  ---------------------------------  
   
  碰到过相似的情况,   不过偶是在多层中....  
  单层还没有碰到过....  
   
 

to   hydonlee(青山情)    
   
  那你是怎么解决这个问题的??  
 

偶原来取得数据是通过   clientDataSet1.Data   =   appServer.GetData...  
  发现有这个问题后,   就通过XML的方式传数据过来...就好了.  
   
  数据从服务端传到客户端.

posted @ 2008-10-20 10:33 delphi2007 阅读(194) | 评论 (0)编辑 收藏

关于adoconnection1 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225205158102.html
在Formcreate里,添加  
  Adoconnection1.Close;  
  adoconnection1.ConnectionString:='Provider=SQLOLEDB.1;Password='''';Persist   Security   Info=False;User   ID=sa;Initial   Catalog=example_db;Data   Source=wp';  
  try  
  adoconnection1.Open();  
  except  
    showmessage('连接数据库失败');  
  exit;  
   
  为什么系统提示:用户'administrator'失败呢??

大家来帮忙啊。

设计时进行测试连接,将测试连接成功的ConnectionString拷贝出来,在FormCreate事件中赋值就行了。

SQLServer换成混合身份验证看看!

To   maozefa(阿发伯)    
  是啊,我就是直接拷出来的啊。能测试成功。

To   SmallHand(火龍)  
   
  还要重新装SQL吗???直接用build去连接是能成功的啊。

这是我在formcreat事件里添加的:  
   
  with   adoconnection1   do  
  begin  
          close;  
          connectionstring:='Provider=SQLOLEDB.1;Password='''';Persist   Security   Info=False;User   ID=sa;Initial   Catalog=example_db;Data   Source=wp';  
  end;  
  try  
          adoconnection1.Open();  
  except  
          showmessage('数据库连接失败!');  
   
  然后运行就出现用户'administrator'失败  
 

如果是空密码,就把密码的内容去掉  
  with   adoconnection1   do  
  begin  
          close;  
          connectionstring:='Provider=SQLOLEDB.1;Persist   Security   Info=False;User   ID=sa;Initial   Catalog=example_db;Data   Source=wp';  
  end;

SQLServer换成混合身份验证,设置sa连接密码

你双击设置不行吗,写多了就容易出错

知道了,是adoquery的问题。

posted @ 2008-10-20 10:33 delphi2007 阅读(167) | 评论 (0)编辑 收藏

delphi+ado+oracle碰到难题!!! Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225203107103.html
服务器:繁体WinXP+oracle8i,字符集:ZHT16BIG5.  
   
  客户机:简体WinXP,字符集原来是:ZHS16GBK,现在改为和服务器一样的:ZHT16BIG5.  
   
  功能是要在oracle的VARCHAR字段中保存繁体文字,在BLOB字段中保存图片.  
   
  现在碰到以下问题:  
   
        1.如果采用'Microsoft   OLE   DB   Provider   for   Oracle',在简体客户机上向服务器添加简体文字,在繁体服务器上文字转换为繁体,并且显示正常.但是没办法向BLOB字段添加大于4k的jpg图片,使用了各种方法也没有办法解决,包括流.,请问有没有办法添加大于4k的图片?  
   
        2.如果采用"Oracle   Provider   for   OLE   DB",向Oracle服务器的BLOB字段添加图片正常,简体转换为繁体大部分文字显示正常,部分显示'?',例如简体'粤东莞'添加到繁体服务器上就显示繁体   '?东莞',在简体客户机上select出来又是正常的.请问有没有办法使繁体oracle所有繁体文字显示正常?  
   
  试了好多天了也没有找到办法,请各位大侠帮忙解决其中之一.谢谢!

Oracle用ODAC这个组件试试。应该可以。  
   
  第二个问题:  
  如果你的oracle的字符集是繁体,插入简体汉字,显示会不正常。如果你把oracle的字符集改为简体中文,就可以正常显示简体。  
  这个无所谓。重要的是客户端可以正常显示就可以。  
   
  可以在oracle服务器上面打开注册表  
   
  run->regedit.exe->HKEY_Local_Machine->software->oracle->homeo->NLS_LANG=SIMPLIFIED   CHINESE_CHINA.ZHS16GBK  
  (健值)             简体中文         繁体中文  
  NLS_LANG   =   SIMPLIFIED   CHINESE_CHINA.ZHS16GBK  
   
  不同的oracle   可能位置不一样。  
 

没有遇到这多字符集处理的情况  
   
  对于图片文件,我用long   row字段,好像没有遇到你说的那种情况  
  我两个驱动都用过,不过,我们的服务器用的是aix  
   
  在win平台下,你还是老老实实用mssql才是王道!

我试了一下,sizzg的第二个方法可以解决问题,只是各种信息是乱码,不过只要不影响客户端使用就OK了,我要找一个繁体的客户端测试一下.!  
  对于lwk_hlj的方法,我想也可以解决问题,但是Oracle以后好象不支持long   row字段,如果实在没有办法,我也只有采用这种方法.  
  在此谢谢sizzg和lwk_hlj了.

这下真是难搞了

对于sizzg的方法,我在繁体客户机上试了,也要改注册表,这样可能不行,我不可能到每一台繁体客户机上改注册表,改天我再试一下lwk_hlj的方法.

不成熟的意见:好象有一个ADO连接里面有什么PACKAGE   SIZE=4096这样的东西吧?会不会和你的4K大小有所关系呢?这个我没有验证过,你自己看一下下吧。

我回过很多贴了,ado对oracle的支持是有问题的,特别是对blob字段  
  1.升级mdac  
  2.一定要用"Oracle   Provider   for   OLE   DB"  
  在delphi下用oracle,最好用odac,bde/odbc也没问题,你也可用dbexpress  
 

posted @ 2008-10-20 10:33 delphi2007 阅读(341) | 评论 (0)编辑 收藏

在Delphi中,TabSheet控件在哪里? Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225195756104.html
我在用Delphi语言学习开发软件的时候,发现TabSheet控件的找不到,我找遍了所有的控件都没有,哪位知道的请告诉我好吗?在此谢谢了!

Tab   sheets   are   typically   referred   to   as   pages.   TPageControl   maintains   an   indexed   array   of   its   tab   sheets   in   its   Pages   property.

添加一个TPageControl;  
  然后new  
          TabSheet

posted @ 2008-10-20 10:33 delphi2007 阅读(1346) | 评论 (0)编辑 收藏

彩票软件中热温冷算法的实现情况 Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225191206105.html
谁知道彩票软件中热温冷是如何用算法来实现的?前10期内共出3期的为温码,小于3期的为冷码,大于3期的为热码!!!

这应该是简单的次数判断

posted @ 2008-10-20 10:33 delphi2007 阅读(111) | 评论 (0)编辑 收藏

急!请问在rvsystem中如何设置单元格的高度! Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225191119106.html
请问在rvsystem中如何设置单元格的高度!再请问settab和tab中的参数各是什么意思!?谢谢!
posted @ 2008-10-20 10:33 delphi2007 阅读(155) | 评论 (0)编辑 收藏

在数据库判断时间时以下代码不会表达哦~~ Delphi / Windows SDK/API
http://www.delphi2007.net/DelphiDB/html/delphi_20061225175336107.html
with   Query2   do  
  begin  
  close;  
  sql.Clear;  
  sql.add('select   借书证号码,所借日期   from   lend   where   借书证号码=:qame   and   所借日期>现在时间+30天   ');  
  ParambyName('qame').AsString   :=   edit14.Text;  
  open;  
  ShowMessage(IntToStr(RecordCount));  
  end;  
   
  现在时间+30天应该如何写哦~~  
 

你把所借日期也用参数表示,DateTime类型   :=   now   +   30;  
   
 

或者:DateTime类型参数   :=   date   +   30;

楼主我已在你此前一贴回贴了,请看一下吧.(用   dateAdd("d",30,Now)这个VBS函数)  
  http://community.csdn.net/Expert/topic/5254/5254714.xml?temp=6.524295E-02

还有,给楼主提个建议:     不要用BDE控件   ,   用ADO控件吧!

posted @ 2008-10-20 10:33 delphi2007 阅读(92) | 评论 (0)编辑 收藏

仅列出标题
共34页: First 24 25 26 27 28 29 30 31 32 Last