Maxscript + Qt close event

Maxscript + Qt close event

Anonymous
Not applicable
1,929 Views
12 Replies
Message 1 of 13

Maxscript + Qt close event

Anonymous
Not applicable

Hi,

 

I'm using code found here to load Qt UIs with maxscript:

https://forums.autodesk.com/t5/3ds-max-programming/maxscript-qt-ui/m-p/10052536/highlight/false#M268...

 

But I can't find how to trigger actions when the UI closes.

I'd like to achieve what "on rollout close" do with maxscript rollouts.

 

Thanks for your help.

0 Likes
Accepted solutions (1)
1,930 Views
12 Replies
Replies (12)
Message 2 of 13

Swordslayer
Advisor
Advisor

Override its closeEvent method:

 

(
	local py = python.import "builtins"
	local shiboken = python.import "shiboken2"
	local QtWidgets = python.import "PySide2.QtWidgets"
	local GetQMaxMainWindow = (python.import "qtmax").GetQMaxMainWindow

	if isProperty ::testDialog #close and shiboken.isValid testDialog and testDialog.isVisible() do testDialog.close()
	global testDialog = QtWidgets.QDialog(GetQMaxMainWindow())
	testDialog.mousePressEvent = fn mousePressEvent evnt = py.print (py.str.format "dialog click at {}" (evnt.pos()))
	testDialog.setWindowTitle "Pyside Qt Window"
	testDialog.setFixedSize 250 250

	testDialog.nativeCloseEvent = testDialog.closeEvent
	testDialog.closeEvent = fn customCloseEvent evnt = (py.print "custom code"; testDialog.nativeCloseEvent evnt)

	testDialog.show()
)
Message 3 of 13

Anonymous
Not applicable

Nice!! Thank you very much, I try that asap!

0 Likes
Message 4 of 13

denisT.MaxDoctor
Advisor
Advisor

@Anonymous wrote:

Nice!! Thank you very much, I try that asap!


Now you understand? How easy it works when the question is asked well and in the right place. 😉 

Message 5 of 13

Anonymous
Not applicable

Just tried to apply it to the Qt UI loading code, but doesn't work 😢

I must miss something...

here it is:

(
	local py = python.import "builtins"
	local shiboken = python.import "shiboken2"
	local QtCore = (python.import "PySide2.QtCore")
	local QFile = QtCore.QFile
	local QUiLoader = (python.import "PySide2.QtUiTools").QUiLoader
	local GetQMaxMainWindow = (python.import "qtmax").GetQMaxMainWindow
	local ui_file = QFile "test.ui"
	ui_file.open QFile.ReadOnly
	if isProperty ::testDialog #close and shiboken.isValid testDialog and testDialog.isVisible() do testDialog.close()
	testDialog = (QUiLoader()).load ui_file (GetQMaxMainWindow())
	ui_file.close()

	testDialog.nativeCloseEvent = testDialog.closeEvent
	testDialog.closeEvent = fn customCloseEvent evnt = (py.print "custom code"; testDialog.nativeCloseEvent evnt)
	testDialog.show()
)
0 Likes
Message 6 of 13

Swordslayer
Advisor
Advisor
Accepted solution

Creating the widgets via PySide2 creates QWidgetWrapper that redirects all the calls to the python method if there's one, the widgets created via QUiLoader are not wrapped, they're created by Qt not by the python wrapper, so if you want to keep everything as is, you'd have to promote and register it as a custom widget in the designer first. Or you can make a python wrapper QObject that loads the ui and installs event filter watching for close event. Alternativelly, you could make a helper class to load children from the ui file. The first method is the most straightforward, I've included the other two for completeness sake (it would work if you weren't in control of the ui file, for example).

Message 7 of 13

Anonymous
Not applicable

Ok thanks, I'll try to work on this.

Didn't expect  to be so complicated for such a simple thing 😅

0 Likes
Message 8 of 13

denisT.MaxDoctor
Advisor
Advisor

@Swordslayer wrote:

Override its closeEvent method:

testDialog.nativeCloseEvent = testDialog.closeEvent

Just noticed now. This is a great find! 😎👍

0 Likes
Message 9 of 13

Swordslayer
Advisor
Advisor

There's also a cleaner way without introducing extra variable:

 

testDialog.closeEvent = fn customCloseEvent evnt = (py.print "custom code"; QtWidgets.QDialog.closeEvent testDialog evnt)
0 Likes
Message 10 of 13

denisT.MaxDoctor
Advisor
Advisor

Do you know how to get the sender of an event? I hope there is some hidden trick that I don't know 😉

0 Likes
Message 11 of 13

denisT.MaxDoctor
Advisor
Advisor

@Swordslayer wrote:

There's also a cleaner way without introducing extra variable:

 

 

 

testDialog.nativeCloseEvent = testDialog.closeEvent

 

 

the most interesting thing here is how easily you can create a new QObject property

 

0 Likes
Message 12 of 13

Swordslayer
Advisor
Advisor

@denisT.MaxDoctor wrote:

Do you know how to get the sender of an event? I hope there is some hidden trick that I don't know 😉


Usually, I don't connect multiple signals to a single event handler but if I had to do that, I'd make the event handler receive extra sender argument and when connecting it, I'd connect it to a curried function (via functools.partial) that would carry the sender with it.

0 Likes
Message 13 of 13

denisT.MaxDoctor
Advisor
Advisor

@Swordslayer wrote:

@denisT.MaxDoctor wrote:

Do you know how to get the sender of an event? I hope there is some hidden trick that I don't know 😉


Usually, I don't connect multiple signals to a single event handler but if I had to do that, I'd make the event handler receive extra sender argument and when connecting it, I'd connect it to a curried function (via functools.partial) that would carry the sender with it.


this is what I usually do but still looking for a better solution:

 

 

 

fn onEvent event sender: = 
(
	<py>.print "... " event sender
)
(	
	qt_bt = <qt>.QPushButton()
	qt_bt.<event> = (fn __ event = onEvent event sender:qt_bt)
)

 

 

 

PS. oops... the idea seems to be correct, but there is a problem with local scope (or garbage collection(?)). As soon as I find a solution, I'll post the update.

0 Likes