QTextEdit auf QLabel abbilden

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Friedericus
User
Beiträge: 25
Registriert: Dienstag 21. September 2010, 14:59

Hi Leuts,

Ich komm hier grad nicht weiter:
Ich möchte den inhalt von TextEdit auf label abbilden lassen, sobald Enter gedrückt wird, aber alles was ich ausprobiert hab, führt nur zu Fehlermeldungen. Hat jemand ne Idee wie das geht?

Code: Alles auswählen

def groupTextEdit(self, title, text):
        group = QtGui.QGroupBox(title)          #title der Box
        layout = QtGui.QVBoxLayout()            #layout der Box
        textEdit = QtGui.QLineEdit(text)    #Line-Edit Feld
        label = QtGui.QLabel()
        textEdit.resize(10, 50)                 #Groesse des LineEdit festlegen
        label.resize(10, 50)
        layout.addWidget(textEdit)              #LineEdit dem Layout hinzufuegen
        layout.addWidget(label)
        group.setLayout(layout)                 #die GroupBox mit dem Layout versehen
        group.connect(textEdit, QtCore.SIGNAL('returnPressed()'),'Hier sollte die Funktion hin')
        return group                            
lunar

Wieso nicht einfach "textedit.returnPressed.connect(label.setText)"? Was ist daran so schwer?

Im Übrigen wäre es zukünftig ganz nett, wenn Du die Fehlermeldungen selbst auch zeigst ;) Dann müssen wir weniger raten.
Friedericus
User
Beiträge: 25
Registriert: Dienstag 21. September 2010, 14:59

hmm mach ich das spuckt er mich sobald ich enter drück

Code: Alles auswählen

TypeError: QLabel.setText(QString): not enough arguments
aus.

wenn ich das so

Code: Alles auswählen

textEdit.returnPressed.connect(label.setText(text))
umbau, kommt mir folgende Fehlermeldung:

Code: Alles auswählen

TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Friedericus hat geschrieben:hmm mach ich das spuckt er mich sobald ich enter drück

Code: Alles auswählen

TypeError: QLabel.setText(QString): not enough arguments
aus.
returnPressed() hat ja auch keinen Rückgabewert. Insofern kann man imho dieses Signal nicht direkt mit einem Slot verbinden, welcher einen Parameter benötigt. Da hat lunar wohl nicht ganz aufgepasst oder er weiß mal wieder mehr als wir anderen ;-)
Friedericus hat geschrieben: wenn ich das so

Code: Alles auswählen

textEdit.returnPressed.connect(label.setText(text))
umbau, kommt mir folgende Fehlermeldung:

Code: Alles auswählen

TypeError: connect() slot argument should be a callable or a signal, not 'NoneType'
Na das ist ja auch logisch, da Du hier nicht die Funktion übergibst, sondern den Rückgabewert von "label.setText()"; und der ist eben None ;-)

Ich würde eben eine Funktion definieren, welche Du mit dem returnPressed-Signal verbindest und in der dann separat die setText()-Methode des Labels aufgerufen wird.

Im übrigen ist die Frage irreführend, da es sich hier ja nicht um ein QTextEdit handelt, sondern um ein QLineEdit-Element!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lunar

Verzeih mir, ich hatte nicht daran gedacht, dass "returnPressed()" kein Argument erhält. Du kannst stattdessen "textEdited()" verwenden: "lineedit.textEdited.connect(label.setText)". Oder Du musst eben eine eigene Funktion oder Methode schreiben, um den Text des Eingabefelds abzufragen, und dem Beschriftungsfeld zuzuweisen, welche Du dann mit dem "returnPressed()"-Signal verbinden kannst.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@lunar: Wäre es in so einer Situation eigentlich opportun, eine lambda-Funktion zu nutzen? Also etwa so:

Code: Alles auswählen

textedit.returnPressed.connect(lambda: label.setText(textedit.text))
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Friedericus
User
Beiträge: 25
Registriert: Dienstag 21. September 2010, 14:59

