Painting in einem Widget

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Patrick1990
User
Beiträge: 116
Registriert: Freitag 3. Juni 2016, 05:45

Hallo,

ich habe ein QMainWindow mit einigen Buttons, Eingabefeldern und einem QWidget (Name: widgetPainting).
In dem QWidget soll nun eine Zeichnung erstellt werden, jedoch nutzt mein Programm immer die gesamte Fläche des MainWindows für die Zeichnung. Wie kann ich sagen, dass nur in dem Widget-Fenster gezeichnet werden soll?


Auszug aus dem Code:

Code: Alles auswählen

     def paintEvent(self, event):

         width = self.widgetPainting.geometry().width()
         height = self.widgetPainting.geometry().height()
         
                  
         self.widgetPainting.setStyleSheet("background-color: rgb(255,255,255); margin:0px; border:1px solid rgb(0, 255, 0); ")

                  
    
         painter = gui.QPainter()

         painter.begin(self)
         
         painter.drawLine(0,0,100, 100)
         painter.end()
         
        
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was ist denn dein Self? Ist das das MainWindow? Dann ist das ja nicht weiter verwunderlich. Stattdessen muss der painter das Widget in begin/end bekommen. Und natürlich solltest du den Code zum malen aus organisatorischen Gründen in dem entsprechenden Widget schreiben, und nicht im MainWindow.
Patrick1990
User
Beiträge: 116
Registriert: Freitag 3. Juni 2016, 05:45

Ok es sind einige grundlegende Dinge, die ich nicht so richtig zu programmieren verstehe.

Ich habe im QtDesigner eine Oberfläche "mainwindow.ui" erstellt, diese enthält das Widget "widgetPainting".
Die *.ui-Datei habe ich anschließend zu einer *.py-Datei umgewandelt.

Diese sieht so aus:

