Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.53/19: Рейтинг темы: голосов - 19, средняя оценка - 4.53
0 / 0 / 0
Регистрация: 30.08.2011
Сообщений: 21
1

Перемещающаяся панель с кнопками

03.11.2011, 16:17. Показов 3975. Ответов 8
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Привет всем!
Почти во всех нормальных программах есть кнопки, группу которых можно перемещать.Я думаю, что такая функция есть и в компоненте ToolBar, но пока там я ее не нашел. Напишите плиз, кто знает, как сделать так чтобы панель с кнопками можно было перемещать.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
03.11.2011, 16:17
Ответы с готовыми решениями:

Как создать свою панель инструментов со своими кнопками?
Здравствуйте! Подскажите, пожалуйста, как создать свою панель инструментов со своими...

Как сделать панель с кнопками внизу, которую можно проматывать
Подскажите, как сделать такую панель? Внизу кнопки и они все не входят на экран, можно промотать...

Разработать программу с двумя кнопками на форме. При нажатии на первую на форму добавляется одна панель Panel
Разработать программу с двумя кнопками на форме. При нажатии на первую на форму добавляется одна...

перемещающаяся шапка??
как сделать чтобы шапка в виде картинки или таблицы.. перемешалась при горизонтальной прокрутке???

8
LK
Заблокирован
03.11.2011, 16:49 2
Лучший ответ Сообщение было отмечено как решение

Решение

Quick and easy toolbar customization
by Damon Chandler

Many applications allow you to specify which buttons appear on its toolbars. In order to provide such a scheme in your own applications, you’ll need a mechanism for dragging and dropping tool buttons. Fortunately, the VCL—namely, the TControl class—provides built-in drag-and-drop support. In this article, I’ll provide a brief review of drag-and-drop, and then I’ll show you how to use this technology to easily add customization support to your application’s toolbars.

The DragMode property

All TControl descendants provide a DragMode property, which can take on one of two values: dmManual or dmAutomatic. When the DragMode property is set to dmManual (the default), the control behaves normally; specifically, the control does no special processing of mouse messages. In contrast, when DragMode is set to dmAutomatic, the control initiates the dragging process automatically by calling the BeginDrag() method in response to left mouse-button messages (WM_LBUTTONDOWN and WM_LBUTTONDBLCLK).

The OnStartDrag event

The BeginDrag() function puts the control into "dragging mode," at which point the control’s OnStartDrag event is fired. Here’s the signature of the OnStartDrag event:
C++
1
2
3
4
typedef void __fastcall
  (__closure *TStartDragEvent)(
    System::TObject* Sender,
    TDragObject* &DragObject);
The Sender parameter specifies a pointer to the control that’s being dragged (i.e., the control whose BeingDrag() method was called). The DragObject parameter is a reference to a TDragObject instance that will be used during the dragging process. As I’ll discuss shortly, you can use the DragObject parameter to specify custom drag-and-drop cursors. If you don’t assign a value to the DragObject parameter, the TControl class will create its own TDragObject-type object (specifically, of type TDragControlObject).

The OnDragOver event

After the OnStartDrag event handler is called, all subsequent mouse messages are sent to DragObject’s internal window. The TDragObject class uses these messages to determine how the dragging process should proceed. For example, as the control (i.e., the control that’s being dragged) is dragged over other controls, DragObject receives the WM_MOUSEMOVE message, in response to which, it determines which VCL control is under the mouse cursor and then calls that control’s OnDragOver event handler:
C++
1
2
3
4
5
6
7
typedef void __fastcall
  (__closure *TDragOverEvent)(
    System::TObject* Sender,
    System::TObject* Source,
    int X, int Y,
    TDragState State,
    bool &Accept);
