PyQt - is it possible to run two applications? - python

Two files. Each runs new window and works by itself. I need to run them both.
When I run first.pyw, only one (second) window is shown.
Is it possible two run them both?
first.pyw:
import sys
from PyQt4.QtGui import *
import second
class first(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setWindowTitle('first')
app = QApplication(sys.argv)
firstApp = first()
firstApp.show()
sys.exit(app.exec_())
second.pyw:
import sys
from PyQt4.QtGui import *
class second(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setWindowTitle('second')
app2 = QApplication(sys.argv)
secondApp = second()
secondApp.show()
sys.exit(app2.exec_())
How can I run two applications that are in different modules?

The accepted answer is essentially right, but there are cases where you want to run multiple QApplications one after the other, e.g. :
Unit tests
A command-line tool that shouldn't require a running X server (hence no QApplication on startup), but can optionally show a window if the user's system supports it
I ended up using the multiprocessing module to start each QApplication in a separate process, so that each one is independent from the others.
from multiprocessing import Queue, Process
class MyApp(Process):
def __init__(self):
self.queue = Queue(1)
super(MyApp, self).__init__()
def run(self):
app = QApplication([])
...
self.queue.put(return_value)
app1 = MyApp()
app1.start()
app1.join()
print("App 1 returned: " + app1.queue.get())
app2 = MyApp()
app2.start()
app2.join()
print("App 2 returned: " + app1.queue.get())

You can only run a single application at a time, although your application can have multiple top-level windows. The QCoreApplication docs say that:
...there should be exactly one QCoreApplication object.
This also holds true for QApplication as it derives from QCoreApplication. You can get access to that application through the QCoreApplication.instance() method or the qApp macro in C++.
What do you expect to get out of having two different applications running? Instead, you could have each module provide a top-level window that then gets displayed by the application launcher.

You import second. Hence it is interpreted before you even reach the definition of class first. As the last line of second.pyw is sys.exit, nothing behind it can be executed.

Related

Loading python module with GUI

I have a organization setup question I need help with. Here is my current folder structure.
What i want to do is run the Main UI with the specified AppCommands module that contains functions. Based on which application i want to run the tool. Is there a way using another python file, where i can load the gui and the associated app commands moduel? So when users click the button it calls the corrects app command.
So say for example I create a python file like this pseudo code
main execute py file for Photoshop
Import photoshop.appcommands as cmds
Import GUI
Gui(cmds)
How do I then tell my main GUI tool to load the photoshop modules 'AppCommands' when it runs?
app #1 code:
def runTool():
msg = 'This is Notepad'
print msg
app #2 code:
def runTool():
msg = 'This is Photoshop'
print msg
Main ui code:
import sys
import os
from PySide import QtGui, QtCore
import AppCommands as cmds
class MainWindow(QtGui.QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
self.uiButton = QtGui.QPushButton('Button', self)
# layout
grid = QtGui.QGridLayout()
grid.addWidget(self.uiButton, 3, 1)
main_widget = QtGui.QWidget()
main_widget.setLayout(grid)
self.setCentralWidget(main_widget)
self.uiButton.clicked.connect(self.browse_clicked)
# actions
def browse_clicked(self):
print 'Execute Command'
cmds.runTool()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
Well, if I understood correctly, you need to choose the right module to load a function after then you started the program with some variable args?
In this case you may import both and try globals:
import notepad.AppCommands
import photoshop.AppCommands
...
# in your app init code:
x = 'photoshop' # an arg passed from config/CLI or from somewhere else
actual_module = globals()[x]
actual_module.AppComands.runTools()
++ But if you just don't know how to run a certain function from a certain module, follow #eyllanesc's answer.

interactive python - keeping console interactive with a GUI mainloop

I am wondering how one would create a GUI application, and interact with it from the console that started it.
As an example, I would like to create a GUI in PyQt and work with it from the console. This could be for testing settings without restarting the app, but in larger projects also for calling functions etc.
Here is a simple example using PyQt:
import sys
from PyQt4 import QtGui
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
when this is run with python -i example.py the console is blocked as long as the main-loop is executed.
How can I call w.resize(100,100) while the GUI is running?
ops, posted wrong answer before
there is a post in Stack about that
Execute Python code from within PyQt event loop
The following example uses the code module to run a console in the command prompt (be sure to run the script from the command line). Subclassing QThread provides a route by which the console can be run in a separate thread from that of the main GUI and enables some interaction with it. The stub example below should be easy enough to incorporate into a larger packaged PyQt program.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import threading #used only to id the active thread
import code
import sys
class Worker(QThread): #Subclass QThread and re-define run()
signal = pyqtSignal()
def __init__(self):
super().__init__()
def raise_sys_exit(self): #more gracefully exit the console
print('(Deactivated Console)')
raise SystemExit
def setup_console(self,global_dict):
console_exit = {'exit': self.raise_sys_exit}
self.console = code.InteractiveConsole(locals=dict(global_dict,**console_exit))
def run(self):
try:
print('worker', threading.get_ident())
self.console.interact()
except SystemExit:
self.signal.emit()
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args,**kwargs)
self.data = [1,2,3,4] #some data we might want to look at
layout = QVBoxLayout()
self.b = QPushButton("Interact")
self.b.clicked.connect(self.b_clicked)
layout.addWidget(self.b)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
self.worker = Worker()
self.worker.signal.connect(self.finished)
def finished(self):
self.b.setEnabled(True)
def b_clicked(self):
print('main',threading.get_ident())
self.worker.setup_console(globals()) #pass the global variables to the worker
self.worker.start()
self.b.setEnabled(False) #disable the GUI button until console is exited
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
The easiest way is to use IPython:
ipython --gui=qt4
See ipython --help or the online documentation for more options (e.g. gtk, tk, etc).

PyQt4 app button not working

I'm trying to set up an app in Linux using PyQt4 designer and I'm struggling to connect signals and slots to it. Right now all I want it to do is connect a button clicked signal to a custom slot, saveEnergyScheme which simply prints 'energy list' to the terminal.
I've translated the .ui code for my app to a python class with pyuic4 -w sumcorr.ui > sumcorr_ui.py. This created a class in the sumcorr_ui.py module called SumCorr_ui:
class SumCorr_ui(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QMainWindow.__init__(self, parent, f)
self.setupUi(self)
I then made my app as a custom widget and tried to add a simple signal-slot connection to a button to show it works:
from PyQt4 import QtGui, QtCore
from sumcorr_ui import SumCorr_ui
class SumCorr(SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = QtGui.QMainWindow()
ui = SumCorr()
ui.setupUi(mySumCorr)
mySumCorr.show()
sys.exit(app.exec_())
I expect to get the line 'energy list' when I click the button named save_energies_button, but nothing happens. Could this be because I haven't built the UI as a widget, but as a main window? Why doesn't it print out??
Try to add ui.show() and you'll see that your code is creating two different windows, one should have the signal connected and one doesn't. That's because you are showing only the mySumCorr window, but you call only setupUi on it, which does not connect the signal.
When you create the SumCorr instance, you are creating a window and setting it up, then, by no reason, you do ui.setupUi(mySumCorr), which setups the mySumCorr instance without connecting the signal, and you show this last window.
I believe your code should be like this:
class SumCorr(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.setupUi(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = SumCorr()
mySumCorr.show()
sys.exit(app.exec_())
Note that it doesn't make any sense to have a SumCorr_ui class, that's because Qt is a UI library so you are just introducing a worthless level of abstraction. The designer file already gives you an abstraction over the ui layout.

Python 3 pyQt4 updating GUI with variables from multiple modules/classes

I've written a large program with nested classes/threads and multiple modules.
I would now like to add a simple GUI and some Labels to display some variables.
However, the variables are scattered throughout the modules and classes.
I'm looking for a way to update these variables into the GUI without altering
the current code too much.
I have a rudimentary understanding of Pyqt4 (i will accept tkinter answers also).
I've tried not to use signals/emits because to my knowledge emits
must be sent from a Qthread which would mean a complete overhaul of my code, changing
classes and threads over to Qthreads. Id like to avoid needing to do this if possible.
Here is one example I've attempted.
test.py
class Update(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
for i in range(10):
time.sleep(2)
import test
wa.label.setText(str(i))
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
self.label = QLabel(" ")
layout = QVBoxLayout()
layout.addWidget(self.label)
self.setLayout(layout)
Update1 = Update()
Update1.start()
Update1.refresh1 = 'ba'
self.label.setText(Update1.refresh1)
if __name__ == "__main__":
app = QApplication(sys.argv)
wa = MyWindow()
wa.show()
sys.exit(app.exec_())
This code works, but my variables need to update from other modules/classes or threads. The moment I move 'class Update' into a new module like THIS:
test.py
import test2
class MyWindow(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
self.label = QLabel(" ")
layout = QVBoxLayout()
layout.addWidget(self.label)
self.setLayout(layout)
Update1 = test2.Update()
Update1.start()
Update1.refresh1 = 'ba'
self.label.setText(Update1.refresh1)
if __name__ == "__main__":
app = QApplication(sys.argv)
wa = MyWindow()
wa.show()
sys.exit(app.exec_())
test2.py #updates GUI
class Update(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
for i in range(10):
time.sleep(2)
import test
test.wa.label.setText(str(i))
I get: AttributeError: 'module' object has no attribute 'wa'
Also, I was also considering putting class Update() into a Qthread, running it from any module/class where a variable has been updated and using the emit function inside Update(). this would solve having to change my current classes/threads to be Qthreads.
If anyone knows of a simple way I could update my GUI simply by calling a class like update() an example would be appreciated
Because wa is only set when __name__ == "__main__" and that only happens when test.py is the main file.
When you do import test, you are running another instance of the test.py file which is not the main script so it has __name__ == 'test' not __main__. So, even if wa was set, you would be changing another instance of it.
Possible solution:
You can get a reference to the __main__ module and set on the test2.py module:
On test.py:
import test2
test2.parent = sys.modules[__name__]
Now, on test2.py (do not import test but make sure test imports test2):
parent.wa.label.setText('Blablabla')

Running python files

I am working on pyqt4 and python26 application.I created forms using qt designer (.ui files).
I converted them to .py and .pyc files.But when i try to run .py file ,python command line comes and goes within a second,the form (corresponding .ui file) cannot be seen...what can be the problem??
this is my code:(.py file)
from DlgAbout_ui import Ui_DlgAbout
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import resources
class DlgAbout(QDialog, Ui_DlgAbout):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.setupUi(self)
self.logo.setPixmap( QPixmap( ":/icons/faunalia_logo.png" ) )
text = self.txt.toHtml()
text = text.replace( "$PLUGIN_NAME$", "RT Sql Layer" )
self.txt.setHtml(text)
First, don't use:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
Instead:
from PyQt4 import QtCore, QtGui
And reference the modules explicitly.
class DlgAbout(QtGui.QDialog, Ui_DlgAbout):
etc.
In your code, all you've done is defined a dialog box. You haven't defined any main application to run, or any way to show the dialog box.
For an example, here's a basic main application to run:
from PyQt4 import QtGui
import sys
class MyMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.form_widget = FormWidget(self)
self.setCentralWidget(self.form_widget)
class FormWidget(QtGui.QWidget):
def __init__(self, parent):
super(FormWidget, self).__init__(parent)
self.layout = QtGui.QVBoxLayout(self)
self.button = QtGui.QPushButton("Button!")
self.layout.addWidget(self.button)
if __name__ == "__main__":
app = QtGui.QApplication([])
foo = MyMainWindow()
foo.show()
sys.exit(app.exec_())
This defines a main window, and a form (Which MyMainWindow sets up, as you can see).
I then check if this is the main file being run (if __name__ == "__main__":), and I start the application (The app = QtGui.QApplication([]), create the main window, and show the main window.
In your case, you could define a main application like I did, and make it alert your QDialog.
Your python code just imports some modules and then defines a new class. It doesn't do anything with the class it has defined, though. In other words, once Python is done creating the new class, it is finished, and it exits.
I don't know PyQT at all, but most likely you need to start the GUI's main loop, and also instantiate an instance of your new class and pass it to PyQT.

Categories