0

I made the transition from PyQt4to PyQt5. My app (created with QtDesigner) has a checkbox which enables a "Save" button, in case you want to save your file. In PyQt4 the dialog would open, I'd choose my file, press OK, done. I implemented a check on the OK button of the main application that would prompt an error if the path was invalid, e.g. if you pressed cancel in the QFileDialog.

With PyQt5 my application exits completely if I close the QFileDialog in any way (OK, cancel, X). I want just the QFileDialog to close and not my main window. How do I do this? Thanks for your time and help.

Here's the relevant part of my code:

self.path = self.ui.savepathButton.pressed.connect(lambda: self.file_save())

def file_save(self):
    path = QFileDialog.getSaveFileName(self, "Choose a path and filename", os.getcwd().replace("\\", "/") +
                                       "/test.stl", filter="Stereolithography Files (*.stl)")
    self.ui.savepath_label.setText(path) <------ NO ERROR WITHOUT THIS LINE

def OKButton_click(self):
    if os.path.isdir(os.path.split(self.ui.savepath_label.text())[0]) is False:
        # Warning if the filename is invalid.
        file_error = QMessageBox()
        file_error.setIcon(QMessageBox.Warning)
        file_error.setText("Invalid path or filename.")
        file_error.setInformativeText("Please choose a working path and filename.")             file_error.setWindowTitle("File name error")
        file_error.setStandardButtons(QMessageBox.Ok)
        file_error.exec_()
    else:
        self.accept()

Edit:

I know where my error is located, but I still cannot fix it. I marked the line in the code. Why does self.ui.savepath_label.setText(path) terminate my application?

Ian
  • 1,688
  • 18
  • 35

2 Answers2

0

I finally found the (very small) error:

While PyQt4 apparently writes the path automatically as string, PyQt5 does not.

I changed

self.ui.savepath_label.setText(path)

into

self.ui.savepath_label.setText(str(path))

and all is good now.

Ian
  • 1,688
  • 18
  • 35
0

The PyQt4 provides two different APIs:

  • API v1 uses the Qt types for objects, so you have to pass things like QString to the setText method
  • API v2 instead uses python types and the methods of the Qt objects automatically convert those python types into their Qt variants, so you have to pass a python str to them.

This is mentioned in this page about PyQt4. PyQt5 only supports version 2 of the API (that page also mentions other differences).

Also note that according to the question pyqt5 - finding documentation the PyQt5 method getSaveFileName actually returns a pair of (filename, filter) so it's effectively equivalent to PyQt4's getSaveFileNameAndFilter method, which means that you could simply use:

self.ui.savepath_label.setText(path[0])

To set the text. Minimal complete example:

from PyQt5.QtWidgets import  QFileDialog, QWidget, QApplication, QHBoxLayout, QPushButton


class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__(None)
        layout = QHBoxLayout()
        self.button = QPushButton('click')
        layout.addWidget(self.button)
        self.setLayout(layout)
        self.button.clicked.connect(self.ask_filename)
    def ask_filename(self):
        fname = QFileDialog.getSaveFileName(self, 'title')
        print(fname)
        self.button.setText(fname[0])


app = QApplication([])
window = Window()
window.show()
app.exec_()

By the way, if you change fname[0] to fname and try to launch this application from the terminal you get the following helpful error message:

Traceback (most recent call last):
  File "test_qt.py", line 15, in ask_filename
    self.button.setText(fname)
TypeError: QAbstractButton.setText(str): argument 1 has unexpected type 'tuple'

which tells you that the return type of getSaveFileName is a tuple and not a str.

Community
  • 1
  • 1
Bakuriu
  • 98,325
  • 22
  • 197
  • 231
  • After I found the workaround with `str()` I noticed, that it would actually return a tuple and basically did what you explained so well in your answer. Thanks for your very insightful post! – Ian Jun 27 '16 at 09:02