我遇到了从PyQt4到PyQt5的“使用Python和Qt进行快速GUI编程”的程序示例。示例程序演示了一个MDI应用程序,可以在主窗口中运行多个文本编辑窗口。
我使用python 3.4.4和PyQt 4.8.7作为PyQt4版本。我使用python 3.4.4和PyQt 5.5.1作为PyQt5版本。
我首先将所有旧式信号定义更改为原始PyQt4程序中的新样式信号。在PyQt 4.5中实现了新的样式信号,因此我可以使用这些更改运行原始程序。在将所有旧式信号更新为新式信号后,应用程序成功运行。
原始程序使用PyQt4.QtGui.QWidget.QWorkspace类来实现MDI工作区。 QWorkspace被PyQt4.3中的PyQt5.QtWidgets.QMdiArea类所取代。我的问题浮出水面,试图修改原始代码以使用QMdiArea。
使用自定义TextEdit小部件的实例(QTextEdit的子类)来呈现和编辑每个文本文档。
MDI应用程序的最小PyQt5版本 - texteditor.py
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class TextEdit(QTextEdit):
NextId = 1
def __init__(self, filename="", parent=None):
print("TextEdit __init__")
super(TextEdit, self).__init__(parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.filename = filename
if not self.filename:
self.filename = "Unnamed-{}.txt".format(TextEdit.NextId)
TextEdit.NextId += 1
self.document().setModified(False)
self.setWindowTitle(QFileInfo(self.filename).fileName())
def load(self):
print("load - TextEdit")
exception = None
fh = None
try:
fh = QFile(self.filename)
if not fh.open(QIODevice.ReadOnly):
raise IOError(fh.errorString())
stream = QTextStream(fh)
stream.setCodec("UTF-8")
self.setPlainText(stream.readAll())
self.document().setModified(False)
except EnvironmentError as e:
exception = e
finally:
if fh is not None:
fh.close()
if exception is not None:
raise exception
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
__version__ = "1.0.0"
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
fileOpenAction = QAction("&Open...", self)
fileOpenAction.setShortcut(QKeySequence.Open)
fileOpenAction.triggered.connect(self.fileOpen)
fileMenu = self.menuBar().addMenu("&File")
fileMenu.addAction(fileOpenAction)
settings = QSettings()
self.restoreGeometry(settings.value("MainWindow/Geometry",
QByteArray()))
self.restoreState(settings.value("MainWindow/State",
QByteArray()))
QTimer.singleShot(0, self.loadFiles)
def loadFiles(self):
if len(sys.argv) > 1:
for filename in sys.argv[1:31]: # Load at most 30 files
if QFileInfo(filename).isFile():
self.loadFile(filename)
QApplication.processEvents()
else:
settings = QSettings()
files = settings.value("CurrentFiles") or []
for filename in files:
if QFile.exists(filename):
self.loadFile(filename)
QApplication.processEvents() #todo What does this do?
def fileOpen(self):
filename, _ = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
for textEdit in self.mdi.subWindowList():
print(type(textEdit))
if textEdit.filename == filename:
self.mdi.setActiveSubWindow(textEdit)
break
else:
self.loadFile(filename)
def loadFile(self, filename):
textEdit = TextEdit(filename)
try:
textEdit.load()
except EnvironmentError as e:
QMessageBox.warning(self, "Text Editor -- Load Error",
"Failed to load {}: {}".format(filename, e))
textEdit.close()
del textEdit
else:
self.mdi.addSubWindow(textEdit)
textEdit.show()
app = QApplication(sys.argv)
app.setWindowIcon(QIcon(":/icon.png"))
app.setOrganizationName("Qtrac Ltd.")
app.setOrganizationDomain("qtrac.eu")
app.setApplicationName("Text Editor")
form = MainWindow()
form.show()
app.exec_()
fileOpen()方法出现问题:
PyQt4 fileOpen()方法
def fileOpen(self):
filename = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
for textEdit in self.mdi.windowList():
if textEdit.filename == filename:
self.mdi.setActiveWindow(textEdit)
break
else:
self.loadFile(filename)
PyQt5 fileOpen()方法
def fileOpen(self):
filename, _ = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
for textEdit in self.mdi.subWindowList():
if textEdit.filename == filename:
self.mdi.setActiveSubWindow(textEdit)
break
else:
self.loadFile(filename)
windowList()在PyQt5中实现为subWindowList()。问题是在PyQt4版本中,当执行for textEdit in self.mdi.windowList():
时,textEdit的类型是TextEdit所以下一行
if textEdit.filename == filename
有效,因为TextEdit确实有 filename 参数。和textEdit是一个{TextEdit} textedit.TextEdit对象,但是在PyQt5版本中,执行for textEdit in self.mdi.subWindowList():
后,textEdit的类型是QMdiSubWindow,所以回溯当然会生成:
Traceback (most recent call last):
File "texteditor3.py", line 292, in fileOpen
if textEdit.filename == filename:
AttributeError: 'QMdiSubWindow' object has no attribute 'filename'
令我感到困惑的是PyQt4版本中的textEdit如何成为TextEdit类型。我认为这将是一种类型。
答案 0 :(得分:0)
我来自德国,我找到了答案。见代码。 抱歉德国评论。
def fileOpen(self):
try:
# PSc QFileDialog.getOpenFileName gibt ein Tuple zurück
# für die weitere Verwendung filname[0] verwenden
filename = QFileDialog.getOpenFileName(self,
"Text Editor -- Open File")
if filename:
try:
# PSc wenn ein zweites Open durchgeführt wird erhält man die Fehlermeldung
# textEdit has no attribute fileName
# http://stackoverflow.com/questions/37800036/porting-pyqt4-qworkspace-to-pyqt5-qmdiarea-subwindowlist-method
# Lösung scheinbar hier gefunden Zeile 268 269
# http://nullege.com/codes/show/src%40p%40y%40pyqt5-HEAD%40examples%40mainwindows%40mdi%40mdi.py/168/PyQt5.QtWidgets.QMdiArea.subWindowActivated.connect/python
# Folgende Zeile dementsprechen geändert
# for textEdit in self.mdi.subWindowList():
for windows in self.mdi.subWindowList():
textEdit = windows.widget()
print('In File Open textEdit.filename: ' + textEdit.filename)
if textEdit.filename == filename[0]:
self.mdi.setActiveWindow(textEdit)
break
else:
# PSc filename Tuple daher filename[0] übergeben
self.loadFile(filename[0])
except:
e = sys.exc_info()
print('An exception occurred in def fileOpen if Filename : \n' + str(e) + '\n')
except:
e = sys.exc_info()
print('An exception occurred in def fileOpenin: \n' + str(e) + '\n')
我之所以改变它:
def fileSave(self):
try:
# PSc PyQt4 Syntax
# textEdit = self.mdi.activeSubWindow()
# geändert laut Zeile 268,269
# nullege.com/codes/show/src%40p%40y%40pyqt5-HEAD%40examples%40mainwindows%40mdi%40mdi.py/168/PyQt5.QtWidgets.QMdiArea.subWindowActivated.connect/python
window = self.mdi.activeSubWindow()
textEdit = window.widget()
if textEdit is None or not isinstance(textEdit, QTextEdit):
return True
try:
textEdit.save()
return True
except EnvironmentError as e:
QMessageBox.warning(self, "Text Editor -- Save Error",
"Failed to save {}: {}".format(textEdit.filename, e))
return False
except Exception as error:
print('An exception occurred in fileSave: {}'.format(error))