Code: Alles auswählen

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButtonVorschau = QtWidgets.QPushButton(self.centralwidget)
        self.pushButtonVorschau.setGeometry(QtCore.QRect(700, 10, 75, 23))
        self.pushButtonVorschau.setObjectName("pushButtonVorschau")
        self.widgetPainting = QtWidgets.QWidget(self.centralwidget)
        self.widgetPainting.setGeometry(QtCore.QRect(300, 80, 450, 450))
        self.widgetPainting.setAutoFillBackground(False)
        self.widgetPainting.setObjectName("widgetPainting")
        self.comboBoxRotortopologie = QtWidgets.QComboBox(self.centralwidget)
        self.comboBoxRotortopologie.setGeometry(QtCore.QRect(30, 40, 161, 22))
        self.comboBoxRotortopologie.setObjectName("comboBoxRotortopologie")
        self.formLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.formLayoutWidget.setGeometry(QtCore.QRect(30, 80, 231, 471))
        self.formLayoutWidget.setObjectName("formLayoutWidget")
        self.formLayoutVariables = QtWidgets.QFormLayout(self.formLayoutWidget)
        self.formLayoutVariables.setContentsMargins(0, 0, 0, 0)
        self.formLayoutVariables.setObjectName("formLayoutVariables")
        self.label_Rotortopologie = QtWidgets.QLabel(self.centralwidget)
        self.label_Rotortopologie.setGeometry(QtCore.QRect(30, 20, 91, 16))
        self.label_Rotortopologie.setObjectName("label_Rotortopologie")
        MainWindow.setCentralWidget(self.centralwidget)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButtonVorschau.setText(_translate("MainWindow", "Vorschau..."))
        self.label_Rotortopologie.setText(_translate("MainWindow", "Rotortopologie"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Nun nutze ich zum "Aufruf" des MainWindows folgenden Code:

Code: Alles auswählen

import sys
#import PyQt5.QtCore as core
import PyQt5.QtWidgets as widgets
#import PyQt5.QtGui as gui

#import types #für method type


import mainwindow as mw



class MainWindowRotor(widgets.QMainWindow, mw.Ui_MainWindow):
    
    def __init__(self, parent = None):                                         
        super(MainWindowRotor, self).__init__(parent)
        self.setupUi(self)

        

        
def main():
    app = widgets.QApplication(sys.argv)   
    mwr = MainWindowRotor()
    mwr.show()
    sys.exit(app.exec_())
                                                               

if __name__ == '__main__':
    main()  
Ich verstehe es so, dass ich bestenfalls eine Klasse erstellen müsste, die das Widget "widgetPainting" beinhaltet und in welcher das paintEvent steht oder?
Wie mache ich das?
Ich weiß lediglich, wie ich Klassen für extra Fenster erstelle, jedoch nicht für ein Widget innerhalb eines Fensters.
Da die Positionierung des Widgets im QtDesigner einfacher zu handhaben ist, wollte ich das Widget auch nicht erst im Code erstellen.

Vielen Dank im Voraus.

Wäre für ein wenig Licht ins Dunkel sehr dankbar.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist in der Tat ein bisschen ätzend. Ich kenne mich mit Python Qt hier aus der lameng nicht aus, meine letzten Projekte waren mit C++. Dort kann man im Designer tatsächlich eine custom Widget klasse angeben, und der generierte Header—Code packt einfach einen entsprechenden include (quasi Import) rein. Unter Umständen kann man den gleichen Mechansimus auch mit pyuic verwenden.

Wenn das nicht geht, kann man immer noch den Weg gehen das entsprechende Widget selbst zu instanzieren und einfach in die Hierarchie einzuhängen. Entweder zb indem du ein Platzhalter-Widget machst & das benutzt um

- es per Namen zu finden
- den parent zu bekommen
- dessen Layout hernehmen
- dein neues Widget da einhängen
- den Platzhalter entfernen.

Es findet sich sicher etwas zu dem Thema in der pyqt Doku oder entsprechenden Beispielen/Mailinglisten.
Patrick1990
User
Beiträge: 116
Registriert: Freitag 3. Juni 2016, 05:45

Habe es jetzt hinbekommen mit einem Platzhalter (diesen konnte ich direkt im QtDesigner einstellen).

Nun habe ich ein weiteres Problem.

Ich lese Werte in der MainWindow-Klasse ein, möchte jedoch die Werte, welche in der MainWindow-Klasse eingelesen wurden in der Painting-Klasse (also das Widget) verwenden.
Ich kann nun leider keine Instanz der MainWindow-Klasse in der Painting-Klasse erstellen. Gibt es andere Möglichkeiten darauf zuzugreifen?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kommst ja per Namen an das Widget. An der Stelle wo du die ui erzeugst kannst du dann dem Widget eine Referenz auf das MainWindow übergeben. Genauso wie du da ja zb auch Signal Slot connnections machst.
Patrick1990
User
Beiträge: 116
Registriert: Freitag 3. Juni 2016, 05:45

__deets__ hat geschrieben:An der Stelle wo du die ui erzeugst kannst du dann dem Widget eine Referenz auf das MainWindow übergeben.
Wie sähe sowas aus?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

widget_instanz.attribut = wert

Mehr nicht.
Patrick1990
User
Beiträge: 116
Registriert: Freitag 3. Juni 2016, 05:45

Ok, vielen Dank. Ich habe immer gedacht ich müsste das genau umgekehrt machen.
So klappt es.

Nun ist nur noch das Problem mit der automatischen Aktualisierung der Zeichnung sobald sich ein Wert geändert hat.
Ich habe es letztens mit Instanz.update() gemacht. widget_instanz.update() das funktioniert hier nun nicht.
Wie kann ich das lösen?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kann ich so nicht sagen. Woher kommen denn die geaenderten Daten? Wer weiss, dass die da sind, und kann wen benarchichtigen?
Patrick1990
User
Beiträge: 116
Registriert: Freitag 3. Juni 2016, 05:45

Ok ich habe, mein Fehler lag an einer ganz anderen Stelle. Die range-Funktion kann nur Integer als Eingabewerte verarbeiten, ich hatte einen Integer und einen float.

Vielen Dank für die Hilfe.
Antworten