The Sender parameter specifies a pointer to the control that’s being dragged over (i.e., the control under the mouse cursor). The Source parameter specifies either a pointer to the TDragObject-type instance that you assigned to the DragObject parameter in the OnStartDrag event handler, or a pointer to the control that’s being dragged (i.e., the control whose BeingDrag() method was called) if you left the DragObject parameter at its default value of NULL. The X and Y parameters specify the location of the mouse cursor in coordinates relative to the client area of the control that’s being dragged over. The State parameter specifies whether the mouse cursor has just entered (dsDragEnter), is leaving (dsDragLeave), or is moving over (dsDragMove) the control’s client area. The Accept parameter is your way of indicating whether or not to accept the drop. Namely, if the control that’s being dragged can be dropped on the control that’s being dragged over, you set the Accept parameter to true; otherwise, you set Accept to false. DragObject will change the mouse cursor accordingly to provide visual feedback to the user.

The OnDragDrop event

When the user drops the control that’s being dragged onto the control that’s being dragged over (and the latter control accepts the drop by setting the Accept parameter to true in its OnDragOver event handler), the latter control’s OnDragDrop event is fired. Here’s what that event looks like:
C++
1
2
3
4
5
typedef void __fastcall
  (__closure *TDragDropEvent)(
    System::TObject* Sender,
    System::TObject* Source,
    int X, int Y);
The Sender parameter specifies a pointer to the control that accepted the drop (i.e., the control that was being dragged over). The Source parameter specifies either a pointer to the TDragObject-type instance that you assigned to the DragObject parameter in the OnStartDrag event handler, or a pointer to the control that was dropped (i.e., the control that was being dragged) if you left the DragObject parameter at its default value of NULL. The X and Y parameters specify the location of the mouse cursor (in coordinates relative to the client area of the control that’s being dragged over).

Keep in mind that, although the TControl class will initiate the drag-and-drop process for you, it’s up to you to handle the drop (e.g., by changing a control’s location).

The OnEndDrag event

The OnEndDrag event is fired after the user drops the control (regardless of whether or not the drop was accepted). In contrast to OnDragOver and OnDragDrop, the OnEndDrag event handler is called for the control that was being dragged:
C++
1
2
3
4
5
typedef void __fastcall
  (__closure *TEndDragEvent)(
    System::TObject* Sender,
    System::TObject* Target,
    int X, int Y);
The Sender parameter specifies a pointer to the control that was being dragged. The Target parameter specifies a pointer to the control on which Sender was dropped. If no control accepted the drop, or if Sender was dropped on a non-VCL control, the Target parameter will indicate NULL. If Target is non-NULL, then the X and Y parameters specify the location of the mouse cursor in coordinates relative to the client area of the control that’s being dragged over. If Target is NULL and Sender was dropped within the application, then the X and Y parameters will both be zero. If Target is NULL and Sender was dropped outside of the application (e.g., on the desktop), then the X and Y parameters specify the location of the mouse cursor in screen coordinates.

Using a TDragObject descendant

As I mentioned earlier, you don’t have to rely on the TControl class’s internal TDragObject-type instance to handle the dragging and dropping. Instead, you can assign your own TDragObject-type instance to the DragObject parameter in the OnStartDrag event. Why would you want to do this? Well, the TDragObject class provides two very useful virtual methods: GetDragImages() and GetDragCursor(). By overriding these methods, you have complete control over the cursors that will be used during the drag-and-drop process. In addition, by using your own TDragObject descendant class, you can easily check whether or not to accept a drop. Recall that if you assign your own TDragObject-type instance to the DragObject property in the OnStartDrag event, the Source parameter of the OnDragOver event will specify a pointer to your TDragObject-type instance. This way, you don’t have to compare the Source parameter with a specific control; rather, you simply check whether or not Source is indeed your TDragObject-type descendant.

Listing A contains the definition of a TDragControlObject descendant class, TDragTBObject, which we’ll use later for toolbar customization. Specifically, this class overrides the GetDragCursor() method in order to display custom, toolbar-specific drag-and-drop cursors. Also, the GetDragImages() method is coded to always return NULL; this guarantees that the custom cursors will always be used, regardless of the control that’s being dragged. (List views and tree-views, for example, display their own drag-and-drop cursors; returning NULL in GetDragImages() will prevent these cursors from being generated.)

Drag-and-drop customization for toolbars

