ScriptSpot

Forum topic · General Scripting

Press Radio button with Maxscript in Command Panel

By OccultArt · 2015-02-18

Description

I want to press a radio button in the command panel. Someone asked how to press a checkbox in a 3dsmax menu (I have included the link). I am trying to press a radio button in the Command Panel: Proboolean --> (sub-object Operations) --> (Remove or Copy or Inst). These settings are not exposed in maxscript unfortunately. I tried your solution for the checkbox but it does not seem to work for radio button. Can someone help me?

Link to ScriptSpot Thread: Pressing a Checkbox with maxscript

miauu solution for Checkbox:



local RollOutHandle = (windows.getChildHWND 0 "access test" )[1]
local checkHandle =(windows.getChildHWND RollOutHandle "Check")[1]
local VK_RETURN = 0x000D
local WM_SETFOCUS = 0x007
local WM_CHAR = 0x0102
UIAccessor.sendMessage checkHandle WM_SETFOCUS 0 0
windows.sendMessage checkHandle WM_CHAR VK_RETURN 0
 
Comments (14)

Can someone help me?

OccultArt · 2016-10-18

I don't know how to get this working in 3dsmax 2017. Could someone please help. I build a lot of code that is now useless in 3dsmax 2017 because I can't select Remove/Copy/Inst in the Proboolean menu.

.

miauu · 2016-10-19

This works:


(
	function SetRadiobuttonsState rbName state =
	(
		local properRb = false
		local BN_CLICKED = 0 -- clicky message ID
		local BM_SETCHECK = 241 -- checkbutton toggle message ID
		local WM_COMMAND = 273 -- windows command message
		max modify mode
		df = #max
		for child in (windows.getChildrenHWND dF)   do
		(
			for classN in (windows.getChildrenHWND child[1]) do
			(
				for btn in (windows.getChildrenHWND classN[1]) do
				(
					if btn[5] == "Extract Selected" do properRb = true
					if properRb == true and (btn[5] == rbName) do
					(
						local parent = UIAccessor.getParentWindow btn[1]
						local id = UIAccessor.getWindowResourceID btn[1]
						windows.sendMessage btn[1] BM_SETCHECK (if state then 1 else 0) 0
						windows.sendMessage parent WM_COMMAND ((bit.shift BN_CLICKED 16) + id) btn[1]
					)
				)
			)
		)
	)
 
-- the name of the radiobuttons: -- "Remove", "Copy", "Inst"
rbNamesArr = #("Remove", "Copy", "Inst")
-- first all radiobuttons have to be turned off
for rb in rbNamesArr do SetRadiobuttonsState rb false
-- turn on desired radiobutton
SetRadiobuttonsState "Copy" true
)

But it have one issue - the Remove Display Filter dialog will appear several times. Try to solve it.

OccultArt · 2016-10-19

Thanks! You are amazing :-)

When I tested it quickly I did not get a "Remove Display Filter dialog" popping up. But I still have to test more.

.

miauu · 2016-10-19

Every time I have 20-30 dialogs to close, but the radiobuttons are changed.

OccultArt · 2017-04-23

It does not work for 3dsmax 2018 (since they introduced a new interface):
"Remove/Copy/Inst Radiobuttons in a Proboolean object in the modifier pannel. These settings are not exposed in maxscript.

The problem starts with this line (there no longer is a "ModifyTask"):

This was the old working code (working up to 3DSMax 2017)

fn priv_proboolean_Extract_pressRadioButton rbName state = (
local properRb = false
local BN_CLICKED = 0 	-- clicky message ID
local BM_SETCHECK = 241 -- checkbutton toggle message ID
local WM_COMMAND = 273 -- windows command message
local panelName = if((maxVersion())[1] >= 19000) then "QWidget" else "ModifyTask"	--QWidget instead of "ModifyTask"
max modify mode
for child in (windows.getChildrenHWND #max) where child[4] == "#32770" do(
	for classN in (windows.getChildrenHWND child[1]) where (classN[4] == panelName) do( --QWidget instead of "ModifyTask"
		for btn in (windows.getChildrenHWND classN[1]) do
		(
			if btn[5] == "Extract Selected" do properRb = true
			if properRb == true and (btn[5] == rbName) do
			(
				local parent = UIAccessor.getParentWindow btn[1]
				local id = UIAccessor.getWindowResourceID btn[1]
				windows.sendMessage btn[1] BM_SETCHECK (if state then 1 else 0) 0
				If state then windows.sendMessage parent WM_COMMAND ((bit.shift BN_CLICKED 16) + id) btn[1]
				if((maxVersion())[1] >= 1900) then return OK  ))))),

