我使用 pyside 时遇到了相当令人沮丧的问题,我欢迎任何建议。
首先,某些背景
我使用 Qt Designer 创建了一个简单的GUI,我在我的pyside-uic.exe
文件中使用了.ui
来生成关联的< strong> Python 文件。
我正在使用 Python 3.3 和 pyside 1.2.1 与 Qt Designer 4 ( Qt 4.8.5 )。
我使用以下代码启动我的GUI:
class my_dialog(QMainWindow, my_gui.Ui_main_window):
def __init__(self, parent=None):
super(my_dialog, self).__init__(parent)
self.setupUi(self)
if ("__main__" == name):
app = QApplication(sys.argv)
main_dialog = my_dialog()
# (1)
main_dialog.show()
sys.exit(app.exec_())
我想要实现的目标
我的GUI有几个标签。选项卡的数量未预先确定,并在运行时进行评估。因此,我决定在 Qt Designer 中创建一个标签,以用作模板。
我第一次需要添加标签时,我会修改此模板,如果我需要任何附加标签,我计划 制作该标签的副本 然后 适当地修改该副本 。
我遇到的问题
我的问题是我似乎找不到复制标签小部件的方法。经过一些研究,我认为copy
模块(或pickle
模块,请参阅编辑)可能会解决问题(以下代码插入 (1) ):
new_tab = copy.deepcopy(main_dialog.my_tab)
main_dialog.my_tabs.addTab(new_tab, "")
但是这引发了以下错误:
main_dialog.my_tabs.addTab(new_tab, "")
RuntimeError:已删除内部C ++对象(Pyside.QtGui.QWidget)
我自己能找到什么
我在SO和其他网站上看到,当使用 pyside 时,可能会出现问题,因为中没有对它们的引用的Python
然而,事实仍然是,即使我将此代码移至 pyside 生成的setupUi()
文件中的.py
方法,我仍然得到完全相同的错误。
值得注意的是,我能够毫无困难地访问my_tab
对象来修改其内容。
我可以在代码中从头开始创建另一个标签,main_dialog.my_tabs.addTab(new_tab, "")
在这种情况下完全正常。
经过一些实验,我意识到问题可能发生在my_tab
对象的副本上。实际上,复制我刚刚创建的选项卡对象,我可以看到尝试将副本添加到GUI选项卡也失败了,并且出现了同样的错误。
看起来副本以某种方式失败,或者由于某种原因立即删除了对象。无论如何,这就是我所推断的......
我的问题
考虑到这一切,我想找到一种方法,要么成功进行对象复制,找到另一种方法来使用现有的 pyside 对象作为其他类似的模板对象。
当然可以从生成的文件中获取选项卡的代码,并编写自己的addTab()
方法。但是,我希望从现有的.ui
文件构建并避免使用硬编码GUI元素。
修改
使用pickle
时:
new_tab = pickle.loads(pickle.dumps(main_dialog.my_tab, -1))
我收到以下错误:
new_tab = pickle.loads(pickle.dumps(main_dialog.my_tab, -1))
_pickle.PicklingError:无法挑选&lt; class&#39; Pyside.QtCore.SignalInstance&#39;&gt;:属性查找Pyside.QtCore.SignalInstance失败。
答案 0 :(得分:1)
经过一些研究,我认为使用其中一种技术复制一个pyside对象是不可能的。
首先要注意的是there is no built-in function to clone a Qt widget,因此应使用copy
,pickle
或marshal
等模块进行克隆。
使用pickle
或marshal
失败,因为发现该对象不可摘。
虽然copy.copy
或copy.deeepcopy
不会引发任何警告/异常/错误,但副本不会发生,或者由于某种原因在之后被删除。
尝试将deepcopy
作为参数传递给addTab
时,不会抛出任何警告/异常/错误,但程序会在该行停止并退回到Python命令提示符。在退出之前在该行上花费几秒钟的事实使我假设deepcopy
尝试浏览对象属性并在某些时候失败。对copy
执行相同操作会导致问题中提到的上一个C++ object deleted
错误,因此我只能推断deepcopy
操作失败。
因此,我能给予寻找类似答案的人的唯一建议是实现他们自己的copy-widget
功能,这最终是我现在要做的。
尽管如此,我希望了解deepcopy
是如何失败的,如此默默无闻,却激起了执行的终结。我开始尝试找到这个there
修改强>
我找到了解决这个问题的解决方案,它解决了我不需要对GUI元素进行硬编码以及使用Qt Designer为可重复元素创建GUI和模板的要求。我希望它可以帮助任何有同样问题的人:
这个想法是可以使用Qt - 和pyside - 在运行时使用.ui
方法加载给定的QUiLoader()
文件。因此可以解析.ui
文件以提取给定的窗口小部件(.ui
文件是简单的XML文件)并使用以下代码来使用它:
loader = QUiLoader()
ui_file = QFile("path_to_ui_file.ui")
ui_file.open(QFile.ReadOnly)
new_tab = loader.load(ui_file)
ui_file.close()
main_dialog.my_tabs.addTab(new_tab, "")
它有效!
关于上述例子的一些事情:
path_to_ui_file.ui
答案 1 :(得分:1)
为要复制的小部件创建单独的ui文件的建议似乎是一个合理的解决方案。虽然使用pyside-uic为小部件生成一个单独的gui模块似乎与使用QUiLoader
一样好(事实上,它会稍微有点效率)。
关于为什么使用例如克隆小部件的问题copy.deepcopy
不起作用:这是因为它只复制python包装器,而不复制底层的C ++对象。在this answer中可以找到更全面的解释。