To keep things as clear as possible, I’ll demonstrate toolbar customization by using utility functions and methods of the TForm1 and TCustomizeDlg classes, whose declarations are provided in Listings B and C. The application’s main form, Form1, and the customization dialog, CustomizeDlg, are depicted in Figure A. (For now, ignore the fact that the toolbars contain no buttons. In the article "Saving and loading components," I’ll show you how to stream the toolbars to and from a file.)

Recall that there are two main customization features that require drag-and-drop support: (1) the user needs to be able to drag-and-drop new buttons onto the toolbar; and (2) the user needs to be able to rearrange the toolbar’s existing buttons. Form1 contains one TCoolBar (CoolBar1) that contains four child TToolBar controls: FileToolBar, EditToolBar, FrmtToolBar, and ViewToolBar. The customization dialog includes a list view (CommandListView), which lists the available commands; this list view will serve as the source of new buttons.

The application’s main form (Form1) contains four toolbars, the customization dialog (CustomizeDlg), and the toolbar popup menu (TBPopupMenu).

Initiating the customization process

Form1 contains a popup menu with a menu item titled "Customize…" We’ll initiate the customization process when this menu item is clicked:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void __fastcall TForm1::
  CustomizeMenuItemClick(TObject *Sender)
{
  CustomizeDlg->Show();
  CustomizeMode(true);
}
 
void __fastcall TForm1::
  CustomizeMode(bool customize)
{
  CustomizeToolBar(
    *FileToolBar, customize);
  CustomizeToolBar(
    *EditToolBar, customize);
  CustomizeToolBar(
    *FrmtToolBar, customize);
  CustomizeToolBar(
    *ViewToolBar, customize);
 
  CustomizeMenuItem->
    Enabled = !customize;
}
As I just mentioned, there are two drag sources: the toolbar’s existing tool buttons and the customization dialog’s CommandListView. Because the customization dialog is displayed only during customization, we can set the CommandListView‘s DragMode property to dmAutomatic at design time. In contrast, we’ll need to toggle the tool buttons’ DragMode properties (between dmManual and dmAutomatic) at run time so that the tool buttons can be dragged and dropped only during customization. We’ll do this from within the CustomizeToolBar() method, which is defined as follows:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void __fastcall TForm1::CustomizeToolBar(
   TToolBar& ToolBar, bool customize)
{
  const int count = ToolBar.ButtonCount;
  for (int idx = 0; idx < count; ++idx)
  {
    TToolButton& Btn =
      *ToolBar.Buttons[idx];
    Btn.DragMode = customize ?
      dmAutomatic : dmManual;
    Btn.OnStartDrag = ToolBtnsStartDrag;
    Btn.OnDragOver = ToolBtnsDragOver;
    Btn.OnDragDrop = ToolBtnsDragDrop;
    Btn.OnEndDrag = ToolBtnsEndDrag;
  }
}
Unfortunately, setting the DragMode property to dmAutomatic will work only for "regular" tool buttons. Because separators don’t receive the WM_LBUTTONDOWN message, the BeginDrag() method is never called for these types of tool buttons. So, in order to drag-and-drop a separator, we’ll need to forward the WM_LBUTTONDOWN message to the separators from within the toolbar’s OnMouseDown event handler:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void __fastcall TForm1::
  ToolBarsMouseDown(
    TObject *Sender, TMouseButton Button,
    TShiftState Shift, int X, int Y)
{
  if (Button == mbLeft)
  {
    // grab a reference to the toolbar on
    // which the mouse button was pressed
    TToolBar& ToolBar =
      static_cast<TToolBar&>(*Sender);
 
    // if the cursor is over a separator
    const int sep_index =
      PtOnSeparator(ToolBar, X, Y);
    if (sep_index >= 0)
    {
      ToolBar.Buttons[sep_index]->
        Perform(WM_LBUTTONDOWN, 0, 0);
    }
  }
}
The ToolBarsMouseDown() method is assigned to all four toolbars at design time. This method uses the X and Y parameters with the PtOnSeparator() utility function to determine if the mouse cursor is over a separator. Here’s how the PtOnSeparator() function is defined:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int PtOnSeparator(
   TToolBar& ToolBar, int X, int Y)
{
  RECT RBtn;
  const POINT PMouse = {X, Y};
  const HWND hToolBar = ToolBar.Handle;
  const int count = ToolBar.ButtonCount;
 
  for (int idx = 0; idx < count; ++idx)
  {
    TToolButton& Btn =
      *ToolBar.Buttons[idx];
    if (Btn.Style == tbsDivider ||
        Btn.Style == tbsSeparator)
    {
      SNDMSG(
        hToolBar, TB_GETITEMRECT, idx,
        reinterpret_cast<LPARAM>(&RBtn)
        );
      if (PtInRect(&RBtn, PMouse))
      {
        return idx;
      }
    }
  }
  return -1;
}
This function simply iterates over all of Toolbar’s buttons, checking to see whether the point specified by the X and Y parameters lies inside the separator’s bounding rectangle. PtOnSeparator() returns either the index of the "hit" separator or –1.

