1

I am trying to return a path from a browse folder dialog box.

I have tried passing the instance object or even attribute to the call and setting it there:

self.browseBtn.clicked.connect(myExporter.browseFolder(self))

or

self.browseBtn.clicked.connect(myExporter.browseFolder(self.path))

But this doesn't work. It causes the browser dialog to pop open immediately upon load and then once you choose a folder it errors out with : Failed to connect signal clicked().

I have tried to set the clicked call to a return, with no luck:

result = self.browseBtn.clicked.connect(myExporter.browseFolder)

Can someone lead me in the right direction as far as how to return a value, when you are dealing with separate classes handling the UI and logic? Also... is it bad practice to be separating them like this? I know I could probably easily solve this if I threw everything into just one python file, but I figured that is not proper.

Here is my ui file (ui.py):

from PySide import QtCore, QtGui

class Ui_Dialog(object):
    def __init__(self):
        self.path =""

    def setupUi(self, Dialog, myExporter):
        Dialog.setObjectName("Dialog")
        Dialog.resize(382, 589)
        ...
        .......
        ............. 
        .................
        self.retranslateUi(Dialog)
        self.tabWidget.setCurrentIndex(1)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

        self.browseBtn.clicked.connect(myExporter.browseFolder)

Here is my exporter file (exporter.py):

class Exporter(object):
    def __init__(self):
        ...
        ......

    def browseFolder(self):
        ...
        .......
        do something
        ...........    
        return path

Here is my load/test file (loadExporter.py):

import ui as interface
import exporter as exporter
from PySide import QtCore, QtGui

app = QtGui.QApplication.instance()
if app is None:
    app = QtGui.QApplication(sys.argv)       
Dialog = QtGui.QDialog()
myExporter = exporter.Exporter()
myUI = interface.Ui_Dialog()
myUI.setupUi(Dialog, myExporter)
Dialog.show()
app.exec_()

2 Answers 2

1

It's not necessarily bad to have them in separate files. Having a separate file for certain widgets is a good thing especially if those widgets can be reused.

I would have my main file have a QMainWindow class.

class MyWindow(QtGui.QMainWindow):
    pass

if __name__ == "__main__":
    QtGui.QApplication([])

    mywindow = MyWindow()
    mywindow.show()

    sys.exit(QtGui.qApp.exec_())

Wrapping the app functionality in if __name__ == "__main__" prevents this code from being run when another file tries to import this file.

A signal (self.browserBtn.clicked) calls a callback method. Everything is an object in python.

def my_func():
    pass

new_func_name = my_func # my_func can be reassigned like any variable

my_func is an object. self.browseBtn.clicked.connect(my_func) passes my_func as a variable to be called later.

When self.browserBtn.clicked.emit() happens (on user click) it is the same as calling the connected functions my_func(). Other signals may pass values to callback functions self.lineEdit.textChanged.connect(my_func) calls 'my_func(new_text)'

You want your function to call everything for you.

def open_file(filename=None):
    """Open a file."""
    # If a filename isn't given ask the user for a file
    if filename is None:
        filename, ext = QtGUi.QFileDialog.getOpenFileName(None, "Open File", ".../My Documents/")
        # You may have to use the ext to make a proper filename

    # Open the file
    with open(filename, "r") as file:
        file.read()

self.browserBtn.clicked.connect(open_file)

Structure

...
import mywidget

class MyWindow(QtGui.QMainWindow):
    def __init__(self):
        super().__init__()
        ...
        self.show_file = QtGui.QLineEdit()
        self.setCentralWidget(self.show_file)

        self.exporter = mywidget.Exporter()
        self.browserBtn.clicked.connect(self.open_file)

    def open_file(self, filename=None):
        """Open a file."""
        path = self.exporter.browseFolder()
        # Do something with the path
        self.show_file.setText(path)

if __name__ == "__main__":
    QtGui.QApplication([])

    mywindow = MyWindow()
    mywindow.show()

    sys.exit(QtGui.qApp.exec_())
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the input, but this doesn't really answer my question. I know that a signal can call a method. I am trying to figure out how to pass and more importantly return values from the signal. The file dialog box is simply returning a file Directory path to fill in a value in the GUI. The path returned needs to be first received and then set into one of the GUI's lines. Of course... I still would like to figure out how to return said value.
It would be great if someone could address the complexity here with the fact that I have the UI and the logic separated, along with a main file to load both. I can easily solve this by just throwing this all into one file, but I am avoiding that and hence why I am having this issue.
You cannot return a value from the signal. The method connected to the signal is called on signal.emit(). The emit function returns immediately, calling the connected functions in a separate timeout. There is no way to return a value from a signal. Make your function have a reference to the objects you need and do all of the operations within your function. That's what I was trying to show with the open method. def open_file(self, filename=None): then use self to call other methods that you need or set a QLineEdit with self.my_line_edit.setText(filename)
I kind of understand now... did some thinking last night even before revisiting this and thought to myself I could just do all of this in a separate method call which is thrown in the signal, in that same UI file... rather than trying from the other module if that makes sense. Thanks.
I added a Structure section at the bottom to clarify.
1

I don't think I fully understand what you're trying to achieve, but may I suggest the following solution.

exporter.py

# implementation

dialog.py (Main UI)

import PyQt4.QtGui as qg
from exporter import Exporter

class Dialog(qg.QDialog):

    def __init__(self):
        super().__init__()
        self.path = None
        self.setup_widgets()

    def setup_widgets(self):
        self.browse.clicked.connect(self.on_browse_clicked)

    def on_browse_clicked(self):
        self.path = Exporter().browse_folder()

main.py

import sys
import PyQt4.QtGui as qg
from dialog import Dialog

if __name__ == '__main__':
    app = qg.QApplication(sys.argv)
    dialog = Dialog()
    dialog.show()
    sys.exit(app.exec_())

This way you still have three files, but dialog.py imports exporter.py instead of main.py importing both of them.

As for returning values from signals, I don't know; I think signals are voids (do not return values).

Signals pass arguments to slots via their formal parameters. Usually slots have the same or fewer parameters than their signal counterparts'. It's slots that return values.

1 Comment

Thanks, this helps as well and is a bit more clear than above (still getting used to PyQt/PySide).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.