返回顶部
首页 > 资讯 > 后端开发 > Python >3dsmax不同版本 pyside qt
  • 471
分享到

3dsmax不同版本 pyside qt

版本dsmaxqt 2023-01-30 22:01:48 471人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

前言: 3Dsmax 在 2014 extension 之后开始集成 python 和 PySide,但是在版本2014 extension - 2015 中,当设置 Qt UI 的父窗口为 max 主窗口的时候会报错,3dsmax20

前言:

3Dsmax 在 2014 extension 之后开始集成 python 和 PySide,但是在版本2014 extension - 2015 中,当设置 Qt UI 的父窗口为 max 主窗口的时候会报错,3dsmax2016 修复了这个bug,2017 和 2018 对 parenting qt widget to max main window 的方式都有所更新,下面来看看每个版本的具体方式。

3dsmax2014 extension - 2015:

  下面是报错的代码:(在MAXScript Listener中运行 Python.ExecuteFile @"[Path]\maxPyGui.py",[Path]改为文件的所在路径)

# -*- coding: utf-8 -*-
"""
在MAXScript Listener中运行 python.ExecuteFile @"[Path]\maxPyGui.py"
[Path]改为 maxPyGui.py 所在的路径
"""
from PySide import QtGui
from PySide import shiboken
import MaxPlus

class _GCProtector(object):
    widgets = []

app = QtGui.QApplication.instance()
if not app:
    app = QtGui.QApplication([])
    
def main():
    MaxPlus.FileManager.Reset(True)
    w = QtGui.QWidget()
    w.resize(250, 100)
    w.setWindowTitle('Window')
    _GCProtector.widgets.append(w)
    
    main_layout = QtGui.QVBoxLayout()
    label = QtGui.QLineEdit()
    main_layout.addWidget(label)

    cylinder_btn = QtGui.QPushButton("test")
    main_layout.addWidget(cylinder_btn)
    w.setLayout(main_layout)
    
    # 这是会报错的方式
    maxWinHwd = MaxPlus.Core.GetWindowHandle()
    parent = shiboken.wrapinstance(long(maxWinHwd), QtGui.QWidget)
    w.setParent(parent)#报错在这里,如果你的窗口继承了QtGui.QWidget,parent = parent 也会报错,如果想正常运行,请注释这行
    
    """Max2016的修正方式
    MaxPlus.AttachQWidgetToMax(w)
    """
    
    """不太好的方式
    hwnd = w.winId()
    import ctypes
    ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
    ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
    int_hwnd = ctypes.pythonapi.PyCObject_AsVoidPtr(hwnd)
    MaxPlus.Win32_Set3dsMaxAsParentWindow(int_hwnd)
    """
    w.show()

if __name__ == '__main__':
    main()
maxPyGui.py

注意:如果运行报错SyntaxError: encoding declaration in Unicode string (maxPyGui.py, line 0),请去掉第一行的 # -*- coding: utf-8 -*-,在命令行中运行不需要指定,下面的代码例子也一样。

  很多人建议不要 parenting qt widget to max main window ,不过还是有人尝试了很多方法,autodesk 官方 也给出了 pyqt4 的方式,链接:https://area.autodesk.com/blogs/chris/pyqt-ui-in-3ds-max-2014-extension,我使用的是pyside,所以没有验证过,也有人把这种方式改为 pyside ,有兴趣的可以试试。

一种比较理想的代替方式:

  下面是在:Https://GitHub.com/alfalfasprossen/qtinwin 上找到的代码,下载后有以下文件:

  

  在这里只关注 maxparenting.py 和 maxparenting_example.py,在MAXScript Listener中运行 python.ExecuteFile @"maxparenting_example.py",这是以owner的方式来实现的,具体描述请看代码里面的注释。

  下面附上代码:

"""This is a quite well working experiment of setting the **owner**
(not the **parent**) of the qt widget to be the 3dsMax main window.

Effectively the qt widget will behave like a natively spawned window,
with correct z-order behaviour concerning its sibling windows.
"""

import ctypes

from PySide import QtGui
from PySide import QtCore
import MaxPlus

GWL_HWNDPARENT = -8
SetWindowLongPtr = ctypes.windll.user32.SetWindowLongPtrW

class FocusFilter(QtCore.QObject):
    def eventFilter(self, obj, event):
        # TODO: fix focus filter not releasing on defocus
        MaxPlus.CUI.DisableAccelerators()
        return False

class MaxWidget(QtGui.QWidget):
    def __init__(self, title):
        super(MaxWidget, self).__init__(None)
        self.parent_hwnd = MaxPlus.Win32.GetMAXHWnd()
        self.hwnd = self.get_hwnd()
        self._parent_to_main_window()
        self.show()
        app = QtGui.QApplication.instance()
        self._focus_filter = FocusFilter()
        self.event_filter = app.installEventFilter(self._focus_filter)

    def get_hwnd(self):
        """Get the HWND window handle from this QtWidget."""
        ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
        ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
        wdgt_ptr = ctypes.pythonapi.PyCObject_AsVoidPtr(self.winId())
        return wdgt_ptr

    def _parent_to_main_window(self):
        """ Parent the widget to the 3dsMax main window.

        Technically this is NOT setting the **parent** of the window,
        but the **owner**.
        There is a huge difference, that is hardly documented in the
        win32 API.
        https://msdn.microsoft.com/en-us/library/windows/desktop/ms644898(v=vs.85).aspx  # noqa
        Setting the parent would make this a child or mdi-
        child window. Setting the owner, makes this a top-level,
        overlapped window that is controlled by the main window, but
        not confined to its client area.
        http://stackoverflow.com/questions/133122/
        """
        SetWindowLongPtr(self.hwnd, GWL_HWNDPARENT, self.parent_hwnd)

    def closeEvent(self, event):
        app = QtGui.QApplication.instance()
        app.removeEventFilter(self.event_filter)
        event.accept()
maxparenting.py
from PySide import QtGui

import maxparenting
reload(maxparenting)

class ExampleWidget(maxparenting.MaxWidget):
    """This is a test that ui interaction works correctly with a more
    or less complex ui.
    """
    def __init__(self):
        super(ExampleWidget, self).__init__("Example Widget")
        self.build_ui()
        self.connect_ui()

    def build_ui(self):
        self.setLayout(QtGui.QVBoxLayout())
        self.label = QtGui.QLabel("some label")
        self.btn = QtGui.QPushButton("button")
        self.lineedit = QtGui.QLineEdit()
        self.textedit = QtGui.QTextEdit()

        self.grp = QtGui.QGroupBox("group box grid layout")
        self.grp.setLayout(QtGui.QGridLayout())
        self.chkbx_1 = QtGui.QCheckBox("chkbx_1")
        self.chkbx_2 = QtGui.QCheckBox("chkbx_2l")
        self.chkbx_2.setDisabled(True)
        self.chkbx_3 = QtGui.QCheckBox("chkbx_2r")
        self.chkbx_4 = QtGui.QCheckBox("chkbx_3")
        self.chkbx_5 = QtGui.QCheckBox("chkbx_4")
        self.grp.layout().addWidget(self.chkbx_1, 0, 0)
        self.grp.layout().addWidget(self.chkbx_2, 1, 0)
        self.grp.layout().addWidget(self.chkbx_3, 1, 1)
        self.grp.layout().addWidget(self.chkbx_4, 2, 0)
        self.grp.layout().addWidget(self.chkbx_5, 3, 0)
        self.grp.layout().setColumnStretch(2,1)

        self.lrbox = QtGui.QHBoxLayout()
        self.lrbox.addWidget(self.textedit)
        self.lrbox.addWidget(self.grp)

        self.layout().addWidget(self.label)
        self.layout().addWidget(self.btn)
        self.layout().addWidget(self.lineedit)
        self.layout().addLayout(self.lrbox)

    def connect_ui(self):
        self.btn.clicked.connect(self.on_btn_clicked)

    def on_btn_clicked(self):
        print "btn clicked"

global qtwdgt
qtwdgt = ExampleWidget()
maxparenting_example.py

  其它.py文件有兴趣的可以自己尝试。

3dsmax2016:

  在2016中,终于做出了修正,在模块 MaxPlus 中增加了AttachQWidgetToMax(),不过这只是一种简单的指定方式,我们还是没办法获得 Max main window 的QT对象,没办法以继承 QtGui.QWidget 来指定parent,but, it's not a bid deal。

# -*- coding: utf-8 -*-
"""
在MAXScript Listener中运行 python.ExecuteFile @"[Path]\maxPyGui.py"
[Path]改为 maxPyGui.py 所在的路径
"""
from PySide import QtGui
from PySide import shiboken
import MaxPlus

class _GCProtector(object):
    widgets = []

app = QtGui.QApplication.instance()
if not app:
    app = QtGui.QApplication([])
    