Called with function:




fn pressRadioButton rbName= (
	rbNamesArr = #("Remove", "Copy", "Inst")
	for rb in rbNamesArr do (																						--	the name of the radiobuttons: -- 	"Remove", "Copy", "Inst"
		proboolean_Extract_pressRadioButton rb false )						--	first all radiobuttons have to be turned off
	proboolean_Extract_pressRadioButton rbName true ),						--	turn on desired radiobutton

Called with:



pressRadioButton "Remove"
pressRadioButton "Copy" 
pressRadioButton "Inst"

Does not work anymore in 3dsmax 2017

OccultArt · 2016-10-18

Please can anyone help? This used to work in 3dsmax 2016 to select the "Remove/Copy/Inst Radiobuttons in a Proboolean object in the modifier pannel. These settings are not exposed in maxscript.

The problem starts with this line (there no longer is a "ModifyTask"):


for classN in (windows.getChildrenHWND child[1]) where (classN[4] == "ModifyTask") do(

This was the old working code (working up to 3DSMax 2016)


fn proboolean_Extract_pressRadioButton rbName state = (
	local properRb = false
	local BN_CLICKED = 0 			-- clicky message ID
	local BM_SETCHECK = 241 		-- checkbutton toggle message ID
	local WM_COMMAND = 273 			-- windows command message
	max modify mode
	df = #max
	for child in (windows.getChildrenHWND dF) where child[4] == "#32770" do(
		for classN in (windows.getChildrenHWND child[1]) where (classN[4] == "ModifyTask") do(
			for btn in (windows.getChildrenHWND classN[1]) do
			(
				if btn[5] == "Extract Selected" do properRb = true
				if properRb == true and (btn[5] == rbName) do
				(
					local parent = UIAccessor.getParentWindow btn[1]
					local id = UIAccessor.getWindowResourceID btn[1]
					windows.sendMessage btn[1] BM_SETCHECK (if state then 1 else 0) 0
					If state then windows.sendMessage parent WM_COMMAND ((bit.shift BN_CLICKED 16) + id) btn[1] ))))),	--ADDED IF STATE THEN 2015


Called with function:




fn pressRadioButton rbName= (
	rbNamesArr = #("Remove", "Copy", "Inst")
	for rb in rbNamesArr do (																						--	the name of the radiobuttons: -- 	"Remove", "Copy", "Inst"
		proboolean_Extract_pressRadioButton rb false )						--	first all radiobuttons have to be turned off
	proboolean_Extract_pressRadioButton rbName true ),						--	turn on desired radiobutton

Called with:



pressRadioButton "Remove"
pressRadioButton "Copy" 
pressRadioButton "Inst"

Does not work anymore in 3dsmax 2017

OccultArt · 2016-10-18

Double Post

Does not work anymore in 3dsmax 2017

OccultArt · 2016-10-18

Double Post

This method works for me

Maarten · 2016-01-27

I just got this working on my example (changing a radiobutton in the '3ds import' dialog).
But it should work for other UI elements also :)


fn fn_change_3ds_rdo Exporttype =( --Main function
objname = "C:\Users\Maarten\Desktop\TEST\\box001.3ds" -- This is just a file directory to make the importer window work

dialogMonitorOPS.UnRegisterNotification id:#test -- remove any old instance
dialogMonitorOps.enabled = true -- enable the monitor
	
fn test = (
	hwnd = DialogMonitorOPS.GetWindowHandle() -- check the dialog that popped up
	 hwnd_title = UIAccessor.GetWindowText hwnd
	
		
		if (hwnd_title == "3DS Import") then ( -- INSERT WINDOW TITLE HERE
		controls= windows.getChildrenHWND hwnd -- get all controls for this dialog

		UIAccessor.Sendmessage  controls[3][1] 241 0 0 --Uncheck first radiobutton
		UIAccessor.Sendmessage  controls[4][1] 241 1 0 --Check second radiobutton
		
		)	
		
	true
)
dialogMonitorOPS.RegisterNotification test id:#test -- register the monitor
importfile objname using:importerplugin.classes[Exporttype] useNewFile:false --CREATE WINDOW HERE	
dialogMonitorOPS.UnRegisterNotification id:#test -- remove the monitor
dialogMonitorOps.enabled = false -- disable the monitor
)

fn_change_3ds_rdo 1 --Calling the function

