Контекстное меню в виде объектов на форме - VB

Узнай цену своей работы

Формулировка задачи:

Привет ! Нужно создать на форме подобие контекстного меню с разделительными линиями. Чтобы каждый пункт меню был отдельным объектом, которые можно перетягивать между собой (по сути меняю местами пункты). Подскажите, что лучше взять за основу. Смотрел тему Клонирование существующего изображения (массива изображений) Собственно, если брать PictureBox нужно уметь на нем сделать надпись (изменить надпись). В качестве разделителей можно просто нарисовать на форме линии между объектами. Хотя линии тоже в идеале нужны как объекты. Нормально или какие еще варианты? Я с графикой не очень дружу. Спасибо.

Решение задачи: «Контекстное меню в виде объектов на форме»

textual
Листинг программы
  1. Option Explicit
  2.  
  3. Private Type MENUINFO
  4.    cbSize           As Long
  5.    fMask            As Long
  6.    dwStyle          As Long
  7.    cyMax            As Long
  8.    hbrBack          As Long
  9.    dwContextHelpID  As Long
  10.    dwMenuData       As Long
  11. End Type
  12.  
  13. Private Declare Function SetMenuInfo Lib "user32.dll" (ByVal hmenu As Long, ByRef MENUINFO As MENUINFO) As Long
  14. Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
  15.  
  16. Private Const WM_ENTERIDLE As Long = &H121
  17. Private Const WM_MENUSELECT As Long = &H11F
  18. Private Const WM_INITMENU As Long = &H116
  19. Private Const WM_MENUDRAG = &H123
  20. Private Const MIM_STYLE As Long = &H10
  21. Private Const MNS_DRAGDROP = &H20000000
  22. Private Const MF_MOUSESELECT As Long = &H8000&
  23. Private Const MF_HILITE As Long = &H80&
  24.  
  25. Dim WithEvents oSub As clsTrickSubclass
  26.  
  27. Private Sub Form_Load()
  28.     Dim mnu As Menu
  29.     Dim idx As Long
  30.    
  31.     ' Создание динамического меню
  32.    For idx = 0 To 10
  33.         If idx Then Load mnuItem(idx)
  34.         With mnuItem(idx)
  35.             .Visible = True
  36.             .caption = Choose(idx + 1, "Dinamic", "-", _
  37.                                        "Moveable", "-", _
  38.                                        "Menu", "-", _
  39.                                        "Move", "-", _
  40.                                        "Any", "Item", _
  41.                                        "The trick")
  42.         End With
  43.     Next
  44.    
  45.     ' Включаем сабклассинг
  46.    Set oSub = New clsTrickSubclass
  47.     oSub.Hook hwnd
  48.  
  49. End Sub
  50.  
  51. Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
  52.    
  53.     ' Показываем меню при клике правой кнопкой мыши
  54.    If Button = vbRightButton Then
  55.         PopupMenu mnuContext
  56.     End If
  57.    
  58. End Sub
  59.  
  60. Private Sub mnuItem_Click(Index As Integer)
  61.     ' Пристанавливаем сабклассинг
  62.    oSub.PauseSubclass
  63.     ' Показываем пункт
  64.    MsgBox mnuItem(Index).caption
  65.     ' Возобновляем сабклассинг
  66.    oSub.ResumeSubclass
  67. End Sub
  68.  
  69. ' Оконная процедура формы
  70. Private Sub oSub_WndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long, Ret As Long, DefCall As Boolean)
  71.     Static selMenu  As Long         ' Текущий выделенный пункт
  72.    Static isDrag   As Boolean      ' Идет ли перетаскивание
  73.    Static dragIdx  As Long         ' Перетаскиваемый пункт
  74.    
  75.     Select Case Msg
  76.    
  77.     ' При инициализации меню, инициализируем данные
  78.    Case WM_INITMENU
  79.        
  80.         Dim info    As MENUINFO
  81.        
  82.         isDrag = False
  83.         selMenu = -1
  84.         dragIdx = -1
  85.        
  86.         ' Задаем стиль перетаскиваемого меню, так мы сможем контролировать видимость меню
  87.        info.cbSize = Len(info)
  88.         info.fMask = MIM_STYLE
  89.         info.dwStyle = MNS_DRAGDROP
  90.        
  91.         ' Задаем
  92.        SetMenuInfo wParam, info
  93.    
  94.     ' При выделении очередного пункта
  95.    Case WM_MENUSELECT
  96.    
  97.         Dim flags As Long
  98.        
  99.         ' Получаем флаги
  100.        flags = wParam \ &H10000
  101.        
  102.         ' Если пунт выделен не мышкой, то значит нам не нужно
  103.        If (flags And MF_MOUSESELECT) = 0 Then DefCall = True: Exit Sub
  104.        
  105.         ' Если пункт подсвечен, то делаем его текущим
  106.        If flags And MF_HILITE Then
  107.             selMenu = wParam And &HFFFF&
  108.         Else
  109.         ' Разделители и недоступные пункты не помечаем
  110.            selMenu = -1
  111.         End If
  112.        
  113.         ' Если идет перетаскивание
  114.        If isDrag Then
  115.             ' Проверяем корректность пунктов для обмена
  116.            If selMenu > 0 And dragIdx > 0 And selMenu <> dragIdx Then
  117.                
  118.                 Dim mnu1 As Menu
  119.                 Dim mnu2 As Menu
  120.                
  121.                 ' Преобразуем индексы меню
  122.                If selMenu = 2 Then selMenu = 3
  123.                 If dragIdx = 2 Then dragIdx = 3
  124.                
  125.                 ' Получаем объекты
  126.                Set mnu1 = IndexToMenu(selMenu - 2)
  127.                 Set mnu2 = IndexToMenu(dragIdx - 2)
  128.                
  129.                 ' Обмен
  130.                Swap mnu1, mnu2
  131.  
  132.                 ' Завершаем перетаскивание
  133.                isDrag = False
  134.                 dragIdx = -1
  135.                
  136.             End If
  137.         End If
  138.    
  139.     ' Для того чтобы получить возможность отследить нажатия из формы
  140.    Case WM_ENTERIDLE
  141.    
  142.         ' Получаем состояние левой кнопки мыши
  143.        If GetKeyState(vbKeyLButton) < 0 Then
  144.             ' Нажата
  145.            ' Если нет перетаскивания и пункт корректный, то начинаем перетаскивание этого пункта
  146.            If (Not isDrag) And selMenu >= 0 Then
  147.                 isDrag = True
  148.                 dragIdx = selMenu
  149.             End If
  150.         ' Иначе отменяем перетаскивание
  151.        Else: isDrag = False
  152.         End If
  153.    
  154.     ' Возвращаем 0, чтобы не закрывалось меню при перетаскивании
  155.    Case WM_MENUDRAG
  156.        
  157.         Ret = 0
  158.         Exit Sub
  159.        
  160.     End Select
  161.    
  162.     ' Остальное нас не интересует
  163.    DefCall = True
  164.    
  165. End Sub
  166.  
  167. ' Обмен свойств пунктов меню
  168. Private Sub Swap(mnu1 As Menu, mnu2 As Menu)
  169.     Dim caption As String
  170.     Dim checked As Boolean
  171.    
  172.     caption = mnu1.caption
  173.     checked = mnu1.checked
  174.    
  175.     mnu1.caption = mnu2.caption
  176.     mnu1.checked = mnu2.checked
  177.    
  178.     mnu2.caption = caption
  179.     mnu2.checked = checked
  180. End Sub
  181.  
  182. ' Получить меню по индексу
  183. Private Function IndexToMenu(ByVal Index As Long) As Menu
  184.     Dim ctl As Object
  185.    
  186.     For Each ctl In Controls
  187.         If TypeOf ctl Is Menu Then
  188.             If Index = 0 Then Set IndexToMenu = ctl: Exit Function
  189.             Index = Index - 1
  190.         End If
  191.     Next
  192. End Function

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

12   голосов , оценка 4.333 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы