Ich habe einen Fehler gefunden, der ein Programmbeispiel von "Rapid GUI Programming with Python and Qt" von PyQt4 nach PyQt5 portiert. Das Beispielprogramm demonstriert eine MDI-Anwendung, aus der mehrere Textbearbeitungsfenster innerhalb des Hauptfensters ausgeführt werden können.Portierung von PyQt4 QWorkspace nach PyQt5 QMdiArea - SubWindowList Methode
Ich habe Python 3.4.4 und PyQt 4.8.7 für die PyQt4-Version verwendet. Ich habe Python 3.4.4 und PyQt 5.5.1 für die PyQt5-Version verwendet.
Ich begann mit der Änderung aller alten Signaldefinitionen in neue Stilsignale im ursprünglichen PyQt4-Programm. Neue Stilsignale wurden in PyQt 4.5 implementiert, so dass ich das ursprüngliche Programm mit diesen Änderungen ausführen konnte. Die Anwendung wurde erfolgreich ausgeführt, nachdem alle alten Signale auf neue Signale aktualisiert wurden.
Das ursprüngliche Programm verwendet die PyQt4.QtGui.QWidget.QWorkspace-Klasse, um den MDI-Arbeitsbereich zu implementieren. QWorkspace wurde in PyQt4.3 durch die PyQt5.QtWidgets.QMdiArea Klasse ersetzt. Mein Problem tauchte auf, als ich versuchte, den ursprünglichen Code zu ändern, um mit QMdiArea zu arbeiten.
Jedes Textdokument wird mit einer Instanz eines benutzerdefinierten TextEdit-Widgets, einer Unterklasse von QTextEdit, dargestellt und bearbeitet.
Minimal PyQt5 Version von MDI-Anwendung - 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_()
Das Problem in der Fileopen auftritt() -Methode:
PyQt4 Fileopen() -Methode
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() Methode
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() ist in PyQt5 als subWindowList() implementiert. Das Problem ist, dass in der PyQt4 Version, wenn for textEdit in self.mdi.windowList():
ausgeführt textEdit vom Typ TextEdit ist so die nächste Zeile
if textEdit.filename == filename
arbeitet seit TextEdit einen Dateinamen Parameter hat. und textEdit ist ein {TextEdit} textedit.TextEdit Objekt, aber in der PyQt5 Version, nach for textEdit in self.mdi.subWindowList():
ausgeführt wird, die Art der textEdit ist QMdiSubWindow so, natürlich die Zurückverfolgungs erzeugt:
Traceback (most recent call last):
File "texteditor3.py", line 292, in fileOpen
if textEdit.filename == filename:
AttributeError: 'QMdiSubWindow' object has no attribute 'filename'
Was wirklich verwirrt mich ist, wie textEdit in der PyQt4-Version wird zu einem TextEdit-Typ. Ich würde denken, es wäre ein Str-Typ.
ich ein minimales, vollständig und überprüfbar Beispiel hinzugefügt! –
Um diese Frage angemessen zu halten, habe ich den Minimalcode für die PyQt4-Version nicht eingefügt. Wenn jemand das sehen möchte, würde ich es gerne hinzufügen oder es Ihnen schicken. –