kk, und warum genau funktioniert die Funktion jetzt mit 'textEdited()' aber nicht mit 'returnPressed' ?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Friedericus hat geschrieben:kk, und warum genau funktioniert die Funktion jetzt mit 'textEdited()' aber nicht mit 'returnPressed' ?
Weil ersteres Signal einen QString (eben den Text des LineEdits) emittiert, den wiederum setText als Parameter benötigt. returnPressed() emittiert eben nichts und deswegen kann man es nicht direkt mit einem Slot verbinden, der einen Parameter benötigt!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
lunar

@Hyperion: Wieso sollte man keine "lambda"-Funktion nutzen? Es fehlen nur die Klammern in "textedit.text()" ;)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

lunar hat geschrieben:@Hyperion: Wieso sollte man keine "lambda"-Funktion nutzen? Es fehlen nur die Klammern in "textedit.text()" ;)
Oops, ja klar :oops:

Naja, mit lambda sollte man ja schon eher vorsichtig umgehen; in diesem Falle würde ich es eben so sehen, dass die "Relais"-Funktion im Grunde genommen keine Funktionalität kapselt, die man modular außerhalb dieses Problems noch mal brauchen würde. Ich wollte das nur mal von Dir bestätigt wissen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Friedericus
User
Beiträge: 25
Registriert: Dienstag 21. September 2010, 14:59

So, jetzt funktioniert alles soweit. Der Inhalt der Line-Edit wird auf dem Label abgebildet, allerdings hab ich keine Returnwerte, d.h.:

Code: Alles auswählen

        textEdit.returnPressed.connect(lambda: label.setText(textEdit.text()))
        print 'mit Klammer:', label.text()
        print 'Ohne Klammer:', label.text
bekomm ich folgendes zurück:

Code: Alles auswählen

mit Klammer: 
Ohne Klammer: <built-in method text of QLabel object at 0x01564588>
das ohne klammer ist klar, aber warum ist label.text() leer obwohl ich mit der lambdafunktion den Wert gerade gesetzt hab?
lunar

Der Text des Beschriftungsfeld wird nicht sofort gesetzt, sondern nur und ausschließlich dann, wenn Du im Eingabefeld die Eingabetaste drückst. Die erste Zeile Deines Beispiels beschreibt nur diese Verbindung, führt aber nicht dazu, dass der Text sofort aktualisiert wird. Das ist ja gerade der immanente Unterschied zwischen Signal-Slot-Verbindungen und normalen Methodenaufrufen, letztere werden ja sofort ausgeführt. Insofern ist dieses Ergebnis genau das, was gemäß des Quelltexts zu erwarten ist.

Das alles muss Dir klar sein, wenn Du Benutzeroberflächen mit Qt entwickeln möchtest.
Friedericus
User
Beiträge: 25
Registriert: Dienstag 21. September 2010, 14:59

lunar hat geschrieben:Der Text des Beschriftungsfeld wird nicht sofort gesetzt, sondern nur und ausschließlich dann, wenn Du im Eingabefeld die Eingabetaste drückst.
ja, das hab ich gemacht. Etwas ins LineEdit eingegeben, danach die Entertaste gedrückt.
Der text wird auch so wie er soll auf dem Label abgebildet, jedoch wird Label.text() eben nicht mit dem String gesetzt.
Aber ich weiß nicht warum. :K
lunar hat geschrieben:... und normalen Methodenaufrufen, letztere werden ja sofort ausgeführt. Insofern ist dieses Ergebnis genau das, was gemäß des Quelltexts zu erwarten ist.
ja es ist ja genau so beabsichtigt. Dass eben die Funktion nicht sofort ausgeführt werden soll, sondern eben nur wenn ich Enter betätige.
lunar

@Friedericus: Nun, aus dem Quelltext, den Du in Deinem Beitrag gezeigt hast, geht das alles nicht hervor. Wenn Du sinnvolle Antworten möchtest, dann musst Du auch den Quelltext zeigen, mit dem dieser Quelltext auftritt, und nicht irgendeinen wahlfreien Zusammenschnitt.

Insofern bleibt es auch jetzt bei allgemeinen Aussagen: "QLabel.text()" gibt immer zurück, was das betreffende Beschriftungsfeld anzeigt. Wenn der Aufruf von ".text()" bei Dir nichts zurückgibt, dann rufst Du ".text()" offenbar auf dem falschen Objekt auf.
Friedericus
User
Beiträge: 25
Registriert: Dienstag 21. September 2010, 14:59

ok, dann hier mal der gesamte Code:

Code: Alles auswählen

from PyQt4 import QtGui, QtCore
import TCPIP_server_Auftragsmodul_v11_units


import sys



class ServerGui(QtGui.QMainWindow):             #Main Window erstellen
    def __init__(self, parent = None):
        self.ipAdress = ''
        self.distance = '10'
        QtGui.QMainWindow.__init__(self, parent)
        self.filename = 'H:/iwbDaten/TCPIP_Client/'
        self.data = ''
        central_widget = QtGui.QWidget()
        self.setCentralWidget(central_widget)
        grid = QtGui.QGridLayout()
        menu = self.menubar()
       # zeile = TCPIP_server_Auftragsmodul_v11_units.Server.start().zeile

        okButton = QtGui.QPushButton("OK")
        cancelButton = QtGui.QPushButton("Beenden")

        distance, self.distance = self.groupTextEdit('distance', self.distance)
        showData, self.filename = self.groupTextEdit('gewaehlte Datei', self.filename)
        progress = self.dateiBearbeiten(self.data)
        group = self.unitGroups(showData, distance, 'Datei einlesen')
        
        grid.addWidget(okButton, 60, 49)
        grid.addWidget(cancelButton, 60, 48)
        grid.addWidget(progress, 20, 10, 20, 40)
        grid.addWidget(group, 10, 10, 10, 40)
       
        central_widget.setLayout(grid)
        self.setWindowTitle('Server')
        self.resize(250, 350)
        
        self.connect(cancelButton, QtCore.SIGNAL('clicked()'), QtCore.SLOT('close()'))
        self.connect(okButton, QtCore.SIGNAL('clicked()'), self.startServer)
  
  
    def startServer(self):
        server = TCPIP_server_Auftragsmodul_v11_units.Server(self.filename, self.distance)
        start = server.start()                                  #Datei, Distance
        return start                                            #H:/iwbDaten/TCPIP_Client/" 
    
    def createWidgets(self):
        central_widget = QtGui.QWidget()
        widget = self.setCentralWidget(central_widget)
        return widget
    

    '''
    ----------MENUBAR-----------
    Erstellt die Menuebar
    Es wird eine Menubar erstellt,
    sowie zwei Funktionen hinzugefuegt:
    OPEN: oeffnet ein File und zeigt den Dateipfad an
    EXIT: Beendet das Programm
    '''
    def menubar(self):                          
        exit = QtGui.QAction(QtGui.QIcon('icons/exit.png'),         #Erstellt die Exit-Schaltflaeche
                              'Exit', self)       
        exit.setShortcut('Ctrl+Q')                                  #weist den Shortcut zu
        self.connect(exit, QtCore.SIGNAL('triggered()'),            #Verbindet die Schaltflaeche 
                        QtCore.SLOT('close()'))                     #mit der close-Anweisung
        
        open = QtGui.QAction(QtGui.QIcon('open.png'),               #Erstellt die Exit-Schaltflaeche
                              'Open', self)             
        open.setShortcut('Ctrl+O')                                  #weist den Shortcut zu
        open.setStatusTip('Open new File')
        self.connect(open, QtCore.SIGNAL('triggered()'),            #Verbindet die Schaltflaeche mit der 
                      self.openFile)                                #openFile-Anweisung
        
        menubar = self.menuBar()                                    #Erstellt eine Menubar      
        file = menubar.addMenu('&Datei')                            #Fuegt ein Menu hinzu
        file.addAction(open)                                        #Open-Button hinzufuegen
        file.addAction(exit)                                        #Exit-Button hinzufuegen
        
   
        
    '''
    ---------OPENFILE---------
    Erstellt den Dialog zum oeffnen des Files
    Hier wird der 'FileOpen'-Dialog erzeugt
    die Daten werden an self.file uebergeben
    Der Dateipfad wird auf dem 'Datei Anzeigen-Label angezeigt
    '''
    def openFile(self):                         
        filename = QtGui.QFileDialog.getOpenFileName(self,'Ordner wählen', '', "*.cli")#Dialog aufrufen 
        file = open(filename)                                                   #Datei oeffnen
        self.data = file.read()                                                 #Datei auslesen
        self.filename = filename                                                #Filename setzen
        self.lab.setText(self.filename)                                         #Dateipfad anzeigen
        
        
    '''
    ---------GROUPLABEL-----------
    Erstellt einen Gruppenkasten mit Label
    Hier wird ein Label erzeugt, welches 
    in eine Group-Box eingebettet wird
    '''
    def groupLabel(self, title, label):
        group = QtGui.QGroupBox(title)          #title der Box
        layout = QtGui.QVBoxLayout()            #layout der Box
        self.lab = QtGui.QLabel(label)          #Label ACHTUNG: label ist self, da hier der Pfad abgebildet wird
        layout.addWidget(self.lab)              #Label dem Layout hinzufuegen
        group.setLayout(layout)                 #die Groupbox mit dem Layout versehen
        return group                            #Gruppe returnen
    
    
    '''
    ---------groupTextEdit-----------
    Erstellt einen Gruppenkasten mit TextEdit
    Hier wird ein Edit-Zeile erzeugt, welches 
    in einer Group-Box eingebettet wird
    '''
    
    def groupTextEdit(self, title, text):
        group = QtGui.QGroupBox(title)          #title der Box
        layout = QtGui.QVBoxLayout()            #layout der Box
        textEdit = QtGui.QLineEdit(text)        #Line-Edit Feld
        label = QtGui.QLabel()
        textEdit.resize(10, 50)                 #Groesse des LineEdit festlegen
        label.resize(10, 50)
        layout.addWidget(textEdit)              #LineEdit dem Layout hinzufuegen
        layout.addWidget(label)
        group.setLayout(layout)                 #die GroupBox mit dem Layout versehen
        textEdit.returnPressed.connect(lambda: label.setText(textEdit.text()))
        print 'mit Klammer:', label.text()
        print 'Ohne Klammer:', label.text
        returnText = label.text()
        return group, returnText               #Gruppe returnen
    
    #def setText(self):
       # label = ''
        #text = self.distance
        #label.setText(text.text)


    '''
    ----------UNITEGROUPS------------
    fasst beide Gruppen zusammen 
    und fasst sie in eine Horizontales
    Layout zusammen
    '''
    def unitGroups(self, group1, group2, title):

        group = QtGui.QGroupBox(title)          #Gruppe erstellen
        layout = QtGui.QHBoxLayout()            #Layout erstellen
        layout.addWidget(group1)                #Gruppe1 hinzufuegen
        layout.addWidget(group2)                #Gruppe2 hinzufuegen
        #layout.addWidget(group3)
        group.setLayout(layout)                 #Gruppe das Layout hinzufuegen
        return group                            #Gruppe returnen
     
    
    ############
    #erstellt Die Gruppe die die Arbeitsschritte darstellt
    ############
    '''
    -------DATEIBEARBEITEN---------
    Hier wird die Gruppe erstellt 
    die Informationen ueber den Arbeitsablauf gibt.
    Sie beinhaltet:
    PBAR:         Prozentbalken
    PPROGRESS:    Information welche Zeile aufgetragen wird
    PSHOW:        Zeigt den Momentan durgefuehrten Arbeitsablauf
    '''   
    def dateiBearbeiten(self, data):
        group = QtGui.QGroupBox('Datei bearbeiten')             #Gruppenkasten hinzufuegen
        plab = QtGui.QLabel('Fortschritt:')                     #Label hinzufuegen
        pbar = QtGui.QProgressBar(self)                         #Prozentleiste erstellen
        pprogress = QtGui.QLabel('Es wird Zeile  %d  von  %e  aufgetragen') #Aktuelle Zeile dartellen
        pshow = QtGui.QTextEdit(data)                 #Anzeige fuer den gegenwaerteigen Arbeitsschritt
        plab1 = QtGui.QLabel('Arbeitsschritt:')                 #Label fuer das Textfeld
        
        progress = QtGui.QVBoxLayout()                          #Erstellt das Layout
        
        progress.addWidget(plab)                                #fuegt die Widgets dem Layout hinzu
        progress.addWidget(pbar)
        progress.addWidget(pprogress)
        progress.addWidget(plab1)
        progress.addWidget(pshow)
        
        group.setLayout(progress)                               #der Gruppe das Layout hinzufuegen
        return group    


app = QtGui.QApplication(sys.argv)                              #Main-Methode
ex = ServerGui()
ex.show()
sys.exit(app.exec_())
und wie gesagt, Der Text wird auf dem Label abgebildet, label.text() jedoch bleibt leer.
lunar

Für diesen Quelltext gilt das oben Gesagte.

"label.text()" gibt den Inhalt des Beschriftungsfeld zum Zeitpunkt des Aufrufs zurück. Dieses Objekt wird nicht "magisch" aktualisiert, wenn sich der Text ändert. Außerdem geschieht dieser Aufruf bei Dir zu einem Zeitpunkt, an dem das Fenster nicht einmal vollständig initialisiert ist, dementsprechend ist der Text immer leer. Du darfst den Text des Beschriftungsfelds natürlich erst dann abfragen, wenn es einen Inhalt hat, also sprich, nachdem der Benutzer die Eingabetaste betätigt hat.

Im Allgemeinen verstehe ich auch nicht, wieso Du unbedingt den Text des Beschriftungsfelds abfragen möchtest, anstatt direkt den Text des Eingabefelds zu nehmen.

Jedenfalls offenbart die Tatsache, dass Du im gezeigten Quelltext die Ausgabe des Texts erwartest, grundlegende Verständnisschwierigkeiten im Signal-Slot-Konzept sowie im allgemein asynchronen Ablauf von ereignisorientierten Programmen, wie es jede Benutzeroberfläche ist. Auch andere Probleme im Quelltext wie beispielsweise die Verwendung absoluter Größenangaben, dem Namen "TCPIP_server_Auftragsmodul_v11_units" (?!) sowie manche Kommentare lassen vermuten, dass die für solche Programme nötigen Grundlagen fehlen. Lese also doch bitte die Einführungen und Tutorien in der Qt-Dokumentation.
BlackJack

@Friedericus: Du hast anscheinend grundsätzlich den Programmablauf bei GUIs nicht verstanden. In der vorletzten Zeile von der Funktion ermittelst Du den Inhalt von dem `label` zu dem Zeitpunkt wo diese Zeile ausgeführt wird. Und da steht in dem Label *tatsächlich* nichts drin. Dafür müsstest Du theoretisch zwischen der Abarbeitung der Zeile mit dem `connect()` und der vorletzten Zeile etwas eingetippt und die Eingabetaste gedrückt haben. Selbst das wäre aber nicht genug, denn da die GUI-Hauptschleife diese Ereignisse gar nicht verarbeiten kann, solange Deine Funktion da noch abgearbeitet wird, kann auch das Signal nicht verarbeitet werden.

Deine DocStrings sind übrigens keine -- dafür stehen sie an der falschen Stelle. Literale Zeichenketten sind nur dann DocStrings, wenn sie direkt *nach* einer ``def``- oder ``class``-Anweisung stehen.
Antworten