Управление элементами интерфейса 3dsMax.UIAccessor

Когда в справке MaxScript нет методов управления какими-то элементами интерфейса 3dsMax, а MaxScript Listener ничего не показывает при нажатии на какой нибудь чекбокс или кнопочку и при этом есть жгучее желание скриптово управлять нужным элементом интерфейса, есть способ:

Из MaxScriptHelp

 

<bool>UIAccessor.SendMessage <HWND>hwndDlg <integer>MessageID <integer>wParam <integer>lParam

 

<bool>--Возвращаемое значение

UIAccessor.SendMessage --метод

<HWND>hwndDlg -- дескриптор (уникальный идентификатор) элемента UI (Пользовательского Интерфейса (User Interface))

<integer>wParam -- дополнительный параметр (0 или 1) 1-включить 0-выключить

<integer>lParam -- дополнительный параметр (0 или 1) 1-включить 0-выключить

 

/*

К примеру нажмём кнопочку Attach для объекта Editable_Poly.

Тестовой сценой будет Editable_Poly объект, режим панели Modify

*/

handleAttach --обявляем переменную, в которой будет дескриптор нужного элемента

child_HWND = for c in windows.getChildrenHWND #max where c[4] == "ModifyTask" do exit with c[1] /*Получаем дескриптор нужной группы инструментов "ModifyTask"
Если из всех массивов дескрипторов найдётся слово "ModifyTask", то переменной child_HWND присвоится значение первого элемента того массива, в котором нашлось это слово "ModifyTask"
Это значит в переменной child_HWND будет находиться дескриптор группы инструментов "ModifyTask"*/

archild_HWND=windows.getChildrenHWND child_HWND -- здесь получим массив дескрипторов группы инструментов "ModifyTask"
for i=1 to archild_HWND.count do
if archild_HWND[i][5]=="Attach" do handleAttach=archild_HWND[i][1]
/*Если в массиве archild_HWND есть слово "Attach", присваиваем переменной handleAttach тот самый нужный дескриптор кнопочки "Attach"*/
UIAccessor.PressButton handleAttach -- нажимаем:)

 

/*

Механизм управления элементами UI устроен через посылание сообщений этим элементам функцией UIAccessor.SendMessage или windows.sendMessage

В этом блоке поиски воздействия на кнопку с помощью сообщений (для кнопки работает каряво, но в целях изучения тоже полезно)

WM_LBUTTONDOWN = 513 -- это код низкоуровневого сообщения

ссылка: https://fossies.org/linux/fpcbuild/fpcsrc/rtl/wince/wininc/messages.inc

UIAccessor.SendMessage handleAttach 0x06bc 0x19 1 -- что то делает с кнопкой, что она не просто нажимается, но ещё и становится действующей

UIAccessor.SendMessage handleAttach WM_LBUTTONDOWN 1 0 -- нажатие кнопки (эта строка срабатывает отдельно, весь код почему то не нажимает кнопку)

--UIAccessor.SendMessage handleAttach 0x06bc 0x18 1 -- Set

--UIAccessor.SendMessage handleAttach 0x06bc 0x18 0 -- Unset

Эксперименты с перебором сообщений

UIAccessor.SendMessage handleAttach <код сообщения> 1 0

16 -- скрытие кнопки

77 -- почему то вызывается Web help MaxScript

78, 275 -- Вылет макса (краш)

130 -- Кнопка блокируется

*/

 

/*

Connect Copy (Включаем/выключаем чекбокс)

Тестовой сценой будет

построенный сплайн,

переведённый в Editable Spline

в режиме панели Modify,

Включён подобъект 2 или 3

*/

global handleConnect --объявляем переменную, в которой будет дескриптор нужного элемента
BM_CLICK=245 -- сообщение клика мыши
BM_GETCHECK=240 -- получить состояние чекбокса
--BM_SETCHECK=241 /* включить чекбокс, но это сообщение работает только

для кнопки получаем дескриптор группы инструментов "Geometry"

визуально включая чекбокс, без результата (функции не работают)*/


child_HWND=for h in windows.getChildrenHWND #max where h[5]=="Geometry" do exit with h[2] -- аналогично как
archild_HWND=windows.getChildrenHWND child_HWND /*Получаем массив массивов дескрипторов инструментов, входящих в группу инструментов "Geometry"*/
for i=1 to archild_HWND.count where archild_HWND[i][5]=="Connect Copy" do handleConnect=archild_HWND[i+1] -- Получаем дескриптор чекбокса.
 
currentState = windows.sendMessage handleConnect[1] BM_GETCHECK 0 0 --Проверка состояния чекбокса
/*Хоть UIAccessor.SendMessage и windows.sendMessage по действию схожи, получают одни и те же параметры, но во первых эти методы возвращают разные значения в листинге,
а в данном случае для проверки состояния чекбокса работает только windows.sendMessage
Поэтому стоит экспериментировать проверять работу с сообщениями для обоих методов*/

