我不确定如何解决以下问题:
self.w
下面的内容)self.w
仍会保留对已关闭窗口的引用self.w.repaint()
,我会收到一条错误消息RuntimeError: underlying C/C++ object has been deleted
。此错误是由于我们仍然存在对self.w
。 问题:
如何修改下面的代码,以便在弹出窗口关闭时,属性self.w
会自动设置为None
?有什么好的和坏的方式来实现这个?我想将self.w
设置为None
的原因是,我将能够检查此属性是否为None
,如果是,我可以重新初始化弹出窗口调用repaint()
之前的窗口,从而避免错误消息。
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from PyQt4.Qt import *
class MyPopup(QWidget):
def __init__(self):
QWidget.__init__(self)
def paintEvent(self, e):
dc = QPainter(self)
dc.drawLine(0, 0, 100, 100)
dc.drawLine(100, 0, 0, 100)
class MainWindow(QMainWindow):
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.cw = QWidget(self)
self.setCentralWidget(self.cw)
self.btn1 = QPushButton("Click me", self.cw)
self.btn1.setGeometry(QRect(0, 0, 100, 30))
self.connect(self.btn1, SIGNAL("clicked()"), self.doit)
self.w = None
def doit(self):
print "Opening a new popup window..."
self.w = MyPopup()
self.w.setGeometry(QRect(100, 100, 400, 200))
self.w.show()
class App(QApplication):
def __init__(self, *args):
QApplication.__init__(self, *args)
self.main = MainWindow()
self.connect(self, SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
def byebye( self ):
self.exit(0)
def main(args):
global app
app = App(args)
app.exec_()
if __name__ == "__main__":
main(sys.argv)
答案 0 :(得分:1)
回答你的问题:
如何修改下面的代码,以便弹出窗口时 关闭,属性self.w自动设置为None?是什么 好的和差的方式实现这个?
您应该尝试在弹出式课程中添加此项' init方法:
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
您可以在此处的文档中找到它: http://qt-project.org/doc/qt-4.8/qt.html#WidgetAttribute-enum
回想起来,如果对self.w.repaint()的调用抛出了错误RuntimeError: underlying C/C++ object has been deleted
,则表示该对象实际上已被删除。 self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
将确保在关闭时删除对象。这是最干净的方法。
从您的评论中收集,您希望在发生此关闭事件时干净地释放包含此窗口小部件的类属性。要做到这一点,我们可以让弹出窗口在关闭时发出信号,主窗口可以捕获以释放。你可以这样做:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from PyQt4.Qt import *
from PyQt4 import QtCore
class MyPopup(QWidget):
close_signal = pyqtSignal()
def __init__(self):
QWidget.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
def paintEvent(self, e):
dc = QPainter(self)
dc.drawLine(0, 0, 100, 100)
dc.drawLine(100, 0, 0, 100)
def closeEvent(self, event):
self.on_close()
def on_close(self):
""" Perform on close stuff here """
self.close_signal.emit()
class MainWindow(QMainWindow):
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.cw = QWidget(self)
self.setCentralWidget(self.cw)
self.btn1 = QPushButton("Click me", self.cw)
self.btn1.setGeometry(QRect(0, 0, 100, 30))
self.connect(self.btn1, SIGNAL("clicked()"), self.doit)
self.btn2 = QPushButton("repaint me", self.cw)
self.btn2.setGeometry(QRect(100, 30, 200, 50))
self.connect(self.btn2, SIGNAL("clicked()"), self.repaintPopup)
self.w = None
def doit(self):
print "Opening a new popup window..."
self.w = MyPopup()
self.w.setGeometry(QRect(100, 100, 400, 200))
self.w.show()
self.w.close_signal.connect(self.on_popup_closed)
def repaintPopup(self):
self.w.repaint()
def on_popup_closed(self):
""" Cleanup the popup widget here """
print "Popup closed."
self.w = None
class App(QApplication):
def __init__(self, *args):
QApplication.__init__(self, *args)
self.main = MainWindow()
self.connect(self, SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
def byebye( self ):
self.exit(0)
def main(args):
global app
app = App(args)
app.exec_()
if __name__ == "__main__":
main(sys.argv)
虽然你的Popup是一个没有任何父级的独立小部件。这就是为什么它显示为一个窗口。如果要维护父子关系,则弹出窗口必须是一个窗口(例如QMainWindow),其中MyPopup QWidget作为其中心窗口小部件,并且您的主窗口设置为父窗口。这将确保此弹出窗口始终被视为主窗口的子窗口,并允许弹出窗口使用nativeParentWidget()方法访问主窗口。要进行这种改变,你只需要重构一下:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from PyQt4.Qt import *
from PyQt4 import QtCore
class MyPopup(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
def paintEvent(self, e):
dc = QPainter(self)
dc.drawLine(0, 0, 100, 100)
dc.drawLine(100, 0, 0, 100)
class PopupWindow(QMainWindow):
close_signal = QtCore.pyqtSignal()
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.cw = MyPopup(parent=self)
self.setCentralWidget(self.cw)
self.setGeometry(QRect(100, 100, 400, 200))
self.cw.setGeometry(QRect(100, 100, 400, 200))
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
print "I am the popup Window. My parent is: %s" % self.nativeParentWidget() # access the parent here
def closeEvent(self, event):
""" Perform on close stuff here """
self.on_close()
def on_close(self):
self.close_signal.emit()
class MainWindow(QMainWindow):
def __init__(self, *args):
QMainWindow.__init__(self, *args)
self.cw = QWidget(self)
self.setCentralWidget(self.cw)
self.btn1 = QPushButton("Click me", self.cw)
self.btn1.setGeometry(QRect(0, 0, 100, 30))
self.connect(self.btn1, SIGNAL("clicked()"), self.doit)
self.btn2 = QPushButton("repaint me", self.cw)
self.btn2.setGeometry(QRect(100, 30, 200, 50))
self.connect(self.btn2, SIGNAL("clicked()"), self.repaintPopup)
self.w = None
def doit(self):
print "Opening a new popup window..."
self.w = PopupWindow(self)
self.w.show()
self.w.repaint()
self.w.close_signal.connect(self.on_popup_closed)
def repaintPopup(self):
self.w.repaint()
def on_popup_closed(self):
""" Cleanup the popup widget here """
print "Popup closed."
self.w = None
class App(QApplication):
def __init__(self, *args):
QApplication.__init__(self, *args)
self.main = MainWindow()
self.connect(self, SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
def byebye( self ):
self.exit(0)
def main(args):
global app
app = App(args)
app.exec_()
if __name__ == "__main__":
main(sys.argv)
您可以使用sip模块的isdeleted()
方法来测试您的对象是否已被删除。如果你愿意,可以额外检查一下。
import sip
sip.isdeleted(self.w)
查看sip模块提供的更多方法来处理swig / C / C ++对象:http://pyqt.sourceforge.net/Docs/sip4/python_api.html
我希望这很有用。