Тема: Очень медленно добавляется (Add) новый пункт к контекстному меню

Написал обработчик события AcadDocument_BeginShortcutMenuDefault, он добавляет 9 новых пунктов в контекстное меню перед тем, как оно разворачивается по правому клику мыши (они потом удаляются по событию AcadDocument_EndShortcutMenu). Так вот после правого клика проходит около полутора секунд, пока меню появится. Ето есть очень нехорошо. На Лиспе то же самое. Кто работал с добавлением пунктов в меню, откликнитесь!!!

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

Чё, никто в меню не добавлял пункты динамически ?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

На Лиспе добавлял через квадратные скобки два десятка пунктов для функции ввода getkword (добавка происходит и в комстроку и в контекстное меню сразу) - никаких тормозов не заметил. Или это не совсем та тема?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> VK
Давайте проведём тест. Добавим в контекстное меню 10 пунктов и сразу сотрём их, и так N раз. (Число N задаётся в самой первой строке нижеприведённого листинга). Уже при N=1 наблюдается ощутимая задержка, не говоря уже о N=5 и т.д. Вот листинг:

(setq N 3) ;-- Здесь ставим число повторов теста
(setq
  def_menu_obj ;-- Глобальная переменная, содержит объект-контекстное меню по умолчанию
  (vla-item
    (vla-get-menus
      (vla-item
        (vla-get-menugroups
          (vlax-get-acad-object)
        )
        "ACAD"
      )
    )
    "Context menu for default mode" ;-- Для английской версии, впрочем, пиратские "локализации"
                                    ;-- наверняка содержат ту же сигнатуру в файле acad.mns
  )
)
(defun add_menu_item (i / ) ;-- Параметр i нужен для уникальности названия добавляемого пункта меню
  (vlax-invoke-method
    def_menu_obj ;-- Используется глобальная переменная
    "AddMenuItem"
    (vlax-make-variant 0) ;-- Добавляем всегда в начало меню
    (vlax-make-variant (strcat "Команда ? " (itoa i))) ;-- Названия пунктов меню должны быть уникальными
    (vlax-make-variant "(alert \"Good Day!\") ") ;-- Почему бы и нет :)
  )
)
(defun del_menu_item ( / )
  (vlax-invoke-method
    (vla-item
      def_menu_obj ;-- Используется глобальная переменная
      0 ;-- Удаляем самый первый пункт меню
    )
    "Delete"
  )
)
;-- А теперь, собственно, тестируем быстродействие:
(repeat N
  (setq i 0)
  (repeat 10
    (add_menu_item (setq i (1+ i))) ;-- Добавляем 10 новых пунктов в котекстное меню
  )
  (repeat 10
    (del_menu_item) ;-- И сразу их удаляем
  )
)

Поделитесь, пожалуйста, как вам удалось избежать тормозов.

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

Мдяяя... getkword для default mode не годится...
А не проще MNS переписать?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> VK
Проще переписать акад (шутка).
> ALL
Никому не интересно ?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

VK пишет:

А не проще MNS переписать?

Я неправильно понял этот совет (только сейчас дошло:). Я подумал, что речь идёт про компилированный бинарный файл ACAD.MNC, а не про исходный текстовый ACAD.MNS, потому и написал "проще переписать Акад":)
Что касается файла MNS, то поправить его легко, но не нужно, потому что после этого придётся его загружать командой MENULOAD, что занимает немалое время и совершенно неприемлемо.
И вообще, править здоровенный текстовый файл, который ещё потом нужно компилить, каждый раз, когда надо изменить контекстное меню - это дикость. Зачем тогда объектная модель ?
Проблема в том, что через объекты всё получается очень тормозно, хоть лиспом, хоть басиком. ARX не пробовал, но полагаю, там то же самое, потому что там идентичный с Visual Lisp'om набор событий. Вот об этом и речь.

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Maxim T
А уточните, пожалуйста, "басик" у вас это VB или VBA?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Leonid
VBA, конечно. У меня встречный вопрос, не по теме (сорри админу) - а как на VB (или на VBA, VBscript) можно обработать событие ДРУГОГО приложения (например, Екселя), возможно ли это ? Ну например, я хочу в акадовском VBA-проекте обрабатывать вызов Екселевского контекстного меню, при этом в ЕКселе не хочу писать ни строчки.

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

Возвращаясь к теме: а что, разве на VB (не VBA) будет работать быстро ? :)))

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Maxim T
Я спросил потому, что у меня была подобная проблема: приложение написанное на VB довольно медленно обрабатывало масссив ACAD-овских объектов. Помог как раз переход на VBA, быстродействие повысилось примерно на два порядка. Но если у вас тормозит на VBA ?... Может быть где-то в цепочке объектной модели использовано лишнее звено?Лишний посредник?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Leonid
Какой посредник ?! Я могу выложить код на VBA, но он очевиден... Вот тут https://www.caduser.ru/forum/topic13576.html я создал ветку для спецов по ARX, но они молчат, наверное, лень проверять. А сам я на ARX не могу проверить, у меня разные версии ARX и сишки.

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Maxim T
Понимаю, что был не очень конкретен в предыдущем посте, но вот тестовая процедура добавляющая те же 9 пунктов, и работающая без всяких задержек месячных(шутка):

