PyQt runs button functions on startup - python

I created a UI using Qt Designer for a python application.
The main function of my application runs when a button is clicked, like this:
self.button.clicked.connect(get_data(arg1, arg2, arg3))
To create the UI when the program begins, here is my main method:
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QDialog()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
However, the function "get_data" runs immediately upon start-up, despite the button not even rendering on my screen.
How can I stop the function from running immediately upon start-up?

It's because you are trying to connect the clicked event to the result of the function get_data. What you want to do is connect it to the actual function, like this:
self.button.clicked.connect(get_data)
You need to find another way to pass args into get_data. A lambda would work, but I'd use other methods (ie making a class)

Related

signal clicked works only with static methods

I'm using PyQt5, I'm trying to create an application that involves a QPushButton. Now, when the user clicks this button, a function is supposed to be executed.
When I try to use button.clicked.connect(self.button_clicked_slot) it works as expected only and only if button_clicked_slot() is a static method, i.e. doesn't take self as an argument. In case it is a non-static method, the function isn't executed when the button is clicked.
I've tried various similar answers from StackOver and elsewhere, none of them could solve the problem I'm facing. I'm creating and using this button inside a class, the slot function is a method of this same class. I've tried to make the class inherit from QWidget and QObject, neither of those solutions worked. It always seems to boil down to using a staticmethod.
The entire code would be very big, however, here is an over-simplified code snippet with the exact same
import sys
from PyQt5 import QtWidgets, QtCore
class activity(QtWidgets.QWidget):
def __init__(self):
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
button = QtWidgets.QPushButton('test button')
button.clicked.connect(self.temp_print)
window.setCentralWidget(button)
window.show()
sys.exit(app.exec_())
#staticmethod
def temp_print():
print('Reached here')
activity()
In the above code, the method temp_print() is executed whenever the button is clicked (because it is a staticmethod). However, if I rewrite the function as:
def temp_print(self):
print('Reached here')
And suddenly, this function is never executed regardless of how many times I click the button.
In several other code snippets and the official documentation, I've seen a non-static function being used as a slot and things seem to be going smoothly for them. The code snippet I shared above is an overly-simplified version of the problem that I'm facing.
And yes, in the code that I shared above, I don't need the self parameter inside the function and thus should be able to use a static method too. However, like I mentioned, this is a simplified version of the code I'm using (my actual code is over 500+ lines and thus it would be very stupid to paste the whole thing here), but, in my actual code, I am using the self parameter and thus need a non-static function to be used as the slot for click events.
Static methods can be invoked without the need to have an instance unlike the methods of the class that need the object to be created.
In your example, app.exec_() prevents the constructor from running, so the other methods of the class such as temp_print can not be called.
So there are 2 possible solutions:
Use a lambda method to invoke temp_print:
import sys
from PyQt5 import QtWidgets
class Activity:
def __init__(self):
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
button = QtWidgets.QPushButton("test button")
button.clicked.connect(lambda: self.temp_print())
window.setCentralWidget(button)
window.show()
sys.exit(app.exec_())
def temp_print(self):
print("Reached here")
if __name__ == "__main__":
Activity()
Let the object finish building:
import sys
from PyQt5 import QtWidgets
class Activity:
def __init__(self):
self.m_app = QtWidgets.QApplication(sys.argv)
self.window = QtWidgets.QMainWindow()
button = QtWidgets.QPushButton("test button")
button.clicked.connect(self.temp_print)
self.window.setCentralWidget(button)
self.window.show()
def temp_print(self):
print("Reached here")
def run(self):
return self.m_app.exec_()
if __name__ == "__main__":
a = Activity()
sys.exit(a.run())

How to run a pyqt5 application properly?

