Activating and Disabling button after process in python and pyGTK - python

Essentially, I am trying to make a button "active" first, run a process, and then after that process has finished running, disable the button again.
Using pyGTK and Python, the code in question looks like this...
self.MEDIA_PLAYER_STOP_BUTTON.set_sensitive(True) #Set button to be "active"
playProcess = Popen("aplay " + str(pathToWAV) + " >/dev/null 2>&1",shell=True) #Run Process
playProcess.wait() #Wait for process to complete
self.MEDIA_PLAYER_STOP_BUTTON.set_sensitive(False) #After process is complete, disable the button again
However, this does not work at all.
Any help would be greatly appreciated.

All is working normally (python 2.7.3). But if you call playProcess.wait() in gui thread - you freeze gui thread without redrawing (sorry, my english isn`t very well). And are you sure that you try to use subprocess.popen()? Maybe os.popen()?
My small test:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk, gtk, gtk.glade
import subprocess
def aplay_func(btn):
btn.set_sensitive(True)
print "init"
playProcess = subprocess.Popen("aplay tara.wav>/dev/null 2>&1", shell=True)
print "aaa"
playProcess.wait()
print "bbb"
btn.set_sensitive(False)
wTree = gtk.glade.XML("localize.glade")
window = wTree.get_widget("window1")
btn1 = wTree.get_widget("button1")
window.connect("delete_event", lambda wid, we: gtk.main_quit())
btn1.connect("clicked", aplay_func)
window.show_all()
gtk.main()
Result:
init
aaa
bbb
And yes, button is working correctly. Sound too.

Related

tkinter not responding when executing command + progressbar. (multi-thread)

for my project I have implemented a graphical interface that interfaces with wearable sensors.
I wrote a code (multi.py) that interfaces directly with 3 sensors. then I wrote some code for the graphical interface (GUI.py) which calls me different portions of multi.py when I click the buttons.
when I call "configure_clicked ()" and "download_clicked ()" form respective button the GUI freezes (continuing to work), because functions are called (multi.configure & multi.download ) that take some time to finish (connecting to devices and downloading data from devices). I know that I have to do another "thread"--> MULTITHREAD. please,Can anyone help me to create a multithread???
I also have "PROGRESS BAR" which should start at the start of each function but this does not happen for "configure_clicked ()" and "download_clicked ()", while I manage to slide it between "start_clicked" and "stop_clicked".
I am attaching the code.
thank in advance whoever will help me.
from tkinter import *
from tkinter import messagebox, ttk
import multi_sensor_acc_gyro1 as multi
class GUI:
def __init__(self,master):
self.master=master
self.states=[]
...
...
#configure button
self.btn_configure=Button(self.quadro_pulsanti_sx,relief=RAISED,command=self.configure_clicked)
#start button
self.btn_start=Button(self.quadro_pulsanti_dx,command=self.start_clicked,relief=RAISED)
#stop button
self.btn_stop=Button(self.quadro_pulsanti_dx,command=self.stop_clicked,relief=RAISED)
#download button
self.btn_download=Button(self.quadro_pulsanti_dx,command=self.download_clicked,relief=RAISED)
#save button
self.btn_save=Button(self.quadro_pulsanti_dx,relief=RAISED,command=self.save_clicked)
#reset button
self.btn_reset=Button(self.quadro_pulsanti_sx,relief=RAISED,command=self.reset_clicked)
#progress bar
self.pb=ttk.Progressbar(self.quadro_pulsanti_basso,orient=HORIZONTAL,length=350,mode="indeterminate")
self.label_pb=Label(self.quadro_pulsanti_basso,text="")
def configure_clicked(self):
mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
output_1=multi.configure(mac_address)
self.states=output_1[0]
self.loggers_acc=output_1[1]
self.loggers_gyro=output_1[2]
self.label_pb.configure(text="")
messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\nclick OK to continue")
def start_clicked(self):
multi.start(self.states)
self.pb.start()
self.label_pb.configure(text="registration in progress...")
def stop_clicked(self):
self.pb.stop()
self.label_pb.configure(text="")
multi.stop(self.states)
def download_clicked(self):
#self.pb.start()
#self.label_pb.configure(text="Download in progress...")
output_2=multi.download(self.states,self.loggers_acc,self.loggers_gyro)
self.df_tr_tot=output_2[0]
self.df_gd_tot=output_2[1]
self.df_gs_tot=output_2[2]
#self.label_pb.configure(text="")
#self.pb.stop()
messagebox.showinfo("DOWNLOAD clicked","the data has been downloaded\n\nclick OK to continue")
def save_clicked(self):
#self.txt_pz.focus_set()
#self.txt_pz.get()
self.txt_pz.focus_set()
id_pz=self.txt_pz.get()
multi.save(self.df_tr_tot,self.df_gd_tot,self.df_gs_tot,id_pz)
messagebox.showinfo("SAVE clicked","I dati sono stati salvati\n\ncliccare OK per continuare")
window = Tk()
window.title(" Grafic User Interface for MMR")
window.iconbitmap('C:/Users/salvo/Documents/MetaWear-SDK-Python/examples/favicon.ico')
height=560
width=540
left=(window.winfo_screenwidth()-width)/2
top=(window.winfo_screenheight()-height)/2
geometry="%dx%d+%d+%d" % (width,height,left,top)
window.geometry(geometry)
gui=GUI(window)
window.mainloop()
This is how you make sure tkinter doesn't stop responding while running a long task:
import threading
from time import sleep
def operation():
# Create a new thread
new_thread = threading.Thread(target=_operation, daemon=True)
# Start the thread
new_thread.start()
# continue code or run this:
while new_thread.is_alive(): # While the new thread is still running
# Here you can also add a loading screen
# Make sure tkinter doesn't say that it isn't responding
tkinter_widget.update() # `tkinter_widget` can be any tkinter widget/window
sleep(0.1) # A bit of delay so that it doesn't use 300% of your CPU
def _operation()
# Here you can do the operation that will take a long time
pass
When you need to run the operation call operation and it will start the new thread. NOTE: make sure that you don't have any tkinter stuff in the new thread because tkinter would crash.
What is happening is that your calculations and Tkinter all exist in the same thread so in order to perform calculations execution of Tkinter's mainloop() has to be paused until those processes have completed. The simplest solution is to add some helper methods and call them in separate threads when buttons are pressed:
from threading import Thread
def configure_clicked(self):
t = Thread(target=self._configure_clicked)
t.start()
def _configure_clicked(self):
mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
output_1=multi.configure(mac_address)
self.states=output_1[0]
self.loggers_acc=output_1[1]
self.loggers_gyro=output_1[2]
self.label_pb.configure(text="")
messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\nclick OK to continue")
And you do similar things to all other methods. After that all shall work fine.

PyQt5: Looking for example of Embedding external app window in Application

I have a largeish application I'm developing in Python3 using PyQt5. I want to do something very much like what is being done here in PyQt4:
# -*- coding: utf-8 -*-
import atexit
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class XTerm(QX11EmbedContainer):
def __init__(self, parent, xterm_cmd="xterm"):
QX11EmbedContainer.__init__(self, parent)
self.xterm_cmd = xterm_cmd
self.process = QProcess(self)
self.connect(self.process,
SIGNAL("finished(int, QProcess::ExitStatus)"),
self.on_term_close)
atexit.register(self.kill)
def kill(self):
self.process.kill()
self.process.waitForFinished()
def sizeHint(self):
size = QSize(400, 300)
return size.expandedTo(QApplication.globalStrut())
def show_term(self):
args = [
"-into",
str(self.winId()),
"-bg",
"#000000", # self.palette().color(QPalette.Background).name(),
"-fg",
"#f0f0f0", # self.palette().color(QPalette.Foreground).name(),
# border
"-b", "0",
"-w", "0",
# blink cursor
"-bc",
]
self.process.start(self.xterm_cmd, args)
if self.process.error() == QProcess.FailedToStart:
print "xterm not installed"
def on_term_close(self, exit_code, exit_status):
print "close", exit_code, exit_status
self.close()
(from https://bitbucket.org/henning/pyqtwi...11/terminal.py)
which is: Embed an X11 shell terminal (xterm) into a tab of my application.
I understand that QX11EmbedContainer is not in PyQt5, and that some usage of createWindowContainer may be the new approach, but I cannot find any example of this in action to follow.
I would ideally like to see the above code ported to a fully functional example using PyQt5 conventions and methods, but any assistance in any form will be helpful.
I have looked at Embedding external program inside pyqt5, but there is only a win32 solution there, and I need to run on Linux and MacOS, with windows being an unnecessary nicety, if there was a generalized solution to fit all 3. It feels like this is close, but I cannot find the appropriate replacement for the win32gui module to use in a general implementation.
I have looked at example of embedding matplotlib in PyQt5 1, but that pertains to matplotlib in particular, and not the general case.
All pointers and help will be gratefully acknowledged.

Running a Qt event loop at the R prompt

I'm trying to create a Qt application that can communicate with R via PyQt and the rPython package and remain responsive while the R prompt is live.
Here's a minimal PyQt4 script that creates a button in a window that prints "clicked" when you click it.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
class Ui_simple(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Test")
Dialog.resize(200,200)
self.pushButton = QPushButton(Dialog)
QObject.connect(self.pushButton, SIGNAL("clicked()"), self.clicked)
def clicked(self):
print "Clicked"
class main(object):
def __init__(self):
self.app = QApplication([])
self.Dialog = QDialog()
self.ui = Ui_simple()
self.ui.setupUi(self.Dialog)
self.Dialog.show()
When run from the Python prompt, the application becomes active when the QDialog object is created and shown. The python prompt returns. I can then exec_ the application object, and I get the prompt back when I quit the dialog:
>>> import simple
>>> a = simple.main()
>>> Clicked [python prompt is back now, I'm clicking the button]
Clicked
>>> a.app.exec_()
Clicked
This behaviour - of being interactive while also waiting for Python text prompt input - is because PyQt4 installs an input hook that waits for keyboard input and processes events.
What I want to do is have this same behaviour with Qt dialogs called from R via the rPython package. The following displays the dialog but it does not appear until the exec_ call, and the R prompt does not return until the application is exited by quitting the dialog window:
> require(rPython)
Loading required package: rPython
Loading required package: RJSONIO
> python.load("simple.py")
> python.exec("a = main()") # nothing happens
> python.exec("a.app.exec_()") # dialog appears, R blocked
Clicked
Clicked # click the buttons
Clicked
0 # kill window now
> # back to R prompt
A solution to my problem would involve the dialog appearing when running a=main() and the R prompt reappearing at that point too.
There are some Qt-based R packages that appear to create dialogs that remain interactive when the R prompt is active, but they are mostly in C and I'm not sure if that make a big difference. See qtutils for example.
There is some event loop handling in qtbase but I'm not sure if something like that is possible for Qt apps called from rPython. All ideas welcome.

Make a vte terminal communicate with running python script

I am trying to achieve the following. I built some gtk application which will have some data, let's say a,b and c.
What I want now is some sort of terminal window in which I can query and change the data as I would in e.g. iPython:
$ a
[1 2 3]
$ a= a+1
$ a
[2 3 4]
And let this take effect in the gtk application. Is this doable?
You can try to launch xterm by subprocess, and to communicate between file.py and term, copy the vars in environment variable, and get it by:
os.environ[your_var]
Take a look of this. Once you are in type "python". About communicating with the script, the only way that I've found is with an external file. What you want it is possible but complicated. here you have an example that i made where i return the variable "tty" from the VTE terminal to the python script.
from gi.repository import Gtk, GObject, Vte
#GObject is not required. I just import it everywhere just in case.
#Gtk, Vte, and GLib are required.
from gi.repository import GLib
import os
#os.environ['HOME'] helps to keep from hard coding the home string.
#os is not required unless you want that functionality.
class TheWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="inherited cell renderer")
self.set_default_size(600, 300)
self.terminal = Vte.Terminal()
self.terminal.fork_command_full(
Vte.PtyFlags.DEFAULT, #default is fine
os.environ['HOME'], #where to start the command?
["/bin/sh"], #where is the emulator?
[], #it's ok to leave this list empty
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
None, #at least None is required
None,
)
#Set up a button to click and run a demo command
self.button = Gtk.Button("Do The Command")
#To get the command to automatically run
#a newline(\n) character is used at the end of the
#command string.
self.command = "echo \"Sending this command to a virtual terminal.\"\n"
command = Gtk.Label("The command: "+self.command)
self.button.connect("clicked", self.InputToTerm)
#end demo command code
#set up the interface
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.pack_start(self.button, False, True, 0)
box.pack_start(command, False, True, 1)
#a scroll window is required for the terminal
scroller = Gtk.ScrolledWindow()
scroller.set_hexpand(True)
scroller.set_vexpand(True)
scroller.add(self.terminal)
box.pack_start(scroller, False, True, 2)
self.add(box)
def InputToTerm(self, clicker):
#get the command when the button is clicked
length = len(self.command)
#A length is not required but is the easiest mechanism.
#Otherwise the command must be null terminated.
#Feed the command to the terminal.
self.terminal.feed_child(self.command, length)
win = TheWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

How to close 1st window after opening 2nd window in pygtk

In my pygtk app, I want to close current window after opening next window.
this is the code which i have written
#!/usr/bin/env python
# example base.py
import pygtk
pygtk.require('2.0')
import gtk
import subprocess
class Base:
def next(self,widget):
subprocess.call('fabfile.py', shell=True)
self.window.destroy()
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_size_request(200,200)
self.button = gtk.Button("Hello World")
self.button.show()
self.button.connect("clicked", self.next)
self.window.add(self.button)
self.window.show()
def main(self):
gtk.main()
print __name__
if __name__ == "__main__":
base = Base()
base.main()
when I click on next button it opens next window but it does not close my current window in background and current window go to hang in background after opening next window.
def next(self,widget):
subprocess.call("scan.py", shell=True)
self.win.destroy()
when i run this code in window machine it is not closing existing window and when i run in Linux machine it is giving this error.
/bin/sh: fabfile.py: command not found
Anyone let me know how to do this.
Thanks...
Try this, I hope it will work,
import subprocess
proc=subprocess.Popen(["fabfile.py"], bufsize=2048, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
proc.wait()
self.win.destroy()
or
import subprocess
proc=subprocess.Popen(["fabfile.py"], bufsize=2048, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
completed = False
while not completed:
if process.poll() is not None:
completed = True
print "communicating"
process.communicate("k")
print "communicated"
subprocess.Popen will open your 2nd window and close after current window.
Update
For linux you have to write below code when you will use subprocess call
The script contains CR characters. The shell interprets these CR characters as arguments.
Solution: Remove the CR characters from the script using the following script.
with open('beak', 'rb+') as f:
content = f.read()
f.seek(0)
f.write(content.replace(b'\r', b''))
f.truncate()
for more clarification you can see this recorded link
http://www.python.org/doc//current/library/subprocess.html#convenience-functions
Run command with arguments. Wait for command to complete, then return
the returncode attribute.
The call to subprocess.call is blocking, win.destroy nor any GTK function will be executed until your scan.py app has exited. In C, you'd use g_spawn_async from GLib, you should be able to figure out the Python equivalent. Or use a thread.

Categories