Страницы: 1
RSS
Как запретить выделение Shape?, отследить выделение Shape на листе
 
Доброе время суток.
Пытаюсь запретить пользователю выделять Shape на листе, например так:
Код
If Not TypeOf Selection Is Range Then ActiveWindow.RangeSelection.Activate
или так (для конкретного Shape):
Код
If TypeOf Selection Is Oval Then ActiveWindow.RangeSelection.Activate
Но как понять, что пользователь выбрал не Range, а объект на листе? Worksheet_SelectionChange на это не реагирует. Но как-то ведь реагирует лента, появляется в ней новый раздел, и т.п.
Есть ли возможность отследить событие выбора объекта при помощи VBA?

PS Я так понимаю, что есть вариант запрета выбора объекта через защиту листа, но это не подходит по ряду причин
F1 творит чудеса
 
Назначить фигуре пустой макрос (?).
 
неожиданно... спасибо, как-то мне в голову не пришло. Но от правой мыши не защищает, увы...
F1 творит чудеса
 
Цитата
как понять, что пользователь выбрал не Range, а объект на листе?
Вариант от  ZVI
 
Спасибо, посмотрю завтра
F1 творит чудеса
 
Добрый день, Максим. Событий таких в VBA, к сожалению, нет.
Вместо цикла с DoEvents менее затратно использовать API-таймер.  
Когда-то давно здесь был вопрос по проверке состояния буфера обмена - есть в нем что-то или нет.
По таймеру запускалась проверка каждые 0.2 секунды, что не затратно для процессора.
Тема та исчезла после сбоя форума, вместо неё в архиве сейчас другая, но файл у меня остался - приложил.
Аналогично можно сделать проверку типа selection
Изменено: ZVI - 21.08.2014 03:10:44
 
Владимир, спасибо большое!
Жаль, что такого события не нашлось, конечно )) теплилась надежда, что какие-то косвенные признаки могут указывать, но, по идее, проверка этих признаков это была бы та же проверка, что и проверка "что выбрано" по таймеру.

Еще раз спасибо, буду изучать-разбираться
F1 творит чудеса
 
Если разговор именно про выделение, то можно посмотреть ещё один вариант от ZVI (#8)
 
Посмотрел предложенные варианты. С координатами мышки, конечно, магия  :)  
С таймером пока не разобрался, так как кнопочки не появляются, и приходится разбирать код, особенно грустно мне в описаниях функции в WinAPI - я и слов-то таких не знаю, как hwnd, не говоря уже о более сложных. В связи с этим вопрос: вот в этой строчке
Код
TimerID = SetTimer(0&, 0&, 200&, AddressOf MyCycle)
200 - это милисекунды, AddressOf MyCycle - передача адреса процедуры MyCycle а DLL по истечении таймера, это я понял. A первые два 0 - имеет смысл о них думать, или просто оставить нулями и не заморачиваться? Что они делают вообще?
Пока всё, что удалось усвоить, это то, что первый параметр - дескриптор окна (он всегда 0 для окна, которое его запустило?), чтобы это ни значило, а второй - идентификатор таймера.
И если первый - 0, и второй - 0, то результатом выполнения функции SetTimer будет запуск процедуры MyCycle и перезапуск таймера? А перезапуск таймера будет сразу, или после завершения вызванной процедуры?

Вариант с картинкой крут, но тут же возникает другой - т.е., для того, чтобы запретить выделение объекта типа Shape его нужно добавлять как объект ActiveX Image, т.е. заранее созданную картинку, так?

Второй вопрос, наверное, в эту же тему, к сообщению 2: как назначить созданному в процессе выполнения макроса объекту какой-то макрос? Т.е., например, я создаю кодом Shape, и хочу чтобы на него повесился макрос какой-то, хоть пустой. Есть какой-то приемчик для этого?
Хочу перепробовать разные варианты, чтобы понять, какой мне больше подходит.
F1 творит чудеса
 
Цитата
я создаю кодом Shape, и хочу чтобы на него повесился макрос какой-то
одну строку добавить в код
Код
with sha ' где sha - объект (автофигура)
   ' ...
  .OnAction = "НазваниеМакроса"
end with
 
спасибо! блин, стыдно, пять раз на той неделе видел похожие строки, но вот выскочило, и всё
F1 творит чудеса
 
Помогите плз разобраться с таймером.. Сделал книгу, в ней несколько Shape, и Label с указанием типа выделенного элемента. Ручками работает нормально.

Прикрутил таймер (образец процедуры потащил на сайте microsoft), также посмотрел код ZVI.
Но таймер обрабатываться не хочет - ругается на строчку
Код
lngTimerID = SetTimer(0&, 0&, 200&, AddressOf CountMe) 
выделяя AddressOf CountMe и  утверждая, что там "Type mismatch"
Вроде бы я в декларации PtrSafe прописал, на объявление функции больше не ругается.
Что не так? Чего ей надо, как мне эту процедуру правильно запустить таймером?
F1 творит чудеса
 
Максим, попробуйте такое декларирование API функций для всех версий Excel:
Код
#If VBA7 Then
  Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hWnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
  Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
  Private Declare PtrSafe Function CountClipboardFormats Lib "user32" () As Long
#Else
  Private Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
  Private Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
  Private Declare Function CountClipboardFormats Lib "user32" () As Long
#End If
Dim TimerID As Variant 
Обращаю внимание на то, что  TimerID As Variant
Изменено: ZVI - 26.08.2014 14:27:25
 
Таймер без WinAPI-функций и Application.OnTime:
http://excelvba.ru/code/timer/htmlfile
 
Владимир, спасибо! Вижу различия - для 64 LongPtr вместо Long, потому и ругалось.

Игорь, спасибо, посмотрю обязательно
Изменено: Максим Зеленский - 23.08.2014 20:36:32
F1 творит чудеса
Страницы: 1
Наверх