case currentState of
(
0: UIAccessor.SendMessage handleConnect[1] BM_CLICK 1 0 -- Включение
1: UIAccessor.SendMessage handleConnect[1] BM_CLICK 1 0 -- Выключение
)

 

-- Другой способ заставить работать чекбокс
BM_SETCHECK= 241
WM_COMMAND=273
state=1
(
UIAccessor.SendMessage handleConnect[1] BM_SETCHECK state 0
PAR = UIAccessor.getParentWindow handleConnect[1]
_ID = UIAccessor.getWindowResourceID handleConnect[1]
UIAccessor.SendMessage PAR WM_COMMAND _ID handleConnect[1] /* активируется команда выполнения кнопки*/

 

global handleUSoftSel
BM_CLICK = 245
BM_GETCHECK=240
--BM_SETCHECK=241
child_HWND=for h in windows.getChildrenHWND #max where h[5]=="Soft Selection" do exit with h[2]
archild_HWND=windows.getChildrenHWND child_HWND
for i=1 to archild_HWND.count where archild_HWND[i][5]=="Use Soft Selection" do handleUSoftSel=archild_HWND[i]
 
currentState = windows.sendMessage handleUSoftSel[1] BM_GETCHECK 0 0
case currentState of
(
0: UIAccessor.SendMessage handleUSoftSel[1] BM_CLICK 1 0
1: UIAccessor.SendMessage handleUSoftSel[1] BM_CLICK 1 0
)
 
Для переключения radiobuttons работает так же сообщение BM_CLICK = 245

 

Ссылочки:

http://www.3dcenter.ru/forum/index.php?act=Print&client=printer&f=58&t=108064

https://fossies.org/linux/fpcbuild/fpcsrc/rtl/wince/wininc/messages.inc

http://forums.cgsociety.org/archive/index.php?t-1206693.html

http://www.scriptspot.com/forums/3ds-max/general-scripting/press-radio-button-with-maxscript-in-command-panel

_______________________________________________________________

Делаем окно роллаута “поверх определённого окна”

Проблема такая: если создать окно роллаута в режиме работы, например, UVEditor-а, то когда начинаешь тыкать инструменты самого эдитора, - наш роллаут перекрывается и становится не виден. Чтобы такого не происходило, при создании диалога (функция CreateDialog) надо указать дескриптор окна-родителя для этого нашего окошка-роллаута. В результате получим наше окошко всегда над определённым окном. Более того, если закрыть родительское окно, то наш диалог тоже закроется!

Вот пример:

 

gco=modpanel.getcurrentObject() -- переменная gco будет содержать в себе объект панели модификаторов.

global Roll_uvE_child, HWND_uvE -- создаём голобальные переменные, чтобы их можно было бы вызвать в любом месте скрипта (это переменная самого нашего роллаута и переменная дескриптора (идентификатора) окна-родителя (для нас это окно-родитель будет окно редактора UVEdit))

WindowHandle = DialogMonitorOPS.GetWindowHandle() -- производим захват всех дескрипторов окон

ChildWindows = UIAccessor.GetChildWindows WindowHandle -- здесь получаем массив всех дескрипторов дочерних окон всех вызванных окон, подавая на функцию UIAccessor.GetChildWindows переменную WindowHandle

 

for i in ChildWindows where (classof i) == Integer do -- если класс каждого элемента i есть целое число, то делать

if (ClassOf (UIAccessor.GetWindowText i)) == String do -- если класс полученного текста из дескриптора есть текстовый тип данных String, то делать… На этом этапе дескриптор окна расшифровывается в понятный нам текст и отфильтровывается от других типов данных.

if (findString (UIAccessor.GetWindowText i) "Edit UVWs")!= undefined do HWND_uvE=i -- если полученный текст (UIAccessor.GetWindowText), из дескриптора i-того элемента массива ChildWindows есть "Edit UVWs" (это титульное название окна UV-редактора) и результаты этих нахождений этой строки с названием не есть undefined, а результат есть и существует, тогда присвоить переменной HWND_uvE значение i, это значение i - как раз элемент массива ChildWindows, он же и есть искомый дескриптор окна UVEdit

           

rollout Roll_uvE_child "" width:130 height:20 -- тестовый роллаут

(

slider sld1 "" range:[1,100,30] pos:[1,-10] width:137 height:25 type:#integer

)

if classof gco == Unwrap_UVW -- если класс объекта панели modify есть Unwrap_UVW, то

then (

try DestroyDialog Roll_uvE_child catch()

CreateDialog Roll_uvE_child pos: [900,230] parent: HWND_uvE

)

пробовать закрыть диалог роллаута если он открыт; Создать диалогу роллаута в такой то позиции и задать окно-родителя через найденный выше дескриптор (parent: HWND_uvE)

 

Вот тоже самое, но оптимизировано:
ChildWindows = UIAccessor.GetChildWindows (DialogMonitorOPS.GetWindowHandle())

--for i in ChildWindows do format "%\n" (UIAccessor.GetWindowText i)

for i in ChildWindows where (UIAccessor.GetWindowText i)=="Edit UVWs" do exit with HWND_uvE=i

_______________________________________________________________

















































Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: