QFileDialog.getOpenFileName()

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
moe
User
Beiträge: 12
Registriert: Montag 30. Juni 2008, 18:00

Hallo Forum,

ich habe ein Problem mit QFileDialog. Ich möchte per getOpenFileName einen Dialog öffnen, in dem der Nutzer eine Datei auswählen kann. Ich habe eine kleine GUI mit dem Qt Designer erstellt, und dann die resultierende ui-Datei per pyuic5 in Python-Code umgewandelt. Hier ist der Code:

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.button = QtWidgets.QPushButton(self.centralwidget)
        self.button.setGeometry(QtCore.QRect(40, 40, 91, 21))
        self.button.setObjectName("button")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setGeometry(QtCore.QRect(170, 40, 113, 20))
        self.lineEdit.setObjectName("lineEdit")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 18))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.button.setText(_translate("MainWindow", "select file"))
        self.button.clicked.connect(openFile)

def openFile():
    filename, _ = QFileDialog.getOpenFileName(self, "Choose picture", "*.jpg")


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_())
    

Ich habe lediglich die Funktion openFile hinzugefügt, und diese mit dem Button verbunden.

Wenn ich jetzt aber das Skript ausführe und auf den Button klicke, wird anstelle eines öffnenden Dialogs die Anwendung beendet. Kann mir jemand sagen warum das nicht funktioniert?

Grüße

moe
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@moe: Nein das hast Du nicht lediglich getan. Du hast auch den Kommentar oben entfernt in dem steht das man diesen Quelltext nicht verändern soll.

Generieren von Code ist aber sowieso nicht das was man hier machen würde, sondern man würde die *.ui-Datei zur Laufzeit mit dem `PyQt5.uic`-Modul laden.

Die GUI verwendet absolute Grössen und Positionsangaben in Pixeln. Das macht man nicht. Qt hat verschiedene Layouts die man verwenden kann um eine GUI zu erstellen die überall funktioniert, und nicht auf Systemen mit gleichen oder zumindest ähnlichen Einstellungen wie dem auf dem man das mit den absoluten Pixelangaben mal erstellt hat.

`QFileDialog` ist undefiniert. Das führt aber zumindest bei mir nicht zu einem Programmabbruch sondern nur zu einer entsprechenden Fehlerausgabe auf der Konsole.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
moe
User
Beiträge: 12
Registriert: Montag 30. Juni 2008, 18:00

Hallo _blackjack_

ich habe jetzt nochmal ein ähnliches GUI mit einem GridLayout erstellt. Auch habe ich mit dem Modul uic die betreffende ui-Datei geladen. Hier ist der Code:

Code: Alles auswählen


from PyQt5 import QtWidgets, uic
from PyQt5.QtWidgets import QMainWindow, QFileDialog

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        
        w = uic.loadUi('main_win.ui', self)
        w.pushButton.clicked.connect(openFile)

def openFile():
    filename, _ = QFileDialog.getOpenFileName(self, "Choose picture", "*.jpg")


app = QtWidgets.QApplication([])
win = MyWindow()
win.show()
app.exec_()


Und hier ist der Code der ui-Datei:

Code: Alles auswählen



<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QWidget" name="gridLayoutWidget">
    <property name="geometry">
     <rect>
      <x>40</x>
      <y>30</y>
      <width>391</width>
      <height>311</height>
     </rect>
    </property>
    <layout class="QGridLayout" name="gridLayout">
     <item row="0" column="0" alignment="Qt::AlignLeft">
      <widget class="QPushButton" name="pushButton">
       <property name="text">
        <string>PushButton</string>
       </property>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>18</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

Leider führt dies aber bei mir immer noch zu einem Programmabbruch, wenn ich auf den Button klicke.
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@moe: Was heisst denn Programmabbruch genau? Was wird da auf der Konsole ausgegeben. Falls Du das nicht von der Konsole aus startest, dann solltest Du das tun, damit Du Fehlermeldungen sehen kannst.

Jetzt ist das Problem das `self` nicht definiert ist.

Das `My` bei `MyWindow` macht keinen Sinn wenn es nicht auch `OurWindow` oder `TheirWindow` gibt.

`w` ist kein guter Name und es macht auch keinen Sinn das an einen lokalen Namen zu binden *und* `self` als Argument an `loadUi()` zu übergeben weil dann ja schon die ganzen Attribute auf dem Objekt selbst gesetzt werden und durch das `w` nun zwei Wege zu den gleichen Attributen führen ohne das man sagen könnte welchen Weg man nun nehmen sollte.

"*.jpg" ist kein Verzeichnisname. Falls das als Filter sein sollte, dann muss das auch dem richtigen Argument übergeben werden und im passenden Format.

Code: Alles auswählen

#!/usr/bin/env python3
import sys

from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog


def open_file():
    filename, _ = QFileDialog.getOpenFileName(
        caption="Choose picture", filter="JPEG Images (*.jpg)"
    )
    if filename:
        print(filename)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("test.ui", self)
        self.pushButton.clicked.connect(open_file)


def main():
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    app.exec_()


if __name__ == "__main__":
    main()

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
moe
User
Beiträge: 12
Registriert: Montag 30. Juni 2008, 18:00

Hallo _blackjack_

vielen Dank für deine Hinweise. Bei mir hat das mit den Argumenten der Funktion getOpenFileName() nicht gestimmt. Jetzt funktioniert es auch bei mir.

Gruß

moe
Benutzeravatar
__blackjack__
User
Beiträge: 13533
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@moe: Du solltest aber auf jeden Fall mal zusehen das Du die Fehlermeldungen zu sehen bekommst die ich deswegen bekommen habe, denn ohne wird das mit der Fehlersuche echt schwer.

Code: Alles auswählen

- (void)countSheep {
    unsigned int sheep = 0;
    while ( ! [self isAsleep]) { ++sheep; }
}
moe
User
Beiträge: 12
Registriert: Montag 30. Juni 2008, 18:00

Hallo _blackjack_

ich starte jetzt meine Python-Skripte immer von der Konsole aus. Danke für den Tipp! Ich hatte gedacht, dass ich auch die Fehlermeldungen sehe, wenn ich das Programm in der IDLE starte.
Antworten