I can't get the GUI for my application to run in the manner that I need it to. My question is, given the below criteria, how do I go about setting up and running the GUI properly. The lack of good documentation that I have found is insanely frustrating (maybe I'm looking in the wrong places?).
I have a main window in a file called MainCustomerWindow.py containing a class by the same name. This is where all the code from the qt designer is. I have another class file called GUIController. The GUIController class does just that, controls the multiple GUI windows. It is in this GUIController class that I am trying to instantiate and run the MainCustomerWindow. Here is the code I have been trying.
def setup_window(self):
APP = QtWidgets.QApplication(sys.argv)
Window = MainCustomerWindow()
Window.setupUi(QtWidgets.QMainWindow)
Window.show()
sys.exit(APP.exec_())
Just as a side note, I come from JavaFX and Swing, and don't fully understand the workflow for pyqt5. So if someone could add an explanation for that as well it would be greatly appreciated.
The class generated by Qt Designer is not a widget, it is a class used to fill an existing widget, so you must create an object in the window, assuming you have used the "Main Window" template, then the widget must be QMainWindow (if it is another maybe you should use QDialog or QWidget), then you have to create another class that belongs to the design, and using the method setupUi() you must pass the widget to fill it:
def setup_window(self):
app = QtWidgets.QApplication(sys.argv)
# create window
window = QtWidgets.QMainWindow()
ui = MainCustomerWindow()
# fill window
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
Although a better option is to create a new class and have it inherit from both:
class MainWindow(QtWidgets.QMainWindow, MainCustomerWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
If you want to get detailed information I recommend you read the following:
http://pyqt.sourceforge.net/Docs/PyQt5/designer.html
You can try taking the code you have there and adding it to the main statement at the end of your app's script. You can also have this statement instantiate your class where the init method contains the setupui() call. For example:
if __name__ == '__main__':
app = QWidgets.QApplication(sys.argv)
window = QMainWindow()
main_window = MainCustomerWindow()
window.show()
sys.exit(app.exec())
This code first sets up the PyQt app as an instance of QApplication. Next it instantiates an instance of QMainWindow so that PyQt knows what to display as the main app starts. In my experience, I've put setupui() in the init method of the app class. In your case, in the init method of MainCustomerWindow Finally, window.show() tells PyQt to begin rendering the main window.

Passing string from one py to gui

Can someone tell me how do this?
I got main.py and gui.py (made in pyqt4).
The main.py runs some code, whatever, print "hello world" and I want to pass this string to gui.py in listWidget.addItem().
So in main.py I did:
from gui import Ui_Form
send_str = "hello all"
ui.listWidget.addItem(send_str)
and I get the error:
NameError: global name 'ui' is not defined.
which points to gui.py as in gui.py is
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
Form = QtGui.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
If i put both code in one py, all if working.
How to separate these two, since i want my main.py to execute in endless loop, and from time to time i want to open gui and check whats new value main.py going to send to window?
First problem is that ui variable is local to the if name == "main"
Second problem is the if itself because that branch will not be activated when you import a module, that is similar to the main() in c
3rd problem: the gui in QT has to run in the main thread. This means that your algorithm needs to run in another thread (there is an alternative with timers but it is ugly and harder to implement)
See a tutorial on QT threads and use the signal-slot mechanism to comunitate between gui thread and algorithm thread.

Using QT (PySide) to get user input with QInputDialog

I did a small script on python to do some stuff, and I want to ask user input first. This is my current code:
import sys
from PySide import QtGui
app = QtGui.QApplication(sys.argv)
gui = QtGui.QWidget()
text, ok = QtGui.QInputDialog.getText(gui, "question",
"""please put the thing I need from you""")
print(text, ok)
if ok:
app.exit()
else:
app.exit()
app.exec_()
print ("I'm aliveeeee'")
The dialog pop-ups exactly as I want, but app.exec_() never ends so the rest of the code is never executed (and the process never finish) I tried to kill it with app.exit(), app.quit(), I also try to show() and close() the QWidget, but nothing is working.
If I do gui.show() before calling the QInputDialog and then close the widget manually, the app closes successfully. However, this is not the behavior I want.
Can you guide me on which is the best way to close the exec loop after I got my data?
PD: This is going to be a windows app (with py2exe) and using the shell is not an option.
Just don't call app.exec_()
The problem here is that this is a toy example. In real life, usually you will show some UI and then call app.exec() to let the user interact with it.

Block and hide QDialog: Alternative to exec_()?

In my Qt-based application (built using PyQt 4.8.6), I have a class that is a subclass of QtGui.QDialog:
class ModelDialog(QtGui.QDialog):
...
When I run the application's user interface, I can display the QDialog like so:
def main():
app = QtGui.QApplication(sys.argv)
dialog = ModelDialog()
dialog.exec_()
According to the Qt docs and the PyQt docs, exec_() is a blocking function for this QDialog, which defaults to a modal window (which by definition prevents the user from interacting with any other windows within the application). This is exactly what happens under normal circumstances.
Recently, however, I've been working on a way to call through the entire QApplication using defaults for all input values, and not asking the user for any input. The application behaves as expected except for one single aspect: calling dialog.exec_() causes the modal dialog to be shown.
The only workaround I've been able to find has been to catch the showEvent function and to promptly hide the window, but this still allows the QDialog object to be shown for a split second:
class ModelDialog(QtGui.QDialog):
...
def showEvent(self, data=None):
self.hide()
Is there a way to prevent the modal window from being shown altogether, while continuing to block the main event loop? I'd love for there to be something like:
def main():
app = QtGui.QApplication(sys.argv)
dialog = ModelDialog()
dialog.setHideNoMatterWhat(True)
dialog.exec_()
(to that end, I tried using QWidget.setVisible(False), but dialog.exec_() sets the dialog to be visible anyways, which is expected according to the Qt docs)
Use app.exec_() instead of dialog.exec_().

Categories