在CB中实现Chevron

前一段时间,到昆明转了一圈,做了一个小项目,又接了一个稍大一点的项目。呵呵,明年的收入有保障了。
昆明是个好地方,虽然当地人说已经有些冷了,但我觉得还很暖和,空气确实不错,中午不睡午觉也不觉得困。
唯一受不了的是晚上,6点左右已用餐完毕,已经很丰盛的了,但用户到晚上9点左右,又拉我出去喝酒吃肉,老天,到十一二点还在吃!!真受不了。
事情多,不怎么出去转,最后跑到云南第一村去了一下,还不知道叫什么名字,好象叫大什么村的,说与什么华西村同一类型的,果然不错,挺有规模。
明年三月再去,交付新项目的演示版。
OK,言归正传,这次到昆明去,给用户交付,算是一个了结。在这段时间中,完成了用户提出的几个需求,还有一个没有做,留待回来再做,因为上网不方便,无法处理。
完成的需求主要是以下几个:
1. 画图时,加上分区功能,即在工作区画出分区坐标,如下A 17之类的,便于用户看图定位。

 

实现后,用户可简单地在页面设置功能中完成相应的定制工作,具体的步骤将在后续的使用手册中说明。

 

2.        画图时,元件的管脚名称可简单地通过右键进行修改。
3.        完善实时服务与数据库服务,以支持可视化方式进行设置。
4.        …

未完成的需求说明如下:
若打开多个图之后,将有些文件名称按钮无法显示在工具条上,用户希望在工具条上有个箭头按钮,通过该按钮的点击,可选择那些未显示出来的按钮,就象IE中一样。
这个需求说起来简单,我花了半天功夫,做出来的效果非常的不好看。干脆等回家后再做,上网查查看有没有解决方法。
回家后,查来查去,发现这是一种技术,微软件称之为Chevron!即从 IE 5.0 以后,IE 的工具栏具有了一个新特性:当 IE 窗口缩小,使得工具栏上的按钮不能完全显示时,工具栏右边会出现一个小按钮,点击后出现一下拉列表,显示出被隐藏的按钮。
再深入地查一下,发现有消息进行支持。
再搜下去,希望找到有现成的例子,但满世界的全是Delphi的实现,C++ Builder还没有如此处理。
通过归纳,网上主要有以下几篇文件有用:
1.        Delphi 完全时尚手册之 CoolBar 篇---实现 CoolBar 的新特性 Chevron
2.        #170:How can I display the chevron button for toolbar?
3.        #171:How can I display the chevron for toolbar and open dropdowned popup menu with invisible buttons?
以上几篇文件的地址我没有保存,有意者可上网搜一下,或者问我要即可。
下面就开始试验。
按《Delphi 完全时尚手册之 CoolBar 篇---实现 CoolBar 的新特性 Chevron》中的方法,事情很多,要改VCL中的ComCtrls.pas,再重编译,再实现,忙乎了半天,效果不甚满意。
于是专攻#170与#171,首先按170来做,希望能出现Chevron按钮,然后再处理下拉式菜单。
先把代码录入进去,把下面的代码从Delphi转成C++ Builder

 

  1. procedure TForm1.FormCreate(Sender: TObject); 
  2. const 
  3.   RBBS_NOGRIPPER  = $00000100;  // never show the gripper 
  4.   RBBS_USECHEVRON = $00000200; 
  5.   RBBIM_IDEALSIZE = $00000200; 
  6. var 
  7.   i: Integer; 
  8.   rbi: TSMRebarBandInfo; 
  9.   R: Trect; 
  10. begin 
  11.   inherited; 
  12.   {if somebuttons in toolbar are invisible, add chevron} 
  13.   rbi.cbSize := SizeOf(rbi); 
  14.   rbi.fMask := RBBIM_STYLE or RBBIM_IDEALSIZE; 
  15.   for i := 1 to yourCoolBar.Bands.Count do 
  16.   begin 
  17.     if not Assigned(yourCoolBar.Bands[i-1].Control) or 
  18.        not (yourCoolBar.Bands[i-1].Control is TToolbar) then continue
  19.     SendMessage(yourCoolBar.Handle, RB_GETBANDINFO, i-1, LongInt(@rbi)); 
  20.     rbi.fStyle := rbi.fStyle or RBBS_USECHEVRON; 
  21.     rbi.fStyle := rbi.fStyle and not RBBS_NOGRIPPER; 
  22.     with TToolbar(yourCoolBar.Bands[i-1].Control) do 
  23.       if ButtonCount <> 0 then 
  24.         with Buttons[ButtonCount-1] do 
  25.           rbi.cxIdeal := Left + Width + 5; 
  26.     SendMessage(yourCoolBar.Handle, RB_SETBANDINFO, i-1, LongInt(@rbi)); 
  27.   end; 
  28. end;

这个倒是不难,在此过程中,我突然发现RBBS_NOGRIPPER、RBBS_USECHEVRON 、RBBIM_IDEALSIZE几个常量在CB中已定义,难道在CB中已有的Chevron的实现?不过,我找了半天,没有找到。还是先自己实现吧,以后再改。
用一个函数吧

 

  1. void __fastcall TForm1::ChevronWorkForCoolBar(TObject * Sender)
  2. {
  3.    TCoolBar * ACoolBar = dynamic_cast<TCoolBar *>(Sender);
  4.    if(!ACoolBar)  return;
  5.    REBARBANDINFO m;
  6.    m.cbSize = sizeof(m);
  7.    m.fMask = RBBIM_STYLE | RBBIM_IDEALSIZE;
  8.    for (int i = 0; i < ACoolBar->Bands->Count; ++i)
  9.    {
  10.       TToolBar * toolbar = dynamic_cast<TToolBar *>(ACoolBar->Bands->Items[i]->Control);
  11.       if (!(toolbar)) continue;
  12.       SendMessage(ACoolBar->Handle, RB_GETBANDINFO, i, long(&m));
  13.       m.fStyle |= RBBS_USECHEVRON;
  14.       m.fStyle &= ~RBBS_NOGRIPPER;
  15.       if(toolbar->ButtonCount)
  16.       {
  17.          TToolButton * button = toolbar->Buttons[toolbar->ButtonCount - 1];
  18.          m.cxIdeal = button->Left + button->Width + 5;
  19.       }
  20.       SendMessage(ACoolBar->Handle, RB_SETBANDINFO, i, long(&m));
  21.    }
  22. }
设置ToolBar的Wrapable属性为false,AutoSize为true,在Form.OnResize事件中调用ChevronWorkForCoolBar,结果一运行,>>箭头就出来了,爽。

再下来就该是下拉菜单了,学习171后,发现是要捕获RBN_CHEVRONPUSHED消息,该消息附于WM_NOTIFY之中(当然,此说法不严谨),那就处理WM_NOTIFY消息呗。
  1. void __fastcall OnChevronNotify(TWMNotify & message); 
  2. BEGIN_MESSAGE_MAP
  3.    VCL_MESSAGE_HANDLER(WM_NOTIFY, TWMNotify, OnChevronNotify);
  4. END_MESSAGE_MAP(TForm)

在录入消息处理函数的过程中,准备实现以下代码的CB转化

  1. type 
  2.     PNMREBARCHEVRON = ^TNMREBARCHEVRON; 
  3.     TNMREBARCHEVRON = packed record 
  4.      hdr: TNMHdr; 
  5.      uBand: Integer; 
  6.      wID: Integer; 
  7.      lParam: LPARAM; 
  8.      rc: TRect; 
  9.      lParamNM: LPARAM; 
  10. end;

正录入的过程中,我突然想到,刚才发现RBBS_NOGRIPPER、RBBS_USECHEVRON 、RBBIM_IDEALSIZE几个常量在CB中已定义,是否在CB中有相应的结构?
暂不管,结果调试了一会,发现可以不用这个结构。按如下方式进行实现即可。

 

  1. void __fastcall TForm1::OnChevronNotify(Messages::TWMNotify & message)
  2. {
  3.    TToolButton *toolButton;
  4.    TMenuItem * mi;
  5.    TPoint P;
  6.    if(message.NMHdr->code == RBN_CHEVRONPUSHED)
  7.    {
  8.       TToolBar * tb = dynamic_cast<TToolBar *>(CoolBar->Bands->Items[0]->Control);
  9.       if(!tb)  return;
  10.       TRect r = tb->ClientRect;
  11.       int i, j = -1;
  12.       for(i = PopupMenu1->Items->Count - 1; i >= 0; --i)
  13.       {
  14.          mi = PopupMenu1->Items->Items[i];
  15.          PopupMenu1->Items->Delete(i);
  16.          delete mi;
  17.       }
  18.       for(i = 0; i < tb->ButtonCount && j == -1; ++i)
  19.       {
  20.          TToolButton * toolButton = tb->Buttons[i];
  21.          if(toolButton->Left + toolButton->Width > r.right)
  22.             j = i;
  23.       }
  24.       if(j != -1)
  25.       {
  26.          for(i = j; i < tb->ButtonCount; ++i)
  27.          {
  28.             mi = new TMenuItem(this);
  29.             toolButton = tb->Buttons[i];
  30.             if(toolButton->Style == tbsSeparator)  mi->Caption = "-";
  31.             else
  32.             {
  33.                mi->Caption = toolButton->Caption;
  34.             }
  35.             PopupMenu1->Items->Add(mi);
  36.          }
  37.          P = tb->ClientToScreen(Point(tb->Buttons[j]->Left, tb->Buttons[j]->Top + tb->Buttons[j]->Height));
  38.          PopupMenu1->Popup(P.x+2, P.y+2);    
  39.       }
  40.    }
  41. }
运行后,呵呵,效果出来了。

 

在此过程中,还发现一个问题,即Chevron按钮按下时,消息是发给CoolBar的父窗口的,也就是说,如果CoolBar的父窗口对象不为本Form窗口,则上面的OnChevronNotify将不会被执行。
其实,找到问题所在,解决问题也就简单了。下面仅列出解决方法代码,以备后用。
开始:

  1. __fastcall TForm1::TForm1(TComponent* Owner)
  2.    : TForm(Owner)
  3. {
  4.    InstanceChildWndProc = MakeObjectInstance(ChildWndProc);
  5.    OldChildWndProc = (void *)(GetWindowLong(Panel1->Handle,GWL_WNDPROC));
  6.    MyOldChildWndProc = (void *)(GetWindowLong(Handle,GWL_WNDPROC));
  7.    SetWindowLong(Panel1->Handle, GWL_WNDPROC, long(InstanceChildWndProc));
  8. }
结束:
  1. void __fastcall TForm1::FormDestroy(TObject *Sender)
  2. {
  3.    SetWindowLong(Panel1->Handle, GWL_WNDPROC, long(OldChildWndProc));
  4.    FreeObjectInstance(InstanceChildWndProc);   
  5. }

处理:

  1. void __fastcall TForm1::ChildWndProc(Messages::TMessage &Message)
  2. {
  3.    if(Message.Msg == 78)
  4.       Message.Result = CallWindowProc((FARPROC)MyOldChildWndProc, Handle, Message.Msg, Message.WParam, Message.LParam);
  5.    else
  6.       Message.Result = CallWindowProc((FARPROC)OldChildWndProc, Handle, Message.Msg, Message.WParam, Message.LParam);
  7. }

万事OK。

按我上述过程,应该能实现Chevron功能了,如果不行,再从头检查一下.当然,可以给我发信ChenBinWen@gmail.com,我可以发源码给你.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值