OnStartDrag event handlers

As you can see from the CustomizeToolBar() method, all tool buttons will share the same OnStartDrag event handler, ToolBtnsStartDrag(). CommandListView is assigned it’s own OnStartDrag event handler, CommandListViewStartDrag(), at design time. Here’s how these handlers are defined:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void __fastcall TForm1::
  ToolBtnsStartDrag(TObject *Sender,
    TDragObject *&DragObject)
{
  TToolButton& Btn =
    static_cast<TToolButton&>(*Sender);
  Btn.Marked = true;
  DragTBObject_->Control = &Btn;
  DragObject = DragTBObject_.get();
}
 
void __fastcall TCustomizeDlg::
  CommandListViewStartDrag(
    TObject *Sender,
    TDragObject *&DragObject)
{
  DragTBObject_->Control =
    CommandListView;
  DragObject = DragTBObject_.get();
}
Recall that the OnStartDrag event handler is called immediately after the user begins to drag a control. For the tool buttons, we grab a reference to the TToolButton that’s being dragged (passed via the Sender parameter) and then set the button’s Marked property to true so that the user knows which button he or she is dragging. For CommandListView, the selected item is automatically highlighted. In both cases, we assign the DragObject parameter a pointer to each class’s private DragTBObject_ member (see Listings A and B), which is created in the class’s constructor.

Providing visual feedback

While the user drags a TToolButton or list-view item over the toolbars, we’ll need provide two forms of visual feedback: (1) an indication whether or not the drop will be accepted, and (2) an indication of where on the toolbar the button will be inserted when dropped.

We can provide visual feedback of the acceptance status by adjusting the current mouse cursor. As I mentioned earlier, we’ll do this by using the TDragTBObject class of Listing A. To indicate where on the toolbar the button will be inserted, we’ll use the TB_SETINSERTMARK message, as demonstrated in the following utility functions:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void ShowInsertMark(TToolBar& ToolBar,
  TToolButton& Btn, bool after)
{
  TBINSERTMARK tbim;
  tbim.iButton = Btn.Index;
  tbim.dwFlags = after;
 
  SNDMSG(
    ToolBar.Handle, TB_SETINSERTMARK, 0,
    reinterpret_cast<LPARAM>(&tbim));
}
 
void HideInsertMark(TToolBar& ToolBar)
{
  const TBINSERTMARK tbim = {-1};
  SNDMSG(
    ToolBar.Handle, TB_SETINSERTMARK, 0,
    reinterpret_cast<LPARAM>(&tbim));
}
The TB_SETINSERTMARK message is sent with an lParam value that’s assigned a pointer to TBINSERTMARK structure. This structure contains two data members: iButton, which specifies the index of the TToolButton before or after which the insertion mark should be displayed; and dwFlags, which specifies whether the insertion mark should be displayed before (0) or after (1) the button indicated by iButton. As you can see from the definition of the HideInsertMark() utility function, when the iButton data member is set to –1, the insertion mark is removed.

OnDragOver event handlers

Recall that the OnDragOver event is called for the control that’s being dragged over (not for the control that’s being dragged). For this reason, we don’t need an OnDragOver event handler for CommandListView. We do however, still need two OnDragOver event handlers: one for the toolbar’s tool buttons, and one for the toolbar itself.

