QWidget: Must construct a QApplication before a QPaintDevice

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Benutzeravatar
nieselfriem
User
Beiträge: 135
Registriert: Sonntag 13. Januar 2013, 16:00

Hallo!

Ich wollte mich mal an QT und Destopapplikation in Python heranwagen. Dazu habe ich das Tutorial auf der Seite https://blog.safaribooksonline.com/2014 ... sing-pyqt/ abgetippert.

Nun bekomme ich beim Start jedoch die obere Fehlermeldung.

Mein Code zum Starten der Applickation:

Code: Alles auswählen

__author__ = 'georg'
import sys
from PyQt4 import QtCore, QtGui, uic
from PyQt4.QtGui import QApplication

form_class = uic.loadUi("calctemp.ui")[0]

class MyWindowClass(QtGui.QMainWindow, form_class):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self,parent)
        self.setupUi(self)
        self.btn_CtoF.clicked.connect(self.btn_CtoF_clicked)
        self.btn_FtoC.clicked.connect(self.btn_FtoC_clicked)

    def btn_CtoF_clicked(self):
        cel = float(self.editCel.text())
        fahr = cel * 9/ 5.0 + 32
        self.spinFahr.setValue(int(fahr + 0.5))

    def btn_FtoC_clicked(self):
        fahr = self.spinFahr.value()
        cel = (fahr -32) * 5.0/9
        self.editCel.setText(str(cel))

app = QtGui.QApplication(sys.argv)
myWindow = MyWindowClass(None)
myWindow.show()
app.exec_()
und die dazu mit pyuic4 erzeugte Datei:

Code: Alles auswählen

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'calctemp.ui'
#
# Created: Mon Mar  2 20:29:35 2015
#      by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.btn_CtoF = QtGui.QPushButton(self.centralwidget)
        self.btn_CtoF.setGeometry(QtCore.QRect(260, 110, 141, 27))
        self.btn_CtoF.setObjectName(_fromUtf8("btn_CtoF"))
        self.btn_FtoC = QtGui.QPushButton(self.centralwidget)
        self.btn_FtoC.setGeometry(QtCore.QRect(270, 250, 131, 27))
        self.btn_FtoC.setObjectName(_fromUtf8("btn_FtoC"))
        self.editCel = QtGui.QLineEdit(self.centralwidget)
        self.editCel.setGeometry(QtCore.QRect(120, 160, 113, 27))
        self.editCel.setObjectName(_fromUtf8("editCel"))
        self.spinFahr = QtGui.QSpinBox(self.centralwidget)
        self.spinFahr.setGeometry(QtCore.QRect(490, 160, 111, 27))
        self.spinFahr.setObjectName(_fromUtf8("spinFahr"))
        self.label = QtGui.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(130, 200, 56, 17))
        self.label.setObjectName(_fromUtf8("label"))
        self.label_2 = QtGui.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(490, 190, 81, 17))
        self.label_2.setObjectName(_fromUtf8("label_2"))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 27))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.btn_CtoF.setText(_translate("MainWindow", "Celcius zu Fahrenheit", None))
        self.btn_FtoC.setText(_translate("MainWindow", "Fahrenheit zu Celcius", None))
        self.label.setText(_translate("MainWindow", "Celcius", None))
        self.label_2.setText(_translate("MainWindow", "Fahrenheit", None))

Hab ich da ein Fehler beim aptippern gemacht oder ist das Tutorial nicht korrekt? Im Forum habe ich dazu leider nichts gefunden.

VG niesel
BlackJack

@nieselfriem: Das Tutorial ist an der Stelle nicht korrekt. Bevor man irgendwelche GUI-Elemente erzeugt, und das tut Zeile 6, muss ein `QApplication` Objekt existieren, wie die Fehlermeldung ja auch deutlich sagt.

*Diese* Variante habe ich allerdings bisher auch noch nie gesehen. Ich sehe da gerade den Sinn der Mehrfachvererbung nicht, und ich kann bei mir auch das Ergebnis von `loadUi()` auch gar nicht mit einem Indexzugriff benutzen. Ich sehe auch nicht wo man da eine *Klasse* herbekommen soll, denn das Ergebnis von dem Aufruf sind ja schon *Exemplare* von Widgets.

Und ganz allgemein verstösst das Programm dagegen das man keinen Code auf Modulebene haben sollte der keine Konstanten, Funktionen, und Klassen definiert. Das Laden der ``*.ui``-Datei gehört also mindestens wie der Rest vom Hauptprogramm in eine Funktion. Allerdings würde ich den Aufruf überhaupt nicht ausserhalb der `ConverterUi` (oder so ähnlich, denn `MyWindowClass` ist ein denkwürdig schlechter Name der da im Tutorial gewählt wurde) tätigen. Der würde eher in der `__init__` stehen, und dort dann das Exemplar der `ConverterUi` selbst als zweites Argument bekommen damit man den Effekt hat, den der Autor vom Tutorial sich offenbar von der Vererbung versprochen hat.

Warum hast Du den zweiten Quelltext in dem Beitrag generiert?
Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

Bevor deine GUI lebensfähig ist, muss ein Medium erstellt werden, in welchem diese existieren kann. Die QApplication-Instanz muss also in jedem Fall vor jedweder QWidget-Instantiierung erfolgen.

Code: Alles auswählen

form_class = uic.loadUi("calctemp.ui")[0]
Das hat an der Stelle nichts zu suchen! Die Verwendung mit dem Index ist mir nicht geläufig.

Du musst keinen Code mit pyuic4 erzeugen, sondern kannst *.ui Dateien via uic.loadui() dynamisch zur Laufzeit laden (bspw. im Konstruktor deiner Window-Klasse). Das ist maximal sinnvoll, wie der Hinweis in dem erzeugten Code auch betont. (All changes made in this file will be lost.)

Wenn du explizit QApplication importierst, kannst du auch QMainWindow explizit importieren. Der separate Import von QtGui ist nicht notwendig.

QtCore wurde importiert aber nicht verwendet. Unnötige Importe sollte man möglichst vermeiden.
Antworten