You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让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()

重要注意事项

  1. PySide版本适配:如果你的软件用的是PySide2(比如Maya 2020及以后版本),需要把QtGui换成QtWidgetsshiboken换成shiboken2,代码结构不变。
  2. 禁止全局置顶flag:绝对不要设置QtCore.Qt.WindowStaysOnTopHint,这个flag就是让窗口全局置顶的元凶。
  3. 父窗口必须在创建时传入:最好在对话框初始化时就把父窗口传进去,而不是之后用setParent(),这样Qt能更稳定地处理窗口层级。

这样修改后,你的对话框就只会依附在Maya/MotionBuilder的主窗口之上,切到其他软件时它会被隐藏,完全符合你的需求!

内容的提问来源于stack exchange,提问作者Zak44

火山引擎 最新活动