Code wird nicht ausgeführt / Ablaufverfolgung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Verstehe die Welt nicht, warum wird der Code nicht ausgeführt. Das Programm:

Code: Alles auswählen

#!/usr/bin/env python3
#-*- coding: UTF-8 -*-

import sys
import sqlite3
from PyQt4.QtGui import QApplication, QFileDialog, QTableWidget
from PyQt4.uic import loadUi

#globale Variablen ????? Sichtbarkeit?
version         = {'name':'SQLiteGUI',
                   'version':'0.1 alpha'}



def main():
    debug       = True
    conn        = None          #DatabaseConnection
    cur         = None          #Database Cursor
    app         = QApplication(sys.argv)
    window      = loadUi("mainwindow.ui")
  

    def version():
        return version

    def debugMessage(s):
        if debug:
            print(s)

    def getDatabaseName(s):
        return QFileDialog.getOpenFileName(window,'Get Database File Name',s)

    def setDatabaseName(s):
        window.lineEditDBName.setText(s)

    def getDbMode():
        dbMode     = 'ro'
        if window.cbDBwriteMode.checkState():
            dbMode = 'rw'
        if window.cbDBcreateMode.checkState():
            dbMode = 'rwc'
        debugMessage('dbMode = ' + dbMode)
        return dbMode

    def getDBTables():  #triggers too
        debugMessage('getDBTables')
        cur.exec(''' select type, name from sqlite_master where type in ('table','trigger') order by type, name;   ''')
        r = 0
        for value in cur.fetch_all():        
            window.tableWidgetDB.setItem(r,0,value[0])
            window.tableWidgetDB.setItem(r,1,value[1])
            debugMessage(value)
            r +=1
        
    def OpenDB():      # auch für reopen zuständig
        debugMessage('openDB')
        s        = 'file:' + window.lineEditDBName.text() + '?mode=' + getDbMode()
        debugMessage('s=',s)
        conn     = sqlite3.connect(s, uri=True)
        cur      = conn.cursor()


    def initializeDB():
        debugMessage("initializeDB")
        OpenDB
        debugMessage('done (001)')
        getDBTables
        debugMessage('done (002)')
        
    #ui file einbinden    
    window.buttonDBSelect.clicked.connect(getDatabaseName)
    window.pushButtonDBOpen.clicked.connect(initializeDB)

    ####################################
    s = getDatabaseName('/usr/data/digikam')
    setDatabaseName(s)
                                                                                   

    window.show()
    sys.exit(app.exec_())



if __name__ == '__main__':
  main()


Sobald ich die Schaltfläche pushButtonDBOpen klicke kommt diese Ausgabe in der Shell

Code: Alles auswählen

>>> 
initializeDB
done (001)
done (002)
>>>
Wo liegt nur mein Fehler?

Frage am Rande, gibt es in Idle eine Programmablaufverfolgung (Einzelschritt)? Außer Breakpoints habe ich da noch nichts gesehen.
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@hans: der Code wird ausgeführt, aber Deine Erwartung, was Python da macht, ist eine andere, als die von Python. Einen Namen zu suchen "OpenDB" ist etwas anderes als eine Funktion auszuführen "OpenDB()".

Dein ganze Programm ist vom Design her falsch. Funktionen innerhalb von anderen Funktionen zu definieren ist im Allgemeinen nicht sinnvoll. Du benutzt globale Variablen und Deine Funktionen sind meistens nur Code-Abschnitte mit Namen. Bei GUI-Programmierung ist es eigentlich fast immer nötig, Klassen zu schreiben. Schreib Dein Programm nochmals neu und verwende dafür eine Main-Window-Klasse. Versuche dabei auch, die Datenbankzugriffe vom GUI-Zustand besser zu trennen.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

@Sirius, jetzte verlangst du (fast) unmögliches von mir :wink: Wäre ja froh, wenn ich einen prozedurales Programm hin bekäme. Aber lass mich deinen Vorschlag mal versuchen. Wie zu erwarten habe ich bei der Klassendefinition die ersten Schwierigkeiten. Hier mal der Anfang eines Beispiels von Stackoverflow.

Code: Alles auswählen

import sys
from PyQt4 import QtGui


class Example(QtGui.QMainWindow):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):               

        self.statusBar().showMessage('Ready')

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Statusbar')    
        self.show()
wie binde ich jetzt meine im QT Creator erstellte Oberfläche mit loadui(.....) ein? Passiert das in der def initUI(self)? Als Basisklasse wird im QT Creator QDilaog verwendet.
BlackJack

@hans: Die `initUI()` würde ich weglassen weil eine `__init__()` die nur aus zwei Zeilen besteht und alles andere in einer anderen Methode irgendwie nicht viel Sinn macht.

Wie/wo Du die *.ui-Datei aus dem Designer einbindest kommt darauf an, nun ja wie Du die einbinden möchtest. Da gibt es mehrere Möglichkeiten. Wenn das Exemplar Deiner Klasse damit initialisiert werden soll, dann muss das vom gleichen Typ wie das Widget aus dem Designer sein und dann musst Du das Exemplar bei `loadui()` als zweites Argument übergeben und dann bitte nicht den Rückgabewert der Funktion an ein Attribut binden. Sieht man öfter, macht aber keinen Sinn und verwirrt mehr. Oder Du schreibst eine Klasse die selber kein Widget ist und bindest das Ergebnis vpn `loadui()` an ein Attribut. Das heisst üblicherweise `ui`.

Warum Stackoverflow und nicht die PyQt-Dokumentation? IIRC sind da Beispiele drin.

Wenigstens die Grundlagen von OOP würde ich aber erst einmal ohne so ein riesen GUI-Rahmenwerk lernen das OOP eigentlich schon als Voraussetzung hat.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Mir raucht die Birne. 2 1/2 Stunden mit meinem simplen Code herumgeschlagen. Die Dokumentationen über Klassendefinition ist ja wohl ein bisschen zu simpel (nicht nur auf Python.org). Scheinbar komme ich so langsam dahinter. Habe mich streng an das Simpelst-Beispiel von QT gehalten. Also doch wieder eine Datei mit pyuic generieren statt loadUi zu verwenden. Taucht allerdings ein neues Problem auf. Keine Fehlermeldungen mehr aber das Layout kollabiert. Alles links oben in der Ecke auf wenige Pixel zusammen geschoben.

Erst mal Pause.

Code: Alles auswählen

import sys
from PyQt4 import QtGui, QtCore
import SQLiteGUI

class SQLiteGUI_CLA(QtGui.QMainWindow):
    def __init__(self):
        super(SQLiteGUI_CLA, self).__init__()
        self.ui = SQLiteGUI.Ui_MainWindow()
        self.ui.setupUi(self)

    def setupUi(self):
        self.ui.buttonDBSelect.clicked.connect(getDatabaseName)
        self.ui.pushButtonDBOpen.clicked.connect(initializeDB)

    def initializeDB():
        pass
    
    def getDatabaseName():
        pass
        

app = QtGui.QApplication(sys.argv)

my_mainWindow = SQLiteGUI_CLA()
my_mainWindow.show()

sys.exit(app.exec_())
Folgender Code wurde von pyuic generiert. Poste allerdings nur den Anfang der Datei

Code: Alles auswählen

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

# Form implementation generated from reading ui file 'SQLiteGUI.ui'
#
# Created by: PyQt4 UI code generator 4.11.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(1078, 549)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
        MainWindow.setSizePolicy(sizePolicy)
        MainWindow.setToolTip(_fromUtf8(""))
        self.gridLayout = QtGui.QGridLayout(MainWindow)
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.frame_2 = QtGui.QFrame(MainWindow)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(2)
        sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth())
        self.frame_2.setSizePolicy(sizePolicy)
        self.frame_2.setFrameShape(QtGui.QFrame.StyledPanel)
        self.frame_2.setFrameShadow(QtGui.QFrame.Raised)
        self.frame_2.setObjectName(_fromUtf8("frame_2"))
        self.verticalLayout = QtGui.QVBoxLayout(self.frame_2)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.tabWidget = QtGui.QTabWidget(self.frame_2)
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.tab = QtGui.QWidget()
        self.tab.setObjectName(_fromUtf8("tab"))
        self.tabWidget.addTab(self.tab, _fromUtf8(""))
        self.tab_2 = QtGui.QWidget()
        self.tab_2.setObjectName(_fromUtf8("tab_2"))
        self.tabWidget.addTab(self.tab_2, _fromUtf8(""))
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@hans: hast Du schon das Offensichtliche versucht?

Code: Alles auswählen

import sys
from PyQt4 import QtGui, QtCore

