How do I include scripts in a qt application? - python

I am trying to use four diferents python scripts in a GUI application.
Every script has around 500 code lines. Then I donĀ“t like to include the every full scrip as a function.
This is the skeleton of the application:
from FullConversor import * #this is the .py gui
import sys
import datetime
import os
import pandas as pd
import shapefile as shp
import csv
import tkinter.filedialog
class FullConversorGUI(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.pushButtonConvert, QtCore.SIGNAL ('clicked()') ,self.conversor)
QtCore.QObject.connect(self.ui.pushButtonClose, QtCore.SIGNAL ('clicked()') ,self.close)
def conversor(self):
if self.ui.radioButton1.isChecked()== True:
pass
if self.ui.radioButton2.isChecked()== True:
pass
if self.ui.radioButton3.isChecked()== True:
pass
if self.ui.radioButton4.isChecked()== True:
pass
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
myapp = FullConversorGUI()
myapp.show()
sys.exit(app.exec_())
Every radioButton must launch a python script, just a .py file who runs fine alone.
How do I do that?

Call import on your script, and run the main function of it when you need.
Pretend you have a script called myscript.py
# this is myscript.py
def main():
# this function will be called from your gui. all your logic should be here.
print "my script"
if __name__ == '__main__':
# this function is called when you invoke the script from the command line.
main()
Then in your gui....
import myscript
if self.ui.radioButton1.isChecked()== True:
myscript.main()
# continue after the script runs
This would result in the following output to stdout:
my script
Obviously, you wouldn't have just a print statement in myscript.py. You can have it run whatever logic you would like.

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.

PyQt4: QProcess readyRead does not always emit correctly

When I use pyqt to run a program I cannot get the output correctly every time.
Here is an example:
from PyQt4 import QtCore, QtGui
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QWidget.__init__(self)
program = "ping"
self.process = QtCore.QProcess()
self.process.readyRead.connect(self.readoutput)
self.process.start(program)
def readoutput(self):
print str(self.process.readAll())
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
In this case, the output is the helper of the ping command, as I would expect. Although if I change the program variable to some other value it doesn't always work, for example if i do:
program = "pyinstaller"
it does not print the helper of pyinstaller as it happens in the console.
How am I supposed to get the output in this case?
pyinstaller might be printing to stderr instead of stdout. You can cause QProcess.readAll() to return both outputs by calling (before self.process.start(program))
setProcessChannelMode(QProcess.MergedChannels)

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).

PyQt SystemTrayIcon won't show when i set the application to start after login

I have this application that controls a deamon of mine. It basically checks if the deamon is already running, if so it gives the option to close, if not it gives the option to close, also it offers you a log of it, and everything is on a menu that opens from a QSystemTrayIcon. When I run it it works perfectly fine, but when I set it to run automatically after i log in it runs, but the trayicon doesn't show, you can even see the process with "ps aux". I'm running on Ubuntu 12.04.
#!/usr/bin/env python
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from subprocess import call
from subprocess import Popen
import os
import time
class SystemTrayIcon(QtGui.QSystemTrayIcon):
def __init__(self, parent=None):
QtGui.QSystemTrayIcon.__init__(self, parent)
self.setIcon(QtGui.QIcon("./mail_open_process.png"))
global closeAction
global openAction
global startOnLaunch
self.menu = QtGui.QMenu(parent)
openAction = self.menu.addAction("Open")
closeAction = self.menu.addAction("Close")
logAction = self.menu.addAction("Log")
startOnLaunch = self.menu.addAction("Start on Launch")
startOnLaunch.setCheckable(True)
exitAction = self.menu.addAction("Exit")
self.setContextMenu(self.menu)
self.connect(openAction,QtCore.SIGNAL('triggered()'),self.openDaemon)
self.connect(closeAction,QtCore.SIGNAL('triggered()'),self.closeDaemon)
self.connect(logAction,QtCore.SIGNAL('triggered()'),self.openLog)
self.connect(exitAction,QtCore.SIGNAL('triggered()'),self.Exit)
#self.connect(startOnLaunch,QtCore.SIGNAL('triggered()'),self.startLaunch)
if os.path.exists("/dev/repa"):
closeAction.setVisible(True)
openAction.setVisible(False)
else:
closeAction.setVisible(False)
openAction.setVisible(True)
def Exit(self):
os.remove("/tmp/daemonMenu.pid")
sys.exit()
def openDaemon(self):
call(["gksu", os.path.expandvars("$HOME")+"/repad/apps/repad -f"])
time.sleep(1)
if os.path.exists("/dev/repa"):
closeAction.setVisible(True)
openAction.setVisible(False)
def closeDaemon(self):
call(["gksu", os.path.expandvars("$HOME")+"/repad/apps/repad -c"])
time.sleep(1)
if not os.path.exists("/dev/repa"):
closeAction.setVisible(False)
openAction.setVisible(True)
def openLog(self):
Popen(["gedit", "/dev/repad.log"])
#def startLaunch(self):
# Dir = "/etc/init.d/S99scriptDaemon"
# if startOnLaunch.isChecked():
# call(["gksu","cp ./S99scriptDaemon /etc/rc5.d"])
#if not startOnLaunch.isChecked():
# call (["gksu","rm /etc/rc5.d/S99scriptDaemon"])
def main():
pid = str(os.getpid())
pidDir = "/tmp/daemonMenu.pid"
if os.path.isfile(pidDir):
pidFile = open(pidDir,"r")
pidLine = pidFile.readline()
call(["kill", "%s" %(pidLine)])
os.remove(pidDir)
file(pidDir, 'w+').write(pid)
if name == 'main':
main()
app = QtGui.QApplication(sys.argv)
trayIcon = SystemTrayIcon()
trayIcon.show()
sys.exit(app.exec_())
I've got the same issue. I made script start.sh and at startup system starts this script. In script I added 10 second delay before starting application. This script seems like this:
sleep 10
./main.py