As the user drags a TToolButton (or list-view item) over the toolbar, one of two events will be fired depending on which control the mouse cursor is over. If the mouse cursor moves over another "regular" TToolButton, then that tool button’s OnDragOver event handler will be called. If, however, the mouse cursor moves over a part of the toolbar that contains either a separator or no child control, then the toolbar’s OnDragOver event handler will be called.

Notice from the declaration of the CustomizeToolBar() method that we’ve assigned the same OnDragOver event handler, ToolBtnsDragOver, to all of the tool buttons; here’s how that handler is defined:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void __fastcall TForm1::ToolBtnsDragOver(
   TObject *Sender, TObject *Source,
   int X, int Y, TDragState State,
   bool &Accept)
{
  // determine whether to accept the drop
  Accept =
    dynamic_cast<TDragTBObject*>(Source);
  if (!Accept) return;
 
  // grab a reference to the
  // button that's being dragged over
  TToolButton& Btn =
    static_cast<TToolButton&>(*Sender);
 
  // grab a reference to the
  // button's toolbar
  TToolBar& ToolBar =
    static_cast<TToolBar&>(*Btn.Parent);
 
  // if the cursor is leaving the button
  if (State == dsDragLeave)
  {
    // hide the insertion mark
    HideInsertMark(ToolBar);
  }
  // otherwise
  else
  {
    // display an insertion mark
    // before or after the button
    const bool after = X > Btn.Width / 2;
    ShowInsertMark(ToolBar, Btn, after);
  }
}
Because we assigned a value to the DragObject parameter in the OnStartDrag event, the Source parameter of our ToolBtnsDragOver() member function will specify a pointer to a TDragTBObject-type object if the control that’s being dragged is indeed a TToolButton or one of CommandListView’s items. We can therefore set the Accept parameter depending on whether or not Source points to a TDragTBObject-type object.

The ToolBtnsDragOver() event handler will handle the case in which the user drags a button (or list-view item) over a "regular" TToolButton. As I mentioned earlier however, if the user moves the mouse cursor over an empty toolbar or over a separator, the toolbar’s OnDragOver event handler will be called. For this reason, we assign all of Form1’s toolbars the following OnDragOver event handler:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void __fastcall TForm1::ToolBarsDragOver(
   TObject *Sender, TObject *Source,
   int X, int Y, TDragState State,
   bool &Accept)
{
  // determine whether to accept the drop
  Accept =
    dynamic_cast<TDragTBObject*>(Source);
  if (!Accept) return;
 
  // grab a reference to the
  // toolbar that's being dragged over
  TToolBar& ToolBar =
    static_cast<TToolBar&>(*Sender);
 
  // if the cursor is leaving the toolbar
  if (State == dsDragLeave)
  {
    // hide the insertion mark
    HideInsertMark(ToolBar);
  }
  // otherwise, if the
  // toolbar contains buttons
  else if (ToolBar.ButtonCount > 0)
  {
    const int index =
      PtOnSeparator(ToolBar, X, Y);
    if (index >= 0)
    {
      // show an insertion mark before
      // or after the separator
      TToolButton& SepBtn =
        *ToolBar.Buttons[index];
      const bool after = X - SepBtn.Left
        > SepBtn.Width / 2;
      ShowInsertMark(
        ToolBar, SepBtn, after);
    }
    else
    {
      // show an insertion mark
      // after the last button
      TToolButton& LastBtn = *ToolBar.
        Buttons[ToolBar.ButtonCount - 1];
      ShowInsertMark(
        ToolBar, LastBtn, true);
    }
  }
  // otherwise
  else
  {
    // ToolBar contains no buttons so
    // accept drops anywhere on it
  }
}
This method is similar to the ToolBtnsDragOver() method except the Sender parameter, this time, specifies a pointer to the toolbar. That takes care of the OnDragOver event handlers. Let’s now tackle the OnDragDrop event handlers.

OnDragDrop event handlers