def main():
    MaxPlus.FileManager.Reset(True)
    w = QtGui.QWidget()
    w.resize(250, 100)
    w.setWindowTitle('Window')
    _GCProtector.widgets.append(w)
    
    main_layout = QtGui.QVBoxLayout()
    label = QtGui.QLineEdit()
    main_layout.addWidget(label)

    cylinder_btn = QtGui.QPushButton("test")
    main_layout.addWidget(cylinder_btn)
    w.setLayout(main_layout)
    
    """这是会报错的方式
    maxWinHwd = MaxPlus.Core.GetWindowHandle()
    parent = shiboken.wrapInstance(long(maxWinHwd), QtGui.QWidget)
    w.setParent(parent)#报错在这里,如果你的窗口继承了QtGui.QWidget,parent = parent 也会报错,如果想正常运行,请注释这行
    """
    
    #Max2016的修正方式
    MaxPlus.AttachQWidgetToMax(w)
    
    """不太好的方式
    hwnd = w.winId()
    import ctypes
    ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
    ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
    int_hwnd = ctypes.pythonapi.PyCObject_AsVoidPtr(hwnd)
    MaxPlus.Win32_Set3dsMaxAsParentWindow(int_hwnd)
    """
    w.show()

if __name__ == '__main__':
    main()
maxPyGui.py

3dsmax2017:

  所以,在2017中,为了解决2016的问题,在 MaxPlus 中增加了GetQMaxWindow(),这个方法直接返回 Max main window 的 PySide.QtGui.QWidget object:

"""
在MAXScript Listener中运行 python.ExecuteFile @"[Path]\maxPyGui.py"
[Path]改为 maxPyGui.py 所在的路径
"""
from PySide import QtGui
from PySide import shiboken
import MaxPlus

class _GCProtector(object):
    widgets = []

app = QtGui.QApplication.instance()
if not app:
    app = QtGui.QApplication([])
    
def main():
    MaxPlus.FileManager.Reset(True)
    w = QtGui.QWidget()
    w.resize(250, 100)
    w.setWindowTitle('Window')
    _GCProtector.widgets.append(w)
    
    main_layout = QtGui.QVBoxLayout()
    label = QtGui.QLineEdit()
    main_layout.addWidget(label)

    cylinder_btn = QtGui.QPushButton(u"我们")
    main_layout.addWidget(cylinder_btn)
    w.setLayout(main_layout)
    
    #Max2017的改进方式
    parent = MaxPlus.GetQMaxWindow()
    w.setParent(parent)#上面返回的parent直接是PySide.QtGui.QWidget object,可以不通过wrapping,直接设置为父窗口
    
    """这是会报错的方式
    maxWinHwd = MaxPlus.Core.GetWindowHandle()
    parent = shiboken.wrapInstance(long(maxWinHwd), QtGui.QWidget)
    w.setParent(parent)#报错在这里,如果你的窗口继承了QtGui.QWidget,parent = parent 也会报错,如果想正常运行,请注释这行
    """
    
    """Max2016的修正方式
    MaxPlus.AttachQWidgetToMax(w)
    """
    
    """不太好的方式
    hwnd = w.winId()
    import ctypes
    ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
    ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
    int_hwnd = ctypes.pythonapi.PyCObject_AsVoidPtr(hwnd)
    MaxPlus.Win32_Set3dsMaxAsParentWindow(int_hwnd)
    """
    w.show()

if __name__ == '__main__':
    main()
maxPyGui.py

3dsmax2018 (PySide2):

  在2018中,去掉了 MaxPlus 中的GetQMaxWindow(),所以没办法直接获得 Max main window 的 PySide.QtGui.QWidget object,但是增加了QtHelpers 类,里面有静态方法GetQmaxMainWindow() 获得 maxMainWindow 的指针,然后我们可以通过传统方式来进行转换:

maxWinHwd = MaxPlus.QtHelpers.GetQmaxMainWindow()

parent = shiboken2.wrapInstance(long(maxWinHwd), QtGui.QWidget)

  例子代码在这里就不提供了,只是要注意的是2018开始,集成的是PySide2,所以要用shiboken2,而且 shiboken2 是在 PySide2 下的一个模块,所以导入方式为(和Maya的不一样):

from PySide2 import shiboken2

--结束END--

本文标题: 3dsmax不同版本 pyside qt

