数据窗口揭秘:未公开的数据窗口事件

  数据窗口揭秘:未公开的数据窗口事件  
   
  (作者:Mark   Brown)  
   
  到目前为止,PB的数据窗口控件仍是PB众多控件中功能最强大,最复杂的控件。  
   
  数据窗口固有的行为  
   
  大家对数据窗口固有的行为都很熟悉。不知道你发现没有,几乎不可能覆盖数据窗口固有的行为。它有自己的一套!  
   
  事实确实如此,数据窗口控件确实有自己的固有行为。数据窗口控件是一个完全独立的子窗口,它可以显示信息,可以独立于父窗口处理Windows消息。然而,与别的并不复杂的控件(例如:commandbuttons,statictexts,singlelineedits)一样,数据窗口控件通过"Notification"Windows消息来与外界(父窗口)联系.由于可以通过预定义的PB事件在数据窗口控件与用户接口之间沟通,PB开发者大多数情况下不会用到这些内部消息。正是由于这些原因,SYBASE公司选择了不公开这些内部消息。显然,他们没有想到有人会使用它们。  
   
  未公开的数据窗口消息  
   
  然而,在许多场合下这些未公开的消息还是很有用的。在一个父窗口有多个数据窗口控件时会很有用的。例如,为了共享某些代码,你可以用父窗口级的全局的不同的数据窗口事件来替代创建用户对象。   最明显的例子是在数据窗口中用到DDDW显示风格,你将发现这些未公开的消息会很有用处,它们可以用来处理这些子数据窗口。   在介绍这些消息之前,需要简单描述一下PB事件与Windows3.1消息之间的区别。  
   
  PB事件与Windows3.1消息之间的区别    
   
  除了GroupBox控件和不同的绘画对象(Line,Oval,Rectangle以及RoundRectangle)以外,每一个在PB画板中可用的Windows控件都有一个或几个事件。PB预定义的事件与Windows3.1的消息并不是完全一致。实际上,大多数的PB事件只是简单的接受类似的Windows消息,了解这一点对于以后掌握还没有在PB控件中定义的Windows3.1消息很重要。  
   
  Windows消息类别  
   
  消息分为两类:传送消息及通知消息。传送消息即是传送给Windows控件去执行某个特定的动作,例如:重新设定Checkbox的选项。这种消息也可以用来确定特定控件的状态信息,如:检测命令按钮是否是高亮显示。另一方面,通知消息用来在应用和Window控件之间交互或通报。例如:当用户在数据窗口控件中点击鼠标时,控件通知它的父窗口它将得到输出焦点(假定它还没有得到焦点)。这个通知消息对应于数据窗口的Getfocus事件。  
   
  PB消息的内部执行  
   
  为了便于举例说明这些通知消息是如何在PB内部执行的,我们用命令按钮控件来检测消息是如何运转的。  
   
  当用户点击命令按钮控件时,Windows依次发送一个wm_command消息。这个通知消息发送给用户选中的子窗口的父窗口(命令按钮,多行编辑框,等等,实际上都是子窗口)。  
   
  在内部处理中,每一个PB窗口都有一个负责正确把Windows消息传送到PB事件中的Windows消息处理函数(对于有经验的Windows编程人员来说是WndProc())。也就是PB的内部消息处理函数负责解释wm_command消息的意义。对于命令按钮控件来说,控件的句柄(hWnd),以及通知代码bn_clicked作为wm_command的参数被传送。通知代码bn_clicked由名字就可知道这是一个显示鼠标点击按钮控件按钮的通知代码。接受到wm_command消息后,PB由Windows句柄可知用户选中的是哪一个命令按钮。在接受到bn_clicked通知代码后,PB触发选中控件的Clicked事件。稍后我们将要告诉你如何自己处理命令按钮的通知消息。  
   
  为何不用PB的事件?  
   
  既然PB已经定义了许多与Windows3.1消息对应的事件,直接使用PB定义的事件不是比截取wm_command消息更简单吗?对于标准Windows控件来说,确实如此。然而,考虑一下子数据窗口(如:DDDW下拉数据窗口),这种特殊的控件只会触发父数据窗口的ItemChanged事件,并且这种情况仅仅发生在用户改变了下拉数据窗口的项目时会发生。然而,问题出来了,如果下拉数据窗口有多个重复的显示值会发生什么呢?仅当选择第一值时会触发Itemchanged事件,选择以后的任何一个都不会触发任何事件。(举个例子比较容易明白:一张产品代码表:  
   
  编码   产品名称    
  01001   渣油    
  01002   氢气    
  01003   硫酸    
  02001   氢气    
  02002   汽油    
  02003   柴油    
   
  上表中有两个“氢气”,”编码“的前两个数值:01:原料;02:半成品;可以看到”产品名称“中有两个”氢气“,一个是原料,一个是半成品。用下拉数据窗口,显示值是”产品名称“,数据值是”编码“,那么你将看到你将无法选中半成品的”氢气“。  
   
  这种情况下修改编码表肯定不是好办法。唯一的办法是自己截获数据窗口控件的通知消息。  
   
  截获wm_command消息  
   
  你可以从本站电子书籍的one.pdf中看到wm_command消息对应PB的pbm_command事件,为了截获不同的数据窗口通知消息,你必须首先为含有数据窗口的父窗口定义一用户自定义事件”ue_command",wm_command消息的参数会通过PB的全局变量message对象来传递。  
   
  当我们引用的Windows的”消息“时,我们实际指的是一种用来传给不同的消息处理函数(还记得WndProc()吗?)的小的数据结构。PB的message对象的前四个属性与Windows的内部消息结构的前四个属性对应。我们需要注意的是属性:message.longparm.  
   
  如果想要了解wm_command消息的详细描叙及用途,可以参考WindowsSDK文档(软件开发包)。我们想要了解的是如何用这个消息来通知应用用户选择了一个子窗口控件。  
   
  当这个消息传给应用时,消息的long型参数包含两部分信息:低字节是子控件的窗口句柄,高字节是通知代码(如:bn_clicked).这里有一个例子:  
   
  //   Script   for   ue_command   event   (WM_COMMAND)    
   
  uint   hWndChildControl,   nNotifyCode    
   
  //   Get   the   child   control's   window   handle    
   
  hWndChildControl   =   IntLow(Message.LongParm)    
   
  //   Was   the   message   sent   from   the   OK   Button?    
   
  IF   hWndChildControl   =   Handle(cb_ok)   THEN    
   
  //   Get   the   notification   code   sent   by   the   control    
   
  nNotifyCode   =   IntHigh(Message.LongParm)      
   
  //   Is   it   a   BN_CLICKED   message?    
   
  IF   nNotifyCode   =   0   THEN   MessageBox('WM_COMMAND',   'BN_CLICKED')    
   
  END   IF    
   
  END   IF    
   
  当你使用这种方法处理Windows消息时需要注意的是:是PB的内部消息处理函数接受并处理Windows消息,然后触发相关的PB事件并执行脚本。这也适用于wm_command消息本身。也就是说,如果在与你截获的通知消息对应的PB事件中有脚本,那么脚本会最先执行(在执行ue_command的脚本之前)。  
   
  未公开的数据窗口消息  
   
  将近有四十个未公开的数据窗口控件通知代码,对学者,好象有点多。然而,这其中的许多对应你平时已经很熟悉的PB事件。与我们已经讨论的别的Window控件一样,数据窗口控件发送通知代码给wm_command消息。  
   
  下面是这些未公开的数据窗口的通知代码,对应的PB事件,IDs;如果代码没有给PB的对象及控件占有,本文给出了关于何种情况导致发送通知代码的简要解释。  
   
   
  ID                                                             Code         Name   Definition  
  pbm_dwnitemchange                               256           ItemChanged   See   Objects    
  pbm_dwnitemvalidationerror             512           ItemError   ''  
  pbm_dwnretrievestart                         768           RetrieveStart   ''  
  pbm_dwnretrieveend                             769           RetrieveEnd   ''  
  pbm_dwnretrieverow                             770           RetrieveRow   ''  
  pbm_dwnupdatestart                             1024         UpdateStart   ''  
  pbm_dwnupdateend                                 1025         UpdateEnd   ''  
  pbm_dwnlbuttondblclk                         1280         DoubleClicked   ''  
  pbm_dwnlbuttonclk                               1281         Clicked   ''  
  pbm_dwnrbuttondblclk                         1282         RightDoubleClicked              
              *   Same   as   DoubleClicked   event,   except   the   right        
                    mouse   button   was   used.  
  pbm_dwndberror                     1536         DBError   See   Objects   and   Controls.  
  pbm_dwnitemchangefocus     1792         ItemFocusChanged   ''  
  pbm_dwnrowchange                                 2048         RowFocusChanged   ''  
  undefined                                               2049         SelectionChanged                  
              *   Unique   to   DropDownDataWindows;   similar   to   the        
                    RowFocusChanged   event,   but   sent   only   after   the    
                    mouse   button   has   been   released.  
  pbm_dwntabout                                       2304         TabOut      
                  *   When   user   presses   the   Tab   key   to   leave   the   last   editable              
                  field   on   a   Data-Window.  
  pbm_dwnbacktabout                               2305         BackTabOut              
              *   When   user   presses   Ctrl-Tab   to   leave   the   first   editable   field          
                    on   the   DataWindow.  
  pbm_dwntabupout                   2306         TabUpOut                  
              *   When   the   user   presses   the   up-arrow   in   an   edit   control   of   a              
                    Freeform   style   DataWindow.  
  pbm_dwntabdownout                               2307         TabDownOut              
              *   When   the   user   presses   the   down-arrow   in   an   edit   control    
                    of   a   Freeform   style   DataWindow.  
  pbm_dwnprocessenter                           2308         ProcessEnter          
              *   When   the   user   presses   the   Enter   key.  
  pbm_dwnkillfocus                                 2309         LoseFocus                
              (See   Objects   and   Controls)  
  pbm_dwnsetfocus                   2310         GetFocus   ''  
  pbm_dwnmousemove                                 2311         MouseMove                
              *   When   the   user   moves   the   mouse   within   the   Data-Window   control.  
  pbm_dwnlbuttonup                                 2313         LeftButtonUp          
              *   When   the   user   releases   the   left   mouse   button.  
  pbm_dwnrbuttonclk                               2314         RightClicked          
              *   When   the   right   mouse   button   is   clicked.    
  pbm_dwnrbuttonup                                 2315         RightButtonUp        
              *   When   the   right   mouse   button   is   released.  
  pbm_dwnchanging                   2316         EditChanged            
              (See   Objects   and   Controls)  
  pbm_dwnhscroll                                     2317         ScrollHorizontal   ''  
  pbm_dwnvscroll                                     2318         ScrollVertical   ''  
  pbm_dwnsql                                             2319         SQLPreview   ''  
  pbm_dwnresize                                       2320         Resize   ''  
  undefined                                               2321         PosChanged              
              *   When   the   user   or   a   script   moves   a   DataWindow   (i.e.,   changes  
    its   position).  
  pbm_dwnprintstart                               2323         PrintStart              
              (See   Objects   and   Controls)  
  pbm_dwnprintpage                                 2324         PrintPage   ''  
  pbm_dwnprintend                   2325         PrintEnd   ''  
  pbm_dwnkey                                             2326         Key   ''  
  pbm_dwndropdown                   2327         DropDown                  
              *   When   the   drop-down   portion   of   a   field   with   the      
                    DropDownDataWindow   edit-style   becomes   visible.  
  pbm_dwndragdrop                   2560         DragDrop                  
              (See   Objects   and   Controls)  
  pbm_dwndragenter                                 2561         DragEnter   ''  
  pbm_dwndragleave                                 2562         DragLeave   ''  
  pbm_dwndragwithin                               2563         DragWithin   ''  
  如何使用这些消息  
   
  这里有一个例子教你如何在脚本中使用这些未公开的通知代码。  
   
  有一个地址表的数据窗口,对city,zip字段用DDDW显示方式。city字段的DDDW会给用户一个城市列表,每一个又有分别的州及邮政编码,用户从下拉城市列表中选中一个城市时,希望可以同时确定州及邮政编码。  
   
  同时要注意到:许多城市有多个邮政编码(如:西雅图就有几百个!),当用户从如:西雅图,WA   98001...西雅图,WA   98019   列表中选择一个时,仅仅只会触发Itemchanged事件一次。如果不管用户可能选择一个完全不同的邮编的情况,将不会触发别的PB事件。如果有的话,只可能是子数据窗口的RowFocusChanged事件。(记住,此事件仅当用户用鼠标或箭头键在数据窗口中的行间移动时触发)。  
   
  好了,我们要作的既是截获子数据窗口发送的wm_command消息。我们可以用上面处理命令按钮的方法来处理,不过有一点不同。首先,DDDW实际上是个子数据窗口,所有的通知消息会传给它的父数据窗口(不是父窗口)。所以你必须在数据窗口控件中定义自定义事件“ue_command".   下面是ue_command事件中的脚本:  
   
  //   Script   for   ue_command   event   (WM_COMMAND)  
  int   iRet,   iDWRow,   iDDRow  
  string   sDWCol  
  DataWindowChild   dwc  
  //   Is   the   notification   message   from   our   DDDW?  
  sDWCol   =   This.GetColumnName()  
  IF   sDWCol   =   'city'   THEN  
  //   Is   it   the   RowFocusChanged   Notification   Code?  
  IF   IntHigh(Message.LongParm)   =   2048   THEN  
  //   Get   child   DataWindow   control  
  iRet   =   This.dwGetChild(sDWCol,   dwc)  
  //   Get   the   DataWindow's   current   row  
  iDWRow   =   This.GetRow()  
  //   Get   the   DropDown's   current   row  
  iDDRow   =   dwc.GetRow()  
  IF   iDDRow   >   0   THEN  
  iRet   =   This.SetItem(iDWRow,   'state',   dwc.GetItemString(iDDRow,   'state'))  
  iRet   =   This.SetItem(iDWRow,   'zip',   dwc.GetItemString(iDDRow,   'zip'))  
  ELSE  
  iRet   =   This.SetItem(iDWRow,   'state',   '')  
  iRet   =   This.SetItem(iDWRow,   'zip',   '')  
  END   IF  
  END   IF  
  END   IF  
  潜在的风险    
   
  当在你的应用中使用了以上所说的数据窗口通知代码后,你应该知道这种潜在的风险。事实是Sybase公司故意决定使这些信息不能轻易得到,至少,给我的印象是如此。风险在于Sybase公司可能在将来改变通知代码的定义,但是对我来说,冒这点风险得到的好处是显而易见的。  
   
  [翻译的不好,请谅解,谢谢!!!]    
   
  作者:段江    
   
  (欢迎转载,但请注明出处:PB档案)    

posted @ 2010-11-12 18:58  lenya  阅读(1073)  评论(0编辑  收藏  举报