Using QT (PySide) to get user input with QInputDialog - python

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.

Related

How to show a dialog all by itself (without parent widget) in PyQt?

In the context of a parent class like a main window, it is easy to pop up a dialog like a message box:
QMessageBox.information(self, "Title", "Here is your informative message")
This pops up the message I want, with parent being self, the widget already open. But what if I want to show such a dialog in the middle of a Python program all by itself (say, to tell them their program has finished running, or whatever), without invoking a parent class?
I tried the following, and the dialog shows, but when I click OK my system hangs for a few seconds, no message is printed, and my Python kernel restarts (with no error message):
import sys
from PyQt5.QtWidgets import QApplication, QMessageBox
app = QApplication(sys.argv)
mess = QMessageBox()
mess.setText("Here is your message")
mess.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
returnValue = mess.exec_()
if returnValue == QMessageBox.Ok:
print("Clicked OK!")
elif returnValue == QMessageBox.Cancel:
print("Cancelled?!")
print("\n\nNow we are done")
When I click Cancel, it seems to work fine. I am not sure what Qt rules I am breaking here. I could just roll my own little popup using a QWidget I suppose.
I am in pyqt5/python 3.7 running in Spyder/iPython. When I run directly from the command line, it actually seems to work, so this could be an iPython or Spyder problem.
Simply replacing self with None seems to display the QMessageBox in the middle of the screen.
QMessageBox.information(None, "Title", "Here is your informative message")
The above code was only "broken" when using Spyder, and now works for newer versions of Spyder (versions 4.1+). So it wasn't a PyQt issue at all, ultimately, but an IDE interaction effect.

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.

Multiple windows in PyQt4?

I've just begun using pyqt4. I followed a tutorial (http://zetcode.com/tutorials/pyqt4/)
One thing that puzzles me is this part:
def main():
app = QtGui.QApplication(sys.argv)
ex = GUI()
sys.exit(app.exec())
And the reason for this I explain here:
I have made a small program that opens four more windows except for the first main window.
So I tried to replicate what I saw worked with main-window and created a class for every new window and tried to do like with the above. Currently it looks like this:
def main2():
#app = QtGui.QApplication(sys.argv)
ex2 = Settings()
sys.exit(app.exec())
As you can see I have modified it. If I left the first line in the function uncommented the program would crash. I tried to do without the sys.exit(app.exec_())-part but that would only make the new window close milliseconds after it showed.
This way though, everything runs and works. Only that in the command window, an error message displays. I don't know how to fix this, since I cannot remove the last line, and I dont't know what to replace "app" with.
I know I'm probably doing the new windows wrong from the beginning, but I don't know how to make these windows open from the original window in any other way. I haven't been able to get anything else to work, and this at least runs and works right now. So the only problem is error messages in the prompt, it would be nice to get rid of them :)
Thanks for any help (complicated and easy ones)!
Forgot to mention, I made the classes start like this:
class GUI(QtGui.QMainWindow):
def __init__(self):
super(GUI, self).__init__()
self.initUI()
and
class Settings(QtGui.QWidget):
def __init__(self):
super(Settings, self).__init__()
...here goes some more...
self.initUI2()
and I open Settings-window by calling main2()
You must create one and only one QApplication in your program.
Keep in mind that GUI programming is event-driven, you first declare widgets and then run the main loop with app.exec(), when the user quit your application, app.exec() returns.
The QApplication purpose is to handle user events and propagate them to your code with Qt signals. I suggest you check Qt documentation, it's very complete, even if it's targetting C++ programmers.
So for instance, a way to create two widgets would be:
def main():
app = QtGui.QApplication(sys.argv)
ex = QtGui.QWidget()
ex.show()
ex2 = QtGui.QWidget()
ex2.show()
sys.exit(app.exec())

Different behaviour between python console and python script

I am experiencing different behaviour on the same code using the python console and a python script.
The code is as follows:
import gtk
import webkit
win = gtk.Window()
win.show()
web = webkit.WebView()
win.add(web)
web.show()
web.open("http://www.google.com")
When running the code in the python console, the output is a new frame that contains the google main page.
When running the code as a script, the result is a void frame. It closes very fast but even if I use a delay function, the webkit is not added to the frame.
How is it possible?
Furthermore, using PyDev IDE it flags: "unresolved import: gtk",
but if i run the project, the program starts without problem of compilation. is it normal?
Add
gtk.main()
to the end of your script. This starts the gtk event loop.
import gtk
import webkit
class App(object):
def __init__(self):
win = gtk.Window()
win.connect("destroy", self.destroy)
web = webkit.WebView()
web.open("http://www.google.com")
win.add(web)
web.show()
win.show()
def destroy(self, widget, data = None):
gtk.main_quit()
app = App()
gtk.main()
My guess is that the console keeps the python session open, while at the end of the script the program closes. When the script closes, it takes everything it created with it.
Something to test this theory: if you type "exit" in the console do you see the interface shut down in the same manner? If so, think of some code (e.g. a pause like a raw_input) that will allow the script to stay open.
Good luck!

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