Open pyqt program without console with pythonw - python

i have a strange problem. I created a GUI program which runs in "spyder" with WinPython-64bit-3.3.2.3 with no problems, now i want to run it without the console to pop up and i try to use pythonw.exe.
When i save my GUI as gui.pyw i can open it with PythonWin by right clicking and use edit with PythonWin but simply double-clicking will make my GUI pop up for less than a second and exit the program afterwards.
Does this have to do with my GUI programming?
the "structure" is this one:
import sys
from PyQt4 import QtGui, QtCore, Qt
from Main_Window_v2 import Ui_Dialog as Dlg
class MeinDialog(QtGui.QDialog, Dlg):
def __init__(self):
QtGui.QDialog.__init__(self)
self.setupUi(self)
self.connect(self.buttonOK,
QtCore.SIGNAL("clicked()"), self.onOK)
self.connect(self.buttonAbbrechen,
QtCore.SIGNAL("clicked()"), self.onClose)
self.connect(self.buttonsql,
QtCore.SIGNAL("clicked()"), self.onsql)
def onsql(self):
login=self.login_text_box.toPlainText()
from calc import get_variables #sql query
self.get_variables=get_variables(login)
#calls a class´ __init__ in another file in my direcotry
def onOK(self):
login=self.login_text_box.toPlainText()
self.get_variables.plot(login)
#calls another function in my class "calc"
def onClose(self):
print("bye!")
self.close()
app = QtGui.QApplication(sys.argv)
dialog = MeinDialog()
dialog.show()
I also tried to get an .exe using cx_freeze and after trying to making build as described here Cx_Freeze: I have the same problem: The Main-Window of the GUI
pops up and disappears again

Just add app.exec_() at the end of your code. Your code was running well in Spyder because Spyder uses PyQt and had the main loop of events already running.

You should add app.exex_() at the end of your code, it is used to dispatch all PyQt GUI threads message or other threads info message.

Related

PyQT5 Designer add checkbox i Python when I have separate file for code

My problem is that I have a file with my UI called xxx.ui. Then as many have suggested I created another python file called test.py where I have put code to use my xxx.ui:
# imports
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import uic
import sys
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('xxx.ui', self)
self.show()
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
Up until this stage everything works ok. But now I would like to add a checkbox to my UI whe program starts without messing inside xxx.ui (so the checkbox will be created dynamicaly when the program runs).
How can I do that ???
Thank You in advance.
After many fail attempts I have found how to do it:
To add Checkbox outside of xxx.ui file. I went to my test.py file and added code below this line:
uic.loadUi('xxx.ui', self)
The code looks like that (I am using horizontal layout widget created in designer called seasonLayout and my checkbox is inside that layout):
self.checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget)
self.checkBox.setObjectName("checkBox_0")
self.checkBox.setText('Hello')
self.seasonLayout.addWidget(self.checkBox)
Then if You want to get to that object all You have to do is to use code below:
(here i change text of this newly created checkbox):
self.checkBoxs = self.findChild(QtWidgets.QCheckBox, 'checkBox_0')
self.checkBoxs.setText('test')
Hopefuly it will be helpful for other because I have really tried to find answer for that almost everywhere and everyone were just using widgets from designer - noone explain how to add them outside of it.

PyQt4: How to reopen dialog window from main window

I am using PyQt4 with Python 3. I am trying to open a dialog window when a button in the main window is pressed. The dialog window also needs to be able to send data back to the main window via signals.
A similar question has been asked here:
Open a second window in PyQt
I have used that post as a guide to build my code.
Now all of that is currently working, except for if you close the dialog window, and try to open it again, you get:
RuntimeError: wrapped C/C++ object of type QDialog has been deleted
Meaning you have to restart the program before you can open it again. This will not work for my particular application.
From what I understand here: https://www.daniweb.com/programming/software-development/threads/299395/pyqt-how-to-open-and-close-dialog-multiple-times
I need to destroy the object (the dialog window) before trying to open it again. I tried to do that, however I am not sure how to do it without closing the entire application when I just want to close the dialog window. Also not sure if that is the solution.
Here is a summarized version of my code:
Main window:
from PyQt4 import QtCore, QtGui
#Qt designer generated code here
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
#Ui setup stuff here
#Button 3
self.pushButton_3 = QtGui.QPushButton(self.centralwidget)
self.pushButton_3.clicked.connect(self.pressed_3)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
#signal from dialog menu
self.dialog = QtGui.QDialog()
self.dialog.ui = entry_window_2.Ui_Dialog()
self.dialog.ui.setupUi(self.dialog)
self.dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.dialog.ui.sendVals.connect(self.recieved_save_data)
def pressed_3(self, checked=None):
self.dialog.exec_()
def recieved_save_data(self, value):
print(value)
Dialog window
from PyQt4 import QtCore, QtGui
#PyQt generated code here
class Ui_Dialog(QtCore.QObject):
sendVals = QtCore.pyqtSignal(int)
def setupUi(self, Dialog):
#PyQt Ui_setup code here
self.ok_cancel = QtGui.QDialogButtonBox(Dialog)
self.ok_cancel.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.ok_cancel.accepted.connect(self.save)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL(_fromUtf8("accepted()")), Dialog.accept)
QtCore.QObject.connect(self.ok_cancel, QtCore.SIGNAL(_fromUtf8("rejected()")), Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def save(self):
self.sendVals.emit(1212)
Any help would be appreciated! :)
So I solved the issue thanks to this article:
http://enki-editor.org/2014/08/23/Pyqt_mem_mgmt.html
The solution is to delete this line here:
self.dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
I am no expert, but from what I understand, for every C++ class in PyQt there is a python wrapper class. As the python programmer, you are interacting with the python wrapper, and wrapper interacts with the C++ class in the background.
The issue here is the "C++ object is deleted by Qt but Python wrapper still exists". This appears to be caused by that line that just deleted.
Perhaps someone can explain it better than I can. But that did in fact fix the problem.

