Button/Funktion eines 2ten Fensters benutzen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Shiva420
User
Beiträge: 12
Registriert: Dienstag 16. Februar 2016, 01:42

Abend Leute!

Ich hänge leider grad ziemlich fest und habe gehofft dass ihr mir weiterhelfen könnt.
Ich habe mehrere Fenster welche sich auf Knopfdruck öffnen, jedes davon hat mind. 1 Knopf mit dem ich die Form wieder schließen möchte und bestenfalls noch eingegebene Werte an die Main übermitteln kann.
Allerdings schaffe ich es nicht den Button mit einer Funktion zu versehen sodass diese dann ausgeführt wird.

Meine Main (gekürzt):

Code: Alles auswählen

import [...]

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
    
        self.pushButton_5.clicked.connect(self.openPrefer)
        
    def openPrefer(self):
        global third
        third = Prefer.PreferForm()
        third.show()
[...]

Meine zweite Form (gekürzt):

Code: Alles auswählen

from PyQt4 import QtCore, QtGui
[...]
class Ui_PreferForm(object):
    def setupUi(self, PreferForm):
  	[...]
        self.Done = QtGui.QPushButton(PreferForm)
        self.Done.setGeometry(QtCore.QRect(108, 300, 71, 31))
        self.Done.setObjectName(_fromUtf8("Done"))
	[...]
        self.retranslateUi(PreferForm)
        QtCore.QMetaObject.connectSlotsByName(PreferForm)

class PreferForm(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_PreferForm()
        self.ui.setupUi(self)

    def pressDone(self):
        print("Test")
        
Ich habe zum testen einfach mal die Funktion pressDone erstellt um überhaupt einmal Leben in die Sache zu bekommen.
Nun habe ich allerdings schon diverse Wege versucht diese funktion auszuführen, meist bekomme ich errorcodes bezüglich eines Signals bzw Nonetype.

Ich hoffe ihr könnt mir weiterhelfen, ich hole mir jetzt erst einmal eine Mütze schlaf, vielleicht geht es danach ja besser! :D
Vielen Dank!
BlackJack

@Shiva420: ``global`` ist, mal ganz unabhängig vom Problem, ein Warnzeichen. Wenn Du das in einem objektorientierten Programm nicht anders gelöst bekommst, dann stimmt etwas mit dem Entwurf nicht.

Der generierte Code-Schnippsel für das zweite Widget („Form“ ist irgendwie eine andere Programmiersprache) zeigt, dass Du die Schaltfläche absolut positioniert hast, statt ein Layout zu verwenden. Das solltest Du ändern. Das ist auch eine andere Programmiersprache, beziehungsweise ein vergangenes Jahrhundert. ;-)

Das Du Quelltext für die GUI generieren lässt ist auch etwas komisch, das macht man bei PyQt eigentlich nicht, denn man kann mit dem `PyQt4.uic` die `*.ui`-Dateien zur Laufzeit laden und sich den Zwischenschritt mit dem Code generieren sparen.

Falls `Prefer` für `Preferences` stehen sollte: Abkürzungen sollte man vermeiden. Der Leser sollte nicht raten müssen was ein Name bedeutet, sondern es an dem Namen ablesen können. Dafür ist der Name ja da.

Zum eigentlichen Problem: Was *genau* versuchst Du denn? Und welche Fehlermeldungen bekommst Du denn *genau*. Ausnahmen bitte 1:1 mit Traceback, sonst müssen wir hier herumraten.

Man sieht aus dem Code nicht welchen Typ ”Form” hat — ist das ein `QDialog`? Dann könnte man das `finished`-Signal verwenden. Und vielleicht siehst Du die Sache von der falschen Richtung aus wenn Du etwas von einem untergeordneten Fenster an ein übergeorndetes schicken willst, statt Daten vom übergeorndeten Fenster aus vom untergeordneten abzufragen.
Shiva420
User
Beiträge: 12
Registriert: Dienstag 16. Februar 2016, 01:42