If you want to filter out the correct controls from the controls array using wildcards (in this example I am using the wildcard "*Selected*only*" to find the 'selected only' option in the 3ds import dialog) use this piece of code:


	controls= windows.getChildrenHWND hwnd -- get all controls for this dialog

			
		for i in 1 to controls.count do (
			if matchpattern controls[i][5] pattern: "*Selected*only*" then(
				UIAccessor.SendMessage controls[i][1] BM_SETCHECK 1 0
				) 
			)

I hope this also works for you guys.
Also check out this page, I got a lot of useful info there:
http://forums.cgsociety.org/showthread.php?f=98&t=639812&page=1&pp=15&hi…

-Maarten

Attachments

Also this

Maarten · 2016-01-27

And if you want to get the correct ID's for the controls in a certain dialog use this piece of code:


	controls= windows.getChildrenHWND hwnd -- get all controls for this dialog
			
		for i in 1 to controls.count do (
			format "i: % \n Control Array: % \n" i controls[i]
				) 

it will return something like this:


i: 1 
 Control Array: #(4459714P, 5704492P, 5704492P, "Edit", "Object01", 0P, 5704492P, 790098P) 
i: 2 
--etc. until it has printed out this info for all controls in the dialog

The 'i' value is the item number of each control in the dialog, the array behind each 'i' value contains info on that control. The first item in this 'control array' is the Window Handle which is used for identification. So when I am sending a message to a certain control I am using this handle example:


print controls[4][1]
--will return the Window Handle (first array item) of the 4th control in the dialog

I do recommend using wildcards in combination with Matchpattern as the control ID's do change between differnt max versions.

-Maarten

.Net allowed?

TsveTan · 2015-03-02

Is allowable to use .Net assembies?

OccultArt · 2015-02-24

Does anyone have an idea how to get this 100% working? I really would like to be able to change the radio buttons somehow: Especially to change from Inst to Remove! Maybe it just isn't possible since Miauu did not get it to work.

Inst to Remove - DOES NOT WORK

(Copy to Inst - DOES NOT WORK)
(Copy to Remove - DOES NOT WORK)

OccultArt · 2015-02-19

I have mailed Miauu and he mailed me a script. But it does not work all the time. It will change from some radio buttons to others: Could someone think of a solution?

Remove to Inst - WORKS
Inst to Copy - WORKS
Remove to Copy - WORKS
Inst to Remove - DOES NOT WORK
Copy to Inst - DOES NOT WORK
Copy to Remove - DOES NOT WORK

Code from Miauu:

function SetRadiobuttonsState rbName state =
(
local properRb = false
local BN_CLICKED = 0 -- clicky message ID
local BM_SETCHECK = 241 -- checkbutton toggle message ID
local WM_COMMAND = 273 -- windows command message
max modify mode
df = #max
for child in (windows.getChildrenHWND dF) where child[4] == "#32770" do
(
for classN in (windows.getChildrenHWND child[1]) where (classN[4] == "ModifyTask") do
(
for btn in (windows.getChildrenHWND classN[1]) do
(
if btn[5] == "Extract Selected" do properRb = true
if properRb == true and (btn[5] == rbName) do
(
local parent = UIAccessor.getParentWindow btn[1]
local id = UIAccessor.getWindowResourceID btn[1]
windows.sendMessage btn[1] BM_SETCHECK (if state then 1 else 0) 0
windows.sendMessage parent WM_COMMAND ((bit.shift BN_CLICKED 16) + id) btn[1]
)
)
)
)
)

-- the name of the radiobuttons: -- "Remove", "Copy", "Inst"
rbNamesArr = #("Remove", "Copy", "Inst")
-- first all radiobuttons have to be turned off
for rb in rbNamesArr do SetRadiobuttonsState rb false
-- turn on desired radiobutton
SetRadiobuttonsState "Remove" true

pixamoon · 2015-02-19

Hmm, good question, It's easy to change other radio boxes like Union, Intersection etc in Parameters by simple UIAccessor.PressButton:

for c in windows.getChildrenHWND #max where c[4] == "Button" and c[5] == "Union" do UIAccessor.PressButton c[1]

or with UIAccessor.SendMessage:

for c in windows.getChildrenHWND #max where c[4] == "Button" and c[5] == "Union" do UIAccessor.SendMessage c[1] 0x007 0 0 

But it doesn't want to work with Remove/Copy/Inst... :(
Will try something more tomorrow. But maybe somebody else know the solution ?
cheers,
Pixamoon