@Christian_N: Die Einrückung bleibt nicht erhalten weil das hier HTML ist, da ist ”whitespace” in Fliesstext egal, das wird normalisiert, heisst führender Leerraum wird entfernt und Leerraum zwischen Text wird auf jeweils ein Leerzeichen zusammengeschrumpft. Wenn man vorformatierten Text hat, der so bleiben soll, dann muss man den in <pre> oder <code> einfassen (oder per CSS dafür sorgen, dass andere Elemente auch Leerraum 1:1 übernehmen). Für die Beiträge hier in der BBCode-Syntax gibt es [code]-Tags in die man den Quelltext einfassen kann. Gibt sogar Syntax-Highlighting, das rät was für eine Sprache da zwischen den Tags steht. Man kann das aber auch mit [code=python]…[/code] explizit machen.
Wenn man die Code-Tags nicht von Hand schreiben will: das ist die mit „</>“ beschriftete Schaltfläche im vollständigen Editor für Beiträge.
Auszeichnungen gehen innerhalb von Code dann nicht mehr, also dort etwas Fett oder Kursiv hervorheben. So ein [i] ist ja auch irreführend, denn das kann bei einem Indexzugriff auch genau so in ganz normalem Quelltext vorkommen. In Python weniger als in einigen anderen Programmiersprachen, aber ausgeschlossen ist es nicht.
Eingerückt wird in Python mit vier Leerzeichen pro Ebene.
Auf Modulebene sollte nur Code stehen, der Konstanten, Funktionen, und Klassen definiert. Das Hauptrogramm steht üblicherweise in einer Funktion die `main()` heisst.
Funktionen und Methoden bekommen alles was sie ausser Konstanten benötigen, als Argument(e) übergeben. Wenn das Hauptprogramm in einer `main()`-Funktion steht, dann kann das Hauptfenster in der `__init__()` nicht mehr einfach so ”aus dem nichts” darauf zugreifen. Es macht da auch nicht so wirklich Sinn das an das Objekt zu binden wenn man sowieso von überall darauf zugreifen könnte. Und in der Praxis muss man das auch nicht übergeben, weil `QApplication` eine statische Methode hat um jederzeit auf *das* *eine* Anwendungsobjekt zugreifen zu können: `instance()`.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassennamen (PascalCase).
Namen sollten keine kryptischen Abkürzungen enthalten, oder gar nur daraus bestehen. Also dieses unsägliche `Frm` überall: entweder schreibt man da `Form` oder man lässt diese für Python und Qt untypische Bezeichnung weg. Und nennt das Hauptfenster nicht `Frm_main` sondern `MainWindow`. Und `cnx` sollte `connection` heissen.
`Frm_main` darf nicht von `Ui_MainWindow` *und* `Ui_Frm_login` erben. Vererbung ist eine „ist ein(e)“-Beziehung, und das Hauptfenster ist kein Anmeldefenster.
Das generieren von Quelltext aus *.ui-Dateien sollte man aber schon lange nicht mehr machen. Man kann die *.ui-Dateien zur Laufzeit einbinden, ohne da in einem unnötigen Zwischenschritt Quelltextdateien für zu generieren.
Die Importe sehen so aus als wenn das Projekt selbst nicht in einem Package steckt. Das ist keine gute Idee. Das sollte alles in einem Package stecken, mit einem Unterpackage für die Widgets (wenn man denn überhaupt Quelltext dafür verwendet — siehe letzter Punkt).
Dann dürfen die beiden Fenster nicht einfach so nebeneinander bestehen und beide gleichzeitig bedienbar sein. Man kann ja im Hauptfenster schon alles machen bevor man sich angemeldet hat. Das löst man entweder dadurch, dass das Hauptfenster bei der Anmeldung noch nicht angezeigt wird, oder dadurch, dass das Anmeldefenster ein modales Fenster ist, also das Hauptfenster solange nicht bedienbar ist. In dem Fall sollte das Anmeldefenster auch ein Kind vom Hauptfenster sein, im Sinne der Objekthierarchie von Qt. Das führt beispielsweise auch dazu, dass die Fensterverwaltung des Systems sich anders/sinnvoll verhalten kann was so Sachen wie Platzierung auf dem Bildschirm, anzeige in der Taskleiste und so weiter angeht.
Wenn man das mit den Fenstern besser regelt, dann muss das Hauptfenster auch nicht `quit()` auf dem Anwendungsobjekt aufrufen, denn die Defaulteinstellung ist, dass die Anwendung sich beendet wenn alle Fenster geschlossen sind. Da steht übrigens zweimal das falsche `quit` im Quelltext. Das Signal sollte mit `self.quit` verbunden werden, und dort macht es keinen Sinn das Anwendungsobjekt mit der ”eingebauten” `quit`-Funktion als *Argument* *aufzurufen*. Das Anwendungsobjekt ist gar nicht aufrufbar.
Das f vor der Zeichenkette mit der SQL-Abfrage macht Angst. Man formatiert keine Werte mit Zeichenkettenoperationen in SQL. Dazu gibt es Platzhalter und das zweite Argument von `Cursor.execute()` was das *sicher* und *performant* erledigt die Abfrage und Werte zusammen zu bringen.
Cursor-Objekte sollte man nach der Verwendung schliessen. Es kann sein, dass für Cursor beim Client und/oder beim Server Ressourcen belegt werden, die man zeitnah wieder freigeben sollte.
Die `abbrechen()`-Methode ist unnötig, man könnte da direkt die `close()`-Methode Slot angeben.
Hier eine Überarbeitung die ein paar Kommentare umsetzt, aber natürlich noch das Problem hat das lokale Namen in einer Methode nicht auf magische Weise in einer anderen Methode existieren. Was auch gar nichts damit zu tun hat, dass die Methoden in verschiedenen Klassen stehen, sowie Klassen eigentlich überhaupt nichts damit zu tun haben. Werte übermittelt man beim Aufruf.
Code: Alles auswählen
import sys
from contextlib import closing
import mysql.connector
from mysql.connector import errorcode
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget
from Widgets.frm_login import Ui_Frm_login
from Widgets.frm_main import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.actionBeenden.triggered.connect(self.close)
self.actionRohdaten.triggered.connect(self.schreibe_rohdaten)
def schreibe_rohdaten(self):
with closing(connection.cursor()) as cursor:
cursor.execute("SELECT * FROM loggerdaten")
for row in cursor.fetchall():
print(row)
class LoginWindow(QWidget, Ui_Frm_login):
def __init__(self):
super().__init__()
self.setupUi(self)
self.quit_button.clicked.connect(self.close)
self.pushButton.clicked.connect(self.login)
def login(self):
try:
connection = mysql.connector.connect(
user=self.user.text(),
password=self.password.text(),
host="xxx.xxx.xxx.xxx",
port=3306,
database="database",
)
self.close()
except mysql.connector.Error as error:
if error.errno == errorcode.ER_ACCESS_DENIED_ERROR:
print("Something is wrong with your user name or password")
elif error.errno == errorcode.ER_BAD_DB_ERROR:
print("Database does not exist")
else:
print(error)
def main():
app = QApplication(sys.argv)
main_window = MainWindow()
login_window = LoginWindow()
main_window.show()
login_window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Letztlich würde ich einen Dialog mit entsprechender Basisklasse verwenden für die Anmeldung und das Hauptfenster dabei vielleicht auch noch gar nicht anzeigen. Denn man möchte ja wirklich sicher sein, dass der Benutzer sich angemeldet hat, bevor er irgendetwas im Hauptfenster machen kann. Man könnte das Loginfenster ja beispielsweise auch einfach über das x in der Fensterleiste schliessen. Wenn man das Hauptfenster erst erstellt und anzeigt wenn sich der Benutzer erfolgreich angemeldet hat, also ein Verbindungsobjekt besteht und man das tatsächlich ”in der Hand” hat. Kann man sicher das Hauptfenster öffnen. Und da dann beim erstellen auch einfach das Verbindungsobjekt mit übergeben.