All tool buttons will share the same OnDragDrop event handler, ToolBtnsDragDrop(); all four toolbars will share the handler ToolBarsDragDrop(). Here’s how these two methods are defined:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void __fastcall TForm1::ToolBtnsDragDrop(
   TObject *Sender, TObject *Source,
   int X, int Y)
{
  // grab a reference to the
  // control that's being dragged
  TControl& SrcCtl =
    *static_cast<TDragTBObject*>
      (Source)->Control;
  // grab a reference to the button
  // that's being dragged over
  TToolButton& Btn =
    static_cast<TToolButton&>(*Sender);
  // grab a reference to the
  // button's parent (toolbar)
  TToolBar& ToolBar =
    static_cast<TToolBar&>(*Btn.Parent);
 
  // move/insert the button
  const bool after = X > 0.5 * Btn.Width;
  DoDrop(&ToolBar, &Btn, &SrcCtl, after);
}
 
void __fastcall TForm1::ToolBarsDragDrop(
   TObject *Sender, TObject *Source,
   int X, int Y)
{
  // grab a reference to the
  // control that's being dragged
  TControl& SrcCtl =
    *static_cast<TDragTBObject*>
      (Source)->Control;
  // grab a reference to the toolbar
  // that's being dragged over
  TToolBar& ToolBar =
    static_cast<TToolBar&>(*Sender);
 
  // if the toolbar contains buttons
  if (ToolBar.ButtonCount > 0)
  {
    // find the index of the separator
    // that's being dragged over
    const int index =
      PtOnSeparator(ToolBar, X, Y);
    if (index >= 0)
    {
      // grab a reference to the button
      // that's being dragged over
      TToolButton& SepBtn =
        *ToolBar.Buttons[index];
 
      // move/insert the source button
      const bool after = X - SepBtn.Left
        > 0.5 * SepBtn.Width;
      DoDrop(&ToolBar, &SepBtn,
        &SrcCtl, after);
    }
    else
    {
      // grab a reference to the
      // last button on the toolbar
      TToolButton& LastBtn = *ToolBar.
        Buttons[ToolBar.ButtonCount - 1];
 
      // move/insert the source button
      DoDrop(&ToolBar, &LastBtn,
        &SrcCtl, true);
    }
  }
  // otherwise
  else
  {
    // accept drops anywhere
    DoDrop(&ToolBar, NULL,
      &SrcCtl, false);
  }
}
These methods are similar to the corresponding OnDragOver event handlers, except that in this case, we actually move or insert the button instead of showing or hiding an insertion mark. This task is handled in the DoDrop() utility method, which is defined as follows:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
void __fastcall TForm1::DoDrop(
   TToolBar& ToolBar, TToolButton* Btn,
   TControl* SrcCtl, bool after)
{
  // if SrcCtl is a toolbutton
  if (dynamic_cast<TToolButton*>(SrcCtl))
  {
    SrcCtl->Parent = &ToolBar;
    if (Btn)
    {
      SrcCtl->Left = after ?
        Btn->Left + Btn->Width :
        Btn->Left;
    }
  }
  // otherwise, we're adding a new button
  else
  {
    // grab a pointer to
    // the dropped list item
    TListView& SrcListView =
      static_cast<TListView&>(*SrcCtl);
    TListItem* DragItem =
      SrcListView.Selected;
 
    // create a corresponding toolbutton
    TToolButton* NewBtn =
      new TToolButton(this);
    NewBtn->Parent = &ToolBar;
    NewBtn->DragMode = dmAutomatic;
    NewBtn->OnStartDrag =
      ToolBtnsStartDrag;
    NewBtn->OnEndDrag =
      ToolBtnsEndDrag;
    NewBtn->OnDragOver =
      ToolBtnsDragOver;
    NewBtn->OnDragDrop =
      ToolBtnsDragDrop;
    // (separator is the last image)
    if (DragItem->ImageIndex ==
        TBImageList->Count - 1)
    {
      NewBtn->Style = tbsSeparator;
      NewBtn->Width = 8;
    }
    else
    {
      NewBtn->Caption =
        DragItem->Caption;
      NewBtn->ImageIndex =
        DragItem->ImageIndex;
    }
    // position the new button
    if (Btn)
    {
      NewBtn->Left = after ?
        Btn->Left + Btn->Width :
        Btn->Left;
    }
  }
  // fix the command IDs
  ResetCommandIDs(ToolBar);
}
The DoDrop() method is designed to either move an existing button or add a new button, depending on the SrcCtl parameter. The SrcCtl specifies a pointer to the control that was dropped. If this control is a TToolButton, then we simply move it to location at which it was dropped—namely, to the right-hand side of the TToolButton that’s specified by the Btn parameter). If SrcCtl is not a TToolButton (i.e., if it’s CommandListView) then we add a new TToolButton to the toolbar, again to the right-hand side of the TToolButton specified by the Btn parameter. Note from the definition of the ToolBarsDragDrop() method that DoDrop() might be called with a NULL Btn parameter. In this case, we simply add or move the new or existing button to (0,0).