Ich gebe zu ich muss mich bezüglich OOP noch mal etwas hinsetzen, habe Python allerdings auch erst vor 1-2 Wochen angefangen. :lol:
Wenn ich richtig Informiert bin dient ein Layout z.B. für eine gleichmäßige Vergrößerung aller Elemente sobald ich das Fenster größer ziehe - oder?
Das möchte ich nämlich überhaupt nicht, eine fixe größe passt mir super. :wink:
Zur laufzeit kann man die .ui dateien laden? :shock: Ich habe überall gelesen ich müsste die per cmd -> pyuic design.ui -o design.py umformen um damit arbeiten zu können, hatte so eig. auch noch keine probleme. :K
Prefer steht regelrecht für das englische wort Prefer :lol: Es geht darum gewisse Spielboard Tiles anderen zu bevorzugen, diese sollen dann im zweiten Widget sozusagen ausgewählt werden, ich habe dafür 25 Buttons (1 spielboard) mit angepasstem Icons dort eingefügt, muss nur noch rausfinden wie ich die Buttons mit Aktionen verknüpfen kann, um bei anklicken der Buttons einmal ihr Bild zu ändern (als anklick bestätigung) und am ende die angeklickten Tiles an die erste Form zu übergeben. (Welche angeklickt wurden)
Ich benutze QWidgets als Fenster, außer natürlich für Main.

Ich werde sofort versuchen den Fehler noch einmal per Konsole ausgeben zu lassen, dann editiere ich es hier nach. :)


Edit:
Ich habe eben gesehen dass "Test" in der Konsole ausgegeben wird sobald ich den Button klicke der eig. das zweite Fenster öffnen sollte. Das Zweite fenster wird dabei nicht geöffnet. Ich scheine also irgendwie die Funktion meines zweiten Fensters im ersten aufzurufen, anstatt das zweite Fenster öffnen zu können und dort die funktion aufrufen zu können.
Dieser Fehler hier tritt dabei auf, wie kann ich damit umgehen?

Traceback (most recent call last):
File "C:/Users/Sync/PycharmProjects/Satoshi Mines Bot/Satoshi Mines Bot.py", line 571, in openPrefer
third = Prefer.PreferForm()
File "C:\Users\Sync\PycharmProjects\Satoshi Mines Bot\Prefer.py", line 226, in __init__
self.ui.setupUi(self)
File "C:\Users\Sync\PycharmProjects\Satoshi Mines Bot\Prefer.py", line 212, in setupUi
self.pushButton.clicked.connect(PreferForm.pressDone())
TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'

Hier der Code von meinem zweiten Fenster

Code: Alles auswählen

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_PreferForm(object):
    def setupUi(self, PreferForm):
        PreferForm.setObjectName(_fromUtf8("PreferForm"))
	[...]
        self.pushButton.clicked.connect(PreferForm.pressDone())

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

    def retranslateUi(self, PreferForm):
        [...]

class PreferForm(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_PreferForm()
        self.ui.setupUi(self)

    def pressDone(self):
        print("Test")
BlackJack

@Shiva420: Layouts sind hauptsächlich dafür da, dass sich die Widgetgrösse dem Inhalt anpasst und die Position automatisch relativ zu den anderen Widgets gesetzt wird, deren Grösse ja auch wieder vom Inhalt abhängt. Fixe Positionen und Grössen mögen Dir prima passen, auf anderen Rechnern mit anderen Randbedingungen mag das allerdings dann anders aussehen, bis hin zur Unbenutzbarkeit Deiner GUI. Das hat früher mal mehr oder weniger gut funktioniert, solange man sich auf ein Betriebssystem beschränkt hat und das dann auch bei jedem Monitor fast die gleiche Auflösung hatte und die Benutzer nichts an den Einstellungen geändert haben, weil dann bestimmte Programme eine kaputte Anzeige hatten — eben weil die Programmierer fixe Positionen und Grössen verwendet haben. Bei dem heutigen Zoo von Systemen, Bildschirmauflösungen, und Benutzern die durchaus etwas an den Einstellungen ändern, kann man sich das nicht mehr erlauben. Ausserdem hat man weniger Arbeit wenn man die GUI verändern will, wenn man beispielsweise irgendwo ein Widget einfügen oder weglassen möchte, oder den Inhalt ändern so dass sich die Wigdetgrösse änder, und man dann nicht von Hand alle anderen betroffenden Widgets verschieben muss, sondern sich das Layout darum kümmert.

Ob der Benutzer Fenster vergrössern kann/will ist eine Frage die davon erst einmal unabhängig ist. Da kann man ja ganz einfach sagen das Fenster so eine Möglichkeit gar nicht erst anbieten sollen.

Doch Du hattest schon ”Probleme” mit dem generieren von Quelltext: Du musst das halt jedes mal machen wenn Du die ui-Datei verändert hast. Das ist ein zusätzlicher Arbeitsschritt den man machen muss und den man später irgendwie in den Build-Prozess integrieren muss. Es sei denn man stellt die generierten UI-Dateien auch in die Versionsverwaltung, was aber unschön ist, weil generierte/redundante Daten dort eigentlich nichts zu suchen haben.

Wenn es ein semantisch ein Dialog ist, sollte man überlegen `QDialog` zu verwenden. Und wie schon gesagt würde ich nicht versuchen von dem untergeordneten Dialog etwas ans Hauptfenster zu senden (ausser maximal ein Signal das man fertig ist (`finished` bei `QDialog`)) sondern die Daten vom Haupfenster-Code aus vom Dialog abzufragen.

Die Ausnahme will Dir sagen das Du `connect()` etwas aufrufbares (z.B. Funktion oder Methode) übergeben musst und nicht `None`. Du rufst an der Stelle `pressDone()` auf, und das hat `None` als Rückgabewert, und das wird dann an `connect` übergeben. Was Du übergeben musst ist die Methode selbst. Und zwar die Methode auf einem Exemplar und nicht die ungebundene Methode auf der Klasse. Ich bin mir jetzt nicht so ganz sicher ob das selbst geschriebener oder genrierter Code ist‽ Und schreibst Du da eigenen Code in den generierten Quelltext? Das solltest Du bleiben lassen, davor sollte eigentlich auch ein Kommentar im generierten Code deutlich abraten. Und erwähnte ich schon mal das man eigentlich keinen Quelltext generiert wenn das nicht sein muss? ;-)
Shiva420
User
Beiträge: 12
Registriert: Dienstag 16. Februar 2016, 01:42

Dann sollte ich mich doch mal mit Layout in Zukunft beschäftigen, hört sich Sinnvoller an als ich mir vorgestellt habe. :)
Stimmt eig. wenn ich mir das umformen von .ui auf .py sparen würde hätte ich es sehr viel einfacher wenn ich in der .ui etwas ändere.
Und ja, ich schreibe ich den von pyqt generierten Code. :oops:
Ich denke ich sollte mich noch mal hinsetzen und das ganze irgendwie etwas tiefer mir anschauen und lernen, ich bin doch noch ziemlich verwirrt wenn es zu mehreren Fenstern/Datein kommt :K
BlackJack

@Shiva420: Mal eine Rückfrage zu dem Sinn des Dialogs: Soll der Benutzer da Felder markieren können, welche von dem Bot bevorzugt gewählt werden sollen? Falls ja, was ist die Idee dahinter? Denn wenn ich mir das Spiel so anschaue, ist die einzige Möglichkeit mit der sich der Betreiber der Webseite einen (zusätzlichen) Vorteil verschaffen könnte, genau das: Benutzer die nicht rein zufällig agieren. Also ist das bevorzugen von ausgewählten Feldern eigentlich eine schlechte Idee. Noch dazu wenn der Benutzer die auswählen kann. Denn das werden Benutzer dann tun, entweder weil sie das Muster mögen, oder weil sie denken eines in den Spielfeldern vom Betreiber entdeckt zu haben. Dummerweise entdecken Menschen sehr gerne und sehr leicht Muster auch in völlig zufälligen Daten die gar nicht existieren. Das Gehirn spielt einem da Streiche. Dazu kommt das die meisten Menschen notorisch falsche Vorstellungen von Zufall und Wahrscheinlichkeiten haben.
Antworten