IPython iterate main loop manually?

Can i somehow instance ipython (or even better, ipython-qtconsole) and step trough its's (IPython's) main loop manually?
I want to edit panda3d programs on the fly.
EDIT1:
Here is code sample which should clarify a bit what i want to do.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from direct.showbase.ShowBase import ShowBase
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.qtApp = QApplication(sys.argv)
label = QLabel("Hello World")
label.show()
self.m = loader.loadModel("frowney")
self.m.reparentTo(render)
while 1:
self.qtApp.processEvents() #manual step trough Qt loop
taskMgr.step() #manual step trough Panda3D loop
app = MyApp()
So you can see how i can manually step trough panda and qt, i want to do same with ipython if its possible.
ANSWER
Complete file:
from direct.showbase.ShowBase import ShowBase
from IPython.lib import inputhook
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.m = loader.loadModel("frowney")
self.m.reparentTo(render)
def stepMe(self):
taskMgr.step() #manual step trough Panda3D loop
return 0
if __name__ == "__main__":
app = MyApp()
inputhook.set_inputhook(app.stepMe)
In your cmd line, just go to directory where file is and do
ipython
run file.py
app.m.setPos(1,1,1)
By "edit panda3d programs on the fly", do you just mean changing things in order to test your running program? Or actually making persistent edits to your program's structure in the interactive environment?
Simply stepping over your loop in an interactive python session is quite easy. You can just replace while 1: with a method declaration such as def step(self):, then call it for each step.
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from direct.showbase.ShowBase import ShowBase
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.qtApp = QApplication(sys.argv)
label = QLabel("Hello World")
label.show()
self.m = loader.loadModel("frowney")
self.m.reparentTo(render)
def step(self):
self.qtApp.processEvents() #manual step trough Qt loop
taskMgr.step() #manual step trough Panda3D loop
return 0 #PyOS_InputHook expects an integer
if __name__ == "__main__":
app = MyApp()
while 1: app.step()
With if __name__ == "__main__" for the main loop, your file will still work as it should when run standalone. But now you can import it into an interactive session and modify things in between steps.
>>> import myfile
>>> app = myfile.MyApp()
>>> app.step()
>>> app.something = something_else
>>> app.step()
Now to add it to IPython's event loop, so it will be run as you use the interpreter, you can use IPython.lib.inputhook.set_inputhook() (new in IPython 0.11).
>>> from IPython.lib import inputhook
>>> inputhook.set_inputhook(app.step)
This should cause your program to run while the interpreter is idle, but still allow manipulation as usual.
Run the script in the ipython debugger using
%run -d -b40 myscript
The -b40 parameter sets a breakpoint in the script on line 40 (which should be the first line of the loop you want to debug). Type c at the prompt to start the script which will stop at the breakpoint. Type h to get help on the debugger.

Categories