Notice that a call to another utility function, ResetCommandIDs(), is made at the end of the DoDrop() method. This function compensates for a bug in the TToolButton class, which scrambles the index-to-command-identifier assignments. Normally, all TToolButtons are assigned a command identifier that corresponds to its ordinal location within the toolbar (i.e., the same value as it’s Index property). This correspondence is needed for the Marked and Indeterminate properties. The ResetCommandIDs() function simply updates the command ID of each TToolButton to reflect its Index:
C++
1
2
3
4
5
6
7
8
9
10
void ResetCommandIDs(TToolBar& ToolBar)
{
  const HWND hToolBar = ToolBar.Handle;
  const int count = ToolBar.ButtonCount;
  for (int idx = 0; idx < count; ++idx)
  {
    SNDMSG(
      hToolBar, TB_SETCMDID, idx, idx);
  }
}
Conclusion

In this article, I’ve shown you how to add drag-and-drop customization to toolbars. Although the presented code is designed only for horizontal toolbars, it shouldn’t be difficult to modify for vertical toolbars. Also, I’ve neglected to mention how to handle the tool button’s event handlers. Users of newer versions of C++Builder can use a TActionList object; otherwise, I recommend using a single, shared handler for each event, querying, for example, the tool button’s (Sender’s) ImageIndex property to determine what action to perform.

The sample project depicted in Figure A is available for download from www.residorph.com. In addition to the code presented here, this project demonstrates how to code the specifics of the customization dialog and the toolbar popup menu.

Listing A: Declaration of the TDragTBObject class
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static const TCursor crTBDropAdd = 1;
static const TCursor crTBDropMove = 2;
static const TCursor crTBDropRemove = 3;
 
class TDragTBObject : public TDragControlObject
{
public:
  __fastcall TDragTBObject(TControl* Control)
    : TDragControlObject(Control) {}
 
protected:
  virtual TCursor __fastcall
    GetDragCursor(bool Accepted, int X, int Y)
    {
      if (Accepted)
      {
        return dynamic_cast<TToolButton*>(Control) ?
          crTBDropMove : crTBDropAdd;
      }
      return crTBDropRemove;
    }
  virtual TDragImageList* __fastcall GetDragImages()
    {
      return NULL;
    }
};
Listing B: Declaration of the TForm1 class
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <memory>
class TForm1 : public TForm
{
__published:
  TCoolBar *CoolBar1;
  TToolBar *FileToolBar;
  TToolBar *EditToolBar;
  TToolBar *FrmtToolBar;
  TToolBar *ViewToolBar;
  TImageList *TBImageList;
 
  TPopupMenu *TBPopupMenu;
  TMenuItem *FileMenuItem;
  TMenuItem *EditMenuItem;
  TMenuItem *ViewMenuItem;
  TMenuItem *FrmtMenuItem;
  TMenuItem *CustomizeMenuItem;
 
  // drag-and-drop support for regular toolbuttons
  void __fastcall ToolBtnsStartDrag(
    TObject *Sender, TDragObject *&DragObject);
  void __fastcall ToolBtnsEndDrag(
    TObject *Sender, TObject *Target, int X, int Y);
  void __fastcall ToolBtnsDragOver(
    TObject *Sender, TObject *Source,
    int X, int Y, TDragState State, bool &Accept);
  void __fastcall ToolBtnsDragDrop(
    TObject *Sender, TObject *Source, int X, int Y);
 