How to stop qt app from freezing the main program?

For example:
#!/usr/bin/env python3
import sys
from PySide import QtCore, QtGui
class Dialog(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
button = QtGui.QPushButton("test")
layout = QtGui.QVBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
toast = Dialog()
toast.show()
app.exec_()
print("App freezes the main process!")
The last print() function will not be executed until you close the dialog.
I am working on a script that only uses qt for displaying some content that does not require user interaction, so I would prefer the gui code runs in background.
This is not possible. Qt documentation states:
Although QObject is reentrant, the GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread. As noted earlier, QCoreApplication::exec() must also be called from that thread.
(emphasis mine)
This answer suggests on the other hand that in reality this is not true :) However it seems that PySide sticks to the official version:
This can be verified by the following code sample:
import sys
import threading
from PySide import QtCore, QtGui
class Dialog(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
button = QtGui.QPushButton("test")
layout = QtGui.QVBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
toast = Dialog()
toast.show()
t = threading.Thread(target = lambda: app.exec_())
t.daemon = True
t.start()
print("App freezes the main process!")
input()
which produces the following output:
App freezes the main process!
QApplication::exec: Must be called from the main thread
(and a crash, on my machine). I have also verified the option with creating the app within the other thread - it works, but crashes on exit.
So the solution seems to let Qt have the main thread, and organize your processing in a separate thread. This shouldn't really be a problem: if you'll separate your concerns well it won't make a difference for your console-app part on which thread it's running.
I'm not sure if the PySide imposes any restrictions, but here's how it's done in C++:
Instantiate QApplication in a secondary thread.
Create your dialog in that same thread.
Call either QDialog::exec() OR {QApplication::exec() plus QDialog::show()} in that same thread.
Make sure that your secondary thread has fully shut down before you quit your app.
Yes, the Qt documentation currently says that only the main thread is allowed. However, there is nothing in the Qt source code that forbids creating QApplication in a secondary thread and then using GUI classes in that thread (for Windows and Linux). The documentation should be changed.
Mac OS X is different though -- the Cocoa framework only allows GUI operations in the main thread.

Pyside UI pops up and then disappears when run from cmd before it can be used?

I am fairly new to python and have made a simple UI using pyside. When run from inside the anaconda IDE the UI works fine, but when I run it using anaconda from the command line \python.exe 'runquacker.py' the UI flashes up and disappears immediately.
The initial script is:
from PySide.QtCore import *
from PySide.QtGui import *
import sys
import quacker
class MainDialog(QDialog, quacker.Ui_Dialog):
def __init__(self, parent=None):
super(MainDialog, self).__init__(parent)
self.setupUi(self)
app = QApplication(sys.argv)
form = MainDialog()
form.show()
The rest of the UI is in quacker.py which collects a bunch of variables from the user, before executing a further analysis.py program using a subprocesscall. The variables are all passed in this way because thats the only way I could get pyside to work with my script!
e.g. For two variables 'plots' and 'block':
subprocess.call([sys.executable, 'd:\\py\\anaconda\\analysis.py', str(plots), str(block)], shell=True)
Ive tried putting a raw_input('Blah..') in a few places but it just causes the program to hang or nothing at all.
Using \python.exe -i runquacker.py also causes the program to hang.
Thanks
You need to add this line at the end of your script: app.exec_()
That's because you need to actually execute your Qt application if you whant to see something.
I'm not pretty sure why it works in Anaconda but if you are using some IDE like Spyder I think it works because Spyder is already running in Qt (so it called QApplication.exec_ before).

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!

Categories