本文链接: https://lsjlt.com/news/179916.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 3dsmax不同版本 pyside qt
    前言: 3dsmax 在 2014 extension 之后开始集成 Python 和 PySide,但是在版本2014 extension - 2015 中,当设置 qt UI 的父窗口为 max 主窗口的时候会报错,3dsmax20...
    99+
    2023-01-30
    版本 dsmax qt
  • MySQL 不同版本说明
    Mysql 的官网下载地址:        http://dev.mysql.com/downloads/  ...
    99+
    2024-04-02
  • SQLPS不同版本的差异
    服务器上装了SQL Server 2014的默认实例,以及SQL Server 2017的命名实例SQL2017$env:PSModulePath为%SystemRoot%\system32\Windows...
    99+
    2024-04-02
  • 了解MySQL的不同版本
    MySQL是一种流行的开源关系型数据库管理系统,被广泛应用于网站开发、数据分析和其他数据处理任务中。MySQL有多个版本,每个版本都有其特点和优点。本文将介绍MySQL的不同版本,并给...
    99+
    2024-04-02
  • Java 不同版本的 Switch语句
    目录旧的Java Switch语句新的Switch语句Java Switch表达式的收益率结论前言: 自Java13以来,Switch表达式被添加到Java核心库中。如果您使用的是J...
    99+
    2024-04-02
  • JavaScript中有什么不同版本
    这篇文章将为大家详细讲解有关JavaScript中有什么不同版本,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。js版本有:1.0、1.1、1.2、1.3、1.4、1.5、1.6、1.7、1.8、1.8.1...
    99+
    2023-06-15
  • 快捷安装不同版本Python
    一、目的 日常测试中,为快捷在Linux系统下安装不同版本Python并安装pip。 二、脚本 #!/bin/bash #mail:xuel@anchnet.com #function:auto install python sys_ini...
    99+
    2023-01-31
    快捷 版本 Python
  • Python 2.7版本与3.6的不同
    许多Python初学者都会问:我应该学习哪个版本的Python。对于这个问题,我的回答通常是“先选择一个最适合你的Python教程,教程中使用哪个版本的Python,你就用那个版本。等学得差不多了,再来研究不同版本之间的差别...
    99+
    2023-01-31
    版本 Python
  • yum安装不同的mysql,php版本
    1.第一步就是看linu是否安装了mysql,经过rpm -qa|grep mysql查看到centos下安装mysql如果有安装就卸载以前低版本rpm -qa|grep mysqlrpm -e --nod...
    99+
    2024-04-02
  • MySQL 不同版本默认字符集
    MySQL 不同版本默认字符集   一、       MySQL 5.6 默认字符集 备注: 默认是 utf...
    99+
    2024-04-02
  • Linux环境下对不同版本python
    目前的linux发行版上,有很多安装了两个版本的python。 我的机器上默认的版本为python 2.x。且在使用easy_install安装三方库时,也默认安装到了2.x的版本上,在3.x版本下则无法import安装的库。 环境:K...
    99+
    2023-01-31
    版本 环境 Linux
  • ubuntu怎么查看qt版本
    要查看Ubuntu系统中安装的Qt版本,可以通过命令行输入以下命令来实现:1. 打开终端(Ctrl+Alt+T)。2. 输入以下命令...
    99+
    2023-10-11
    qt ubuntu
  • windows中同时安装两个不同版本的mysql
    文章目录 前言解压mysql新建所需目录及文件配置my.ini文件安装配置mysql8.0.25dll丢失错误解决问题 修改注册表启动mysql登录后修改密码总结 前言 有的时候,你是...
    99+
    2023-09-21
    mysql windows 数据库
  • JAVA JDK不同版本对JFrame的支持
        最近,一新手学习JAVA,其摸索到了JFrame,在使用中遇到了一个问题,就是JDK1.8对JFrame的set方法不完全支持。环境信息:操作系统:DELL 7470/windows 7 X86_64开发平台:M...
    99+
    2023-06-02
  • Python不同版本之间如何切换
    这篇文章主要介绍“Python不同版本之间如何切换”,在日常操作中,相信很多人在Python不同版本之间如何切换问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python不同版本之间如何切换”的疑惑有所帮助!...
    99+
    2023-07-05
  • 在不同的 go 版本中使用 ginkgo
    php小编百草为您介绍如何在不同的Go版本中使用Ginkgo。Ginkgo是一个强大的Go语言测试框架,它提供了丰富的特性和灵活的语法,使得编写和运行测试变得更加简单高效。然而,在不同...
    99+
    2024-02-09
    go语言
  • 【Windows上同时安装两个不同版本MYSQL】MySQL安装教程--5.7和8.0版本
    一、MySQL官网下载对应版本的zip文件 最新版本8.0.34下载链接:https://dev.mysql.com/downloads/mysql/ MySQL 5.7下载链接:https://d...
    99+
    2023-09-20
    windows mysql 数据库
  • Linux 中如何切换相同程序的不同版本
    几天前,我们曾经讨论如何 如何在不同的 php 版本之间进行切换 。在那篇文章中,我们使用 update-alternatives 命令实现从一个 PHP 版本切换到另一个 PHP 版本。也就是说, update-alt...
    99+
    2022-06-04
    linux 切换程序版本 linux 切换版本
  • Hybris怎么维护同一个文本基于不同语言的版本
    本篇内容主要讲解“Hybris怎么维护同一个文本基于不同语言的版本”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Hybris怎么维护同一个文本基于不同语言的版本”吧!i18n(其来源是英文单词 ...
    99+
    2023-06-04
  • Git如何查看不同版本的差异
    这篇文章主要介绍了Git如何查看不同版本的差异,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。查看不同版本的差异命令作用git diff查看不...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作