  // drag-and-drop support for separator toolbuttons
  void __fastcall ToolBarsMouseDown(
    TObject *Sender, TMouseButton Button,
    TShiftState Shift, int X, int Y);
  void __fastcall ToolBarsDragOver(
    TObject *Sender, TObject *Source, int X, int Y,
    TDragState State, bool &Accept);
  void __fastcall ToolBarsDragDrop(
    TObject *Sender, TObject *Source, int X, int Y);
 
  // TBPopupMenu event handlers
  void __fastcall CustomizeMenuItemClick(
    TObject *Sender);
 
private:
  std::auto_ptr<TDragTBObject>
    DragTBObject_;
 
  // toolbar utility methods
  void __fastcall CustomizeToolBar(
    TToolBar& ToolBar, bool customize);
  void __fastcall DoDrop(
    TToolBar& ToolBar, TToolButton* Btn,
    TControl* SrcCtl, bool after);
 
public:
  __fastcall TForm1(TComponent* Owner);
  void __fastcall CustomizeMode(bool customize);
};
Listing C: Declaration of the TCustomizeDlg class
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <memory>
class TCustomizeDlg : public TForm
{
__published:
  TListView *CommandListView;
private:
  std::auto_ptr<TDragTBObject>
    DragTBObject_;
public:
  virtual __fastcall TCustomizeDlg(
    TComponent* AOwner);
};
3
0 / 0 / 0
Регистрация: 30.08.2011
Сообщений: 21
03.11.2011, 16:56  [ТС] 3
Спасибо, посижу с гугл переводчиком, может че нить и пойму
0
LK
Заблокирован
03.11.2011, 17:25 4
есть еще неплохой translate.ru
А разве в Архангельского, например, по этому вопросу ничего нет ?
Помнится, во времена моей молодости как бы было .
1
0 / 0 / 0
Регистрация: 30.08.2011
Сообщений: 21
03.11.2011, 17:51  [ТС] 5
Цитата Сообщение от LK Посмотреть сообщение
А разве в Архангельского, например, по этому вопросу ничего нет ?
Я даже не знаю, что это такое
0
LK
Заблокирован
03.11.2011, 17:55 6
книга - Архангельский А.Я. Программирование в С++ Builder , есть в сети, для версий билдера 6 , 2007 , 2009 есть разные издания

учите Билдер методом научного тыка ? хороший способ, сам пользуюсь
0
0 / 0 / 0
Регистрация: 30.08.2011
Сообщений: 21
03.11.2011, 18:23  [ТС] 7
Не я книги не люблю читать, предпочитаю сам разбираться, а если че не понятно, люди на форуме помогут
0
LK
Заблокирован
03.11.2011, 18:32 8
я вам не "Войну и мир" , и даже не про Гарри Поттера предлагаю , и я с вами не согласен категорически
0
1365 / 732 / 67
Регистрация: 28.01.2011
Сообщений: 2,064
03.11.2011, 19:17 9
Цитата Сообщение от AJIEKC Посмотреть сообщение
Не я книги не люблю читать, предпочитаю сам разбираться, а если че не понятно, люди на форуме помогут
Нацисты тоже не любили книги читать, они их жгли, напомнить чем это закончилось...
да простит меня форум за офтоп, не сдержался.

1
03.11.2011, 19:17
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.11.2011, 19:17
Помогаю со студенческими работами здесь

Перемещающаяся надпись:
Разработать форму с надписью (компонент TLabel) , причем при нажатие левой (или правой) клавиши...

Перемещающаяся картинка по форме
Добрый день! Вопрос конечно из разряда глупых.. Но может подскажете, есть такая программа...

Перемещающаяся линия символов на экране!
Здравствуйте, с ассемблером я вообще не дружу, поэтому обращаюсь к вам, как к знающим людям. Прошу...

Кнопка, перемещающаяся в случайное место на экране
Здравствуйте. Мне была дана задача - сделать кнопку, которая будет перемещаться в случайную точку...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru