在C++ Builder中实现拖放功能 Windows中的拖放功能大家一定很熟悉了，如文件的转移，拷贝等操作用鼠标轻轻一拖即可，在编写程序中有时也用到拖放，那么如何实现呢？现以C++ Builder5（简称CB5）为例，分析拖放功能的具体实现。 一．工具条的拖放 ---- 要实现拖放功能，首先必须了解几个与拖放有关的属性和方法， 对于TControl控件，CB5提供了三个属性，DockSite，DragKind和DragMode。灵活运用这三个属性会得到意想不到的效果。这三个属性的意义是： ---- DockSite：指定当前控件是否接受Drag-and-Dock类型的操作 ---- DragKind：拖放种类，分为dkDrag和dkDock两种 ---- DragMode：拖放模式，分为自动和手动模式两种 ---- 其中Dock操作是指某控件脱离它的Parent，转而成为另一个控件的Child，也就是两个控件合并。若某一控件的DockSite为True，表明它接受执行Dock操作的某控件，并成为它的Parent。 ---- 著名的Office工具条可以随意拖放，其实实现起来很简单：在Form上放一CoolBar控件，再在CoolBar控件上随意放几个ToolBar控件，它们的属性设置代码如下：
    CoolBar1.DockSite=true;

    ToolBar1.DragKind=dkDock;

    ToolBar1.DragMode= dmAutomatic;
---- 其它ToolBar的属性设置与ToolBar1的属性设置相同，编译运行程序，拖动工具条试试，Cool极了吧。 二、任何两上控件间的拖放 ---- 与此操作有关的几个函数有： ---- BeginDrag：开始执行拖放操作，如果控件的DragMode为dmManual，则必须调用此函数，如果DragMode为dmAutomatic，则不用调用。 ---- OnDragOver：当被拖放的对象经过此控件时触发此事件，其中的参数Accept表示是否接受拖放的对象。 ---- OnDragDrop：当放下被拖放的对象时触发此事件。 ---- 下面举例说明拖放的实现过程： ---- 在CB5中新建一工程，在Form1上放两个ListBox，分别命名为ListBox1，ListBox2，打开ListBox1的Items属性框，随便输入几行字符串。 ---- 其属性设置如下：
    ListBox1->MultiSelect=true;

    // MultiSelect属性设为true，表示可以多选

    ListBox1->DragMode= dmAutomatic;

    ListBox2->MultiSelect=true;

    ListBox2->DragMode= dmAutomatic;

    //两个ListBox拖放事件相同，可以互相拖放

    ListBox2->OnDragOver= ListBox1DragOver;

    ListBox2->OnDragDrop= ListBox1DragDrop;

    ListBox2->OnStartDrag= ListBox1StartDrag;

    在头文件中设置两个int型变量CurIndex，NewIndex

    程序代码如下：

    //-----------------------------------------------------------

    #include < vcl.h >

    #pragma hdrstop

    #include "unit1.h"

    #include "FileCtrl.hpp"

    //-----------------------------------------------------------

    #pragma package(smart_init)

    #pragma resource "*.dfm"

    TForm1 *Form1;

    //----------------------------------------------------------

    __fastcall TForm1::TForm1(TComponent* Owner)

            : TForm(Owner)

    {

    }

    //----------------------------------------------------------

    void __fastcall TForm1::ListBox1StartDrag(TObject *Sender,

          TDragObject *&DragObject)

    {

          //开始执行拖放事件时记录ListBox->ItemIndex;

          CurIndex=((TListBox *)Sender)->ItemIndex;

    }

    //----------------------------------------------------------

    void __fastcall TForm1::ListBox1DragDrop

    (TObject *Sender, TObject *Source,

          int X, int Y)

    {

           int index;

     //如果Sender等于Source，表明在同一控件内执行操作

     //本例用来交换ListBox中的任意两个Items

      if(Sender==Source)

        {

        //得到拖放后的ItemIndex

       NewIndex=Y/(ListBox1->ItemHeight);

      //如果ItemIndex大于ListBox中的Item数，表示拖到最后一个

      NewIndex=NewIndex< ((TListBox *)Sender)- >Items->Count?

        NewIndex:((TListBox *)Sender)->Items->Count-1;

      //执行Move操作，移动Item

      ((TListBox *)Sender)->Items->Move(CurIndex,NewIndex);

           }

           //如果Sender不等于Source，表明在两个控件间执行操作

           //此例是将数据从一ListBox拖到另一个ListBox

           else

           {

      //若只选中一项

      if(((TListBox *)Source)->SelCount==1)

      {

        ((TListBox *)Sender)->Items->Add(((TListBox *)Source)->

        Items->Strings[((TListBox *)Source)->ItemIndex]);

        ((TListBox *)Source)->Items->Delete(((TListBox *)Source)->

        ItemIndex);

      }

      //多选操作

      if(((TListBox *)Source)->SelCount>=1)

      {

         //循环操作，测试哪些项被选中

         for(index=0;index< ((TListBox *)Source)- >Items->Count;

           index++)

       if(((TListBox *)Source)->Selected[index])

      ((TListBox *)Sender)->Items->Add(((TListBox *)Source)->

           Items->Strings[index]);

        //从后向前删除Source控件中数据

     for(index=((TListBox *)Source)->Items->Count-1;index>=0;

     index--)

         if(((TListBox *)Source)->Selected[index])

        ((TListBox *)Source)->Items->Delete(index);

      }

           }

    }

    //----------------------------------------------------------

    void __fastcall TForm1::ListBox1DragOver

    (TObject *Sender, TObject *Source,

     int X, int Y, TDragState State, bool &Accept)

    {

     //本例中如果原控件各目标控件都为ListBox控件，则接受拖放

    Accept = Source->ClassNameIs("TListBox")&&

          Sender->ClassNameIs("TListBox");

    }

    运行程序，用鼠标拖拖看。

    //----------------------------------------------------------

    本程序在PWin98+BCB5下编译运行通过
骆名群