如何让Dialog窗口仅置于Maya/Motionbuilder父程序窗口之上?
解决Maya/MotionBuilder中PySide对话框全局置顶的问题
我太懂这个困扰了!在Maya或者MotionBuilder里用PySide做UI时,默认创建的对话框经常会霸道地跑到所有窗口最上层,哪怕你切到其他软件它也跟着挡视线——根本不是我们想要的“只依附宿主3D软件窗口”的效果。
问题的核心很简单:你没有把Qt对话框和宿主软件的主窗口绑定成父子关系。Qt不知道这个窗口该“归属”哪个程序,就默认给它加了全局置顶的属性。下面分软件给你具体的解决方案:
针对Maya的解决方案
首先要获取Maya的主窗口对象,然后把它作为父窗口传给你的对话框,同时避免使用全局置顶的窗口flag。
完整代码示例
from PySide import QtCore, QtGui import maya.OpenMayaUI as omui from shiboken import wrapInstance # PySide2请换成shiboken2 def get_maya_main_window(): # 拿到Maya主窗口的底层指针,转成Qt可识别的QWidget对象 main_window_ptr = omui.MQtUtil.mainWindow() return wrapInstance(long(main_window_ptr), QtGui.QWidget) class MyDialog(QtGui.QDialog): def __init__(self, parent=None): super(MyDialog, self).__init__(parent) self.setup_ui() def setup_ui(self): self.setObjectName("Dialog") self.resize(400, 300) # 这里可以添加你的自定义UI元素 self.label = QtGui.QLabel("仅在Maya窗口之上的对话框", self) self.label.setAlignment(QtCore.Qt.AlignCenter) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.label) # 关键步骤:获取Maya主窗口作为父容器 maya_main_win = get_maya_main_window() # 创建对话框时传入父窗口 dialog = MyDialog(parent=maya_main_win) # 设置窗口flags:用Dialog类型,加上标题栏,**不要加WindowStaysOnTopHint** dialog.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.WindowTitleHint) dialog.show()
针对MotionBuilder的解决方案
MotionBuilder获取主窗口的方式和Maya略有不同,需要通过pyfbsdk拿到主窗口句柄再转成Qt对象:
完整代码示例
from PySide import QtCore, QtGui import pyfbsdk from shiboken import wrapInstance # PySide2请换成shiboken2 def get_mb_main_window(): # 获取MotionBuilder主窗口的句柄,转成Qt窗口对象 mb_main_win = pyfbsdk.FBSystem().MainWindow return wrapInstance(int(mb_main_win.Handle), QtGui.QWidget) class MyDialog(QtGui.QDialog): def __init__(self, parent=None): super(MyDialog, self).__init__(parent) self.setup_ui() def setup_ui(self): self.setObjectName("Dialog") self.resize(400, 300) self.label = QtGui.QLabel("仅在MotionBuilder窗口之上的对话框", self) self.label.setAlignment(QtCore.Qt.AlignCenter) layout = QtGui.QVBoxLayout(self) layout.addWidget(self.label) # 获取MotionBuilder主窗口作为父容器 mb_main_win = get_mb_main_window() dialog = MyDialog(parent=mb_main_win) dialog.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.WindowTitleHint) dialog.show()
重要注意事项
- PySide版本适配:如果你的软件用的是PySide2(比如Maya 2020及以后版本),需要把
QtGui换成QtWidgets,shiboken换成shiboken2,代码结构不变。 - 禁止全局置顶flag:绝对不要设置
QtCore.Qt.WindowStaysOnTopHint,这个flag就是让窗口全局置顶的元凶。 - 父窗口必须在创建时传入:最好在对话框初始化时就把父窗口传进去,而不是之后用
setParent(),这样Qt能更稳定地处理窗口层级。
这样修改后,你的对话框就只会依附在Maya/MotionBuilder的主窗口之上,切到其他软件时它会被隐藏,完全符合你的需求!
内容的提问来源于stack exchange,提问作者Zak44