Public Sub MenuAdd(ShortcutMenu As IAcadPopupMenu)
    Dim currMenuGroup As AcadMenuGroup
    Set currMenuGroup = ThisDrawing.Application.MenuGroups.Item(0)
    ' Create the new menu
    Dim newMenu As AcadPopupMenu
    Dim MenuName As String
    ' Add a menu item to the new menu
    Dim newMenuItem As AcadPopupMenuItem
    Dim MacroName As String
    Dim MenuLabel As String
    Dim i As Integer
    ' Assign the macro string the VB equivalent of "ESC ESC _open "
    MacroName = Chr(3) & Chr(3) & Chr(95) & "Test_Item" & Chr(32)
    For i = 3 To 12
         MenuName = "TestMenu" & i
         Set newMenu = currMenuGroup.Menus.Add(MenuName)
         MenuLabel = "Test_Item" & i
         Set newMenuItem = ShortcutMenu.AddMenuItem(newMenu.Count + 1, MenuLabel, MacroName)
          'Display the menu on the menu bar
         newMenu.InsertInMenuBar (ThisDrawing.Application.MenuBar.Count + 1)
    Next i
End Sub

Теперь бы их еще и убрать...

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

Последний кусок, конечно,  лишний) остался от стандартного примера:

 'Display the menu on the menu bar
         newMenu.InsertInMenuBar (ThisDrawing.Application.MenuBar.Count + 1)

Так что, непонятно, в чем проблема?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Leonid
Спасибо за "болванку" кода:), самому писать с нуля было лень (шутка).
Нет задержек, потому что у вас добавление 10 (а не 9, кстати) пунктов меню исполняется только 1 раз, и кажется, что всё происходит быстро.
А вот если повторить его хотя бы 5 раз (цикл по j в нижеприведённом листинге), то тормозит ещё как, вот попробуйте-ка:

Public Sub MenuAddBad()
    Dim currMenuGroup As AcadMenuGroup
    Set currMenuGroup = ThisDrawing.Application.MenuGroups.Item(0)
    Dim ShortcutMenu As IAcadPopupMenu
    Set ShortcutMenu = currMenuGroup.Menus("Context menu for default mode")
    ' Create the new menu
    Dim newMenu As AcadPopupMenu
    Dim MenuName As String
    ' Add a menu item to the new menu
    Dim newMenuItem As AcadPopupMenuItem
    Dim MacroName As String
    Dim MenuLabel As String
    Dim i As Integer, j As Integer
    ' Assign the macro string the VB equivalent of "ESC ESC _open "
    MacroName = Chr(3) & Chr(3) & Chr(95) & "Test_Item" & Chr(32)
    For j = 1 To 5
      For i = 1 To 10
         'MenuName = "TestMenu" & i
         'Set newMenu = currMenuGroup.Menus.Add(MenuName)
         MenuLabel = "Test_Item" & i
         Set newMenuItem = ShortcutMenu.AddMenuItem(i, MenuLabel, MacroName)
      Next i
      For i = 1 To 10
        ShortcutMenu.Item(1).Delete 'удаляем добавленные пункты
      Next i
    Next j   'и так 5 раз
End Sub

Как видите, я немного изменил ваш код, а именно:
1. Вычисляю объект "контекстное меню" в теле процедуры (4-я строка кода), а не передаю его извне, как у вас;
2. Я закомментировал совершенно ненужную (и даже лишнюю) строку Set newMenu = currMenuGroup.Menus.Add(MenuName), находящуюся в цикле добавления пунктов, и соответственно парой строк ниже поставил вместо newMenu.Count + 1 просто i (также, границы цикла по i я изменил с 3..12 на 1..10 из чисто эстетских соображений:) ).
3. Добавил удаление 10ти новых пунктов, иначе нельзя прогонять по j более одного раза, это очевидно.
По-моему, эти изменения абсолютно непринципиальны (п.1) и даже увеличивают быстродействие (п.2). Насчёт п.3 - он, конечно, отнимает некоторое время, но уж поверьте, тот мой код, с которого всё обсуждение началось, тормозил и БЕЗ delete. Тормозил ненамного, около 1 секунды (как и ваше творение:), кстати), но этого оказалось достаточно, чтобы разъярённые пользователи закидали меня клавиатурами (шутка).
Что скажете ?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

"А напоследок я скажу -" проблема с задержкой при динамическом добавлении пунктов в меню высосана из пальца.
Приведенный мною код(котрый представляет собой немного "подкрученный" стандартный пример) добавляет 10 пунктов в течение 0,23375
сек. Эта задержка вполне допустима, т.к. на глаз она незаметна. Конечно, если гонять циклы перед там как показать несчастному пользователю меню, то можно  создать искусственную паузу любого размера. Но это уже не из области программирования, а из  садизма, фрейдизма и т.п.
Короче говоря, Максим, ты решаешь практическую проблему, или это чисто академический интерес?

Re: Очень медленно добавляется (Add) новый пункт к контекстному меню

> Leonid
Конечно, практическую проблему!
У меня лежит готовая прога, которую я не могу выпустить "в свет" из-за этой "вполне допустимой", как вы считаете, задержки. Про разъярённых юзеров я написал не ради красного словца, это реальность. Этот код (не зацикленный, конечно:)) вызывается в моей проге при каждом вызове контекстного меню, и даже такая небольшая задержка вызывает раздражение пользователя, тем более что работает он на весьма быстрой машине и всё остальное не тормозит. Я сам тестировал (ессессно) и согласен с ними. Конечно, если уменьшить число добавляемых пунктов эдак до трёх, задержка уменьшится, хотя я и не пробовал, потому что тогда пропадает смысл в проге. Буду пробовать на ARX, но подозреваю, что будет то же самое, потому что там с визуал лиспом совершенно идентичный набор событий.