class SQLiteGUI_CLA(QtGui.QMainWindow):
    def __init__(self):
        super(SQLiteGUI_CLA, self).__init__()
        loadUi('mainwindow.ui', self)
        self.buttonDBSelect.clicked.connect(getDatabaseName)
        self.pushButtonDBOpen.clicked.connect(initializeDB)

    def initializeDB():
        pass
    
    def getDatabaseName():
        pass
        
def main():
    app = QtGui.QApplication(sys.argv)
    main_window = SQLiteGUI_CLA()
    main_window.show()
    sys.exit(app.exec_())
    
if __name__ == '__main__':
    main()
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
2 1/2 Stunden mit meinem simplen Code herumgeschlagen.
BlackJack hat's ja schon gesagt - GUI-Programmierung ist eben _nicht_ der richtige Weg, um ein simples Problem zu lösen. Weil: Selbst die simpleste GUI braucht 10-15 Zeilen zusätzlich Code _und_ setzt voraus, dass man ein grundlegendes Verständnis von Objektorientierung unter Python, Instanzierung von Klassen, Methodenaufrufen etc. hat. Wenn du mit Python anfängst kann das ziemlich viel auf einmal sein.

Also besser - was ja auch schon gesagt wurde - das Problem trennen, also erst den DB-Teil pythonisch-funktionierend haben und dann ggf. die GUI drüber setzen.

Gruß, noisefloor
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

schnell noch Code von Sirius ausprobiert. Bis auf kleine Fehler ging es , aber die Implementierung von Signal / Slot mag das Programm überhaupt nicht. Meint, die Funktionen wären nicht definiert. Gibt es in Python wie in Delphi die Möglichkeit der Forward-Deklaration?

@noisefloor: so ganz unbeleckt bin ich auch nicht. Habe sogar schon Pythonscripts in GIMP geschrieben, habe aber die letzten vier Jahre nichts gemacht. Liegt momentan ziemlich viel Wissen im Verborgenen. SQL kenne ich ziemlich gut. Speziell den Select-Befehl haue ich der Datenbank die Scripts um die Ohren, dass sie richtig was zu tun hat. Ich behaupte, dass mein SQL Code verständlicher ist als das was man in irgendeiner GUI zusammen klicken kann. Thema Klammerung in Verbindung mit and, or, in, etc.

Und auch schon angedeutet, ich komme von Delphi. Und irgendwann muss man sich ja mal mit der GUI unter Python beschäftigen.
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@hans: das sind so copy-paste-Fehler. Methoden muß man verständlicherweise über die Instanz referenzieren:

Code: Alles auswählen

        self.buttonDBSelect.clicked.connect(self.getDatabaseName)
        self.pushButtonDBOpen.clicked.connect(self.initializeDB)
BlackJack

@hans: „Forward Deklarationen“ gibt es nicht weil es in Python gar keine Variablen-, Funktions- oder Klassendeklarationen gibt¹. Die Namen werden zur Laufzeit aufgelöst, und wenn ein Name zu dem Zeitpunkt an dem er *benutzt* werden soll, nicht definiert ist, nützt einem ja auch keine „Forward Deklaration“ mehr die verspricht das ein Name irgendwann mal definiert wird. Denn auch dann wäre es zu spät wenn man das nicht vor dem ersten lesenden Zugriff auf einen Namen machen würde.

____
¹ Stimmt nicht ganz: ``global`` und `__future__`-Importe kann man als Deklarationen im klassischen Sinn ansehen.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

So langsam ist Land in Sicht. Nur noch zur Klarstellung wie Signal / Slots zu Fuß erstellt werden. Habe das aus der vom pyuic generierten Datei gezogen

Code: Alles auswählen

        ##### Signals and Slots ###########
        #Button bei Klick
        self.connect(self.buttonDBSelect,
                     QtCore.SIGNAL("clicked()"),
                     self.selectDatabase)
        #Checkbox bei Zustandsänderung
        self.connect(self.cbDBwriteMode,
                     QtCore.SIGNAL("toggled(bool)"),
                     self.setDatabaseMode)
         ###################################
BlackJack

@hans: Warum sollte man das so machen wollen? Die `connect()`-Methode von den Signalobjekten ist kürzer hingeschrieben und auch sicherer weil man sofort beim Verbinden Rückmeldung bekommt ob das Signal überhaupt existiert.
Antworten