I'm trying to make a GUI. The program enables VNC on a device. So when I press GO button, it'll start with "Enabling VNC..." It takes a few seconds to enable. Followed by a "sucCess" message at upon completion. I see this in the terminal.
I'm trying to do the same thing on the GUI. The "enabling vnc" message doesn't even appear until the very end. It appears together with the "success" message. It's like it buffers all GUI output messages together then spits it all out in the end.
Here is what I have:
def actions():
# Enable VNC
if action_VNC.get():
print("Enabling VNC...")
msg_initVNC = "Enabling VNC..." + "\n"
outText.insert(tk.END, msg_initVNC)
#DO STUFF HERE
print('Success. VNC enabled.')
print('########')
msg_outVNC = 'Success. VNC enabled.' + "\n" + '########' +"\n"
outText.insert(tk.END, msg_outVNC)
window.mainloop()
The #DO STUFF HERE enables the VNC and it works. It' takes about 3 -5 seconds to happen. I'd like the program to output the print text to my GUI when it is supposed to and not wait until the end to output everything together. It does this already on the terminal. Thoughts?
I found window.update_idletasks() worked very well for me. So my output code looks like this:
outText.insert(tk.END, msg_seconds)
window.update_idletasks()
It's kinda buffered. GUIs work by "event driven" programming, which means that the visible window is not updated until a function is finished. This means you can't make functions in a GUI that take a long time to complete.
One way around this is to use the threading module.
from threading import Thread
def actions():
# Enable VNC
if action_VNC.get():
print("Enabling VNC...")
msg_initVNC = "Enabling VNC..." + "\n"
outText.insert(tk.END, msg_initVNC)
t = Thread(target=do_stuff, daemon=True)
t.start() # start the worker function in the background
root.bind("<<TaskDone>>", task_done) # listen for the task done event
def do_stuff():
#DO STUFF HERE
root.event_generate("<<TaskDone>>") # send the task done event
def task_done(*args):
print('Success. VNC enabled.')
print('########')
msg_outVNC = 'Success. VNC enabled.' + "\n" + '########' +"\n"
outText.insert(tk.END, msg_outVNC)
window.mainloop()
Related
I'm trying to create a program that spams your screen with terminal windows using threading and would like to create a failsafe button that force quits python when a certain parameter is met. I've tried "os._exit()" and that does not work. I am looking for a way to destroy all threads and force quit python as if my program runs for too long it will crash my computer.
def spam():
for i in range(30):
if i % 10 == 0: # if i is divisible by 10, it pauses for comedic timing
time.sleep(2)
os.system('open -a Terminal .') # opens terminal window
playsound('/Users/omar/Downloads/boom.wav') # plays comical 'vine' funny meme audio
thread = multiprocessing.Process(target=spam) # creates a thread
thread.start()
if pyautogui.failSafeCheck() == True or pynput.keyboard.Controller().type == 'Keyboard':
os._exit() and thread.terminate()
spam() # function call
I want to run a program using the subprocess module. While running the program, there are cases where it waits for a button press to continue. It is not waiting for this input to the stdin input. The input sent to stdin is ignored by the program. Only when I press a button on the console will the program continue running.
I tried it like this:
proc = Popen("festival.exe level.sok", stdin=PIPE, text=True)
proc.stdin.write('.')
proc.stdin.flush()
It this case nothing happened.
and like this:
proc = Popen...
proc.communicate('.')
In this case, the python code will not continue running until I press a button on the console. If I set a timeout then the python code continues to run but festival.exe does not continue to run.
What should I do to make festival.exe continue running?
P.S.: festival.exe is a solver for sokoban. This case occurs when the given level cannot be solved. E.g.:
########
#.. $ $#
# # #
########
assuming you have the festival program like this:
from random import getrandbits
solved = getrandbits(1)
if solved:
print("executed correctly")
else:
print('a error ocurred')
input('press a button to continue')
exit(1)
you can solve with:
from subprocess import Popen, PIPE
p = Popen(['python3','festival.py'],stdin=PIPE)
p.communicate(input=b'any\n')
i'm new in the python language and have been learning and working with it for 2 days now.
I'm writing a code to send grbl files to my cnc-machine.
my code:
def grbl_sturing(Gcode_file):
print('running')
lbl_Running = Label(root, text="running")
lbl_Running.grid(row=0, column=2)
#Grbl setup
poort = serial.Serial('com11',115200)
code = open(Gcode_file,'r');
poort.write(b'\r\n\r\n')
time.sleep(2)
poort.flushInput()
#sturing
for line in code:
l = line.strip()
print ('Sending: ' + l)
poort.write(l.encode() + b'\r\n')
grbl_out = poort.readline()
print (' : ' + str(grbl_out.strip()))
#Grbl afsluiten
code.close()
poort.close()
So when i press a button in my tkinter window i go to this fucntion. My intensions where to let me know in a label and in my cmd that the program is sending/running.
But when i press this button my cmd show this:
running
Sending: $H
: b'ALARM:9'
Don't mind the alarm its because the cnc-machine isn't powered.
In the cmd it works like itended but when i look in my tkinter window it runs first and when its done it shows me that it is running. Why does it do this and how can i fix it? thank you in advance.
ps(sorry for my bad English)
So, what is happening here is that you are creating the label, but the GUI isn't updating until later, to make it update in that order you must use the line:
TK.update()
Where TK is your tkInter variable to force the interface to update at that point, instead of waiting for the main loop.
I'm not too familiar with threading, and probably not using it correctly, but I have a script that runs a speedtest a few times and prints the average. I'm trying to use threading to call a function which displays something while the tests are running.
Everything works fine unless I try to put input() at the end of the script to keep the console window open. It causes the thread to run continuously.
I'm looking for some direction in terminating a thread correctly. Also open to any better ways to do this.
import speedtest, time, sys, datetime
from threading import Thread
s = speedtest.Speedtest()
best = s.get_best_server()
def downloadTest(tries):
x=0
downloadList = []
for x in range(tries):
downSpeed = (s.download()/1000000)
downloadList.append(downSpeed)
x+=1
results_dict = s.results.dict()
global download_avg, isp
download_avg = (sum(downloadList)/len(downloadList))
download_avg = round(download_avg,1)
isp = (results_dict['client']['isp'])
print("")
print(isp)
print(download_avg)
def progress():
while True:
print('~ ',end='', flush=True)
time.sleep(1)
def start():
now=(datetime.datetime.today().replace(microsecond=0))
print(now)
d = Thread(target= downloadTest, args=(3,))
d.start()
d1 = Thread(target = progress)
d1.daemon = True
d1.start()
d.join()
start()
input("Complete...") # this causes progress thread to keep running
There is no reason for your thread to exit, which is why it does not terminate. A daemon thread normally terminates when your programm (all other threads) terminate, which does not happen in this as the last input does not quit.
In general it is a good idea to make a thread stop by itself, rather than forcefully killing it, so you would generally kill this kind of thread with a flag. Try changing the segment at the end to:
killflag = False
start()
killflag = True
input("Complete...")
and update the progress method to:
def progress():
while not killflag:
print('~ ',end='', flush=True)
time.sleep(1)
I want to monitor the change of track in Rhythmbox using python. I want to continuously check for change of track and execute a set of functions if the track is changed. I have written a piece of code which gets hold of the Rhythmbox interfaces from the dbus and gets the current track details. But this program has to be run manually to check for any change.
I am new to this and I would like to know how we can create a background process which continuously runs and checks Rhythmbox.
I dont want to make a Rhythmbox plugin(which rather would make my work simple) as I will be extending the application to listen to multiple music players.
Please suggest me what exactly I would have to do to achieve the functionality.
The Rhythmbox player object (/org/gnome/Rhythmbox/Player) sends a playingUriChanged signal whenever the current song changes. Connect a function to the signal to have it run whenever the signal is received. Here's an example that prints the title of the song whenever a new song starts, using the GLib main loop to process DBus messages:
#! /usr/bin/env python
import dbus
import dbus.mainloop.glib
import glib
# This gets called whenever Rhythmbox sends the playingUriChanged signal
def playing_song_changed (uri):
global shell
if uri != "":
song = shell.getSongProperties (uri)
print "Now playing: {0}".format (song["title"])
else:
print "Not playing anything"
dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
bus = dbus.SessionBus ()
proxy = bus.get_object ("org.gnome.Rhythmbox", "/org/gnome/Rhythmbox/Player")
player = dbus.Interface (proxy, "org.gnome.Rhythmbox.Player")
player.connect_to_signal ("playingUriChanged", playing_song_changed)
proxy = bus.get_object ("org.gnome.Rhythmbox", "/org/gnome/Rhythmbox/Shell")
shell = dbus.Interface (proxy, "org.gnome.Rhythmbox.Shell")
# Run the GLib event loop to process DBus signals as they arrive
mainloop = glib.MainLoop ()
mainloop.run ()
Take a look at the Conky script here:
https://launchpad.net/~conkyhardcore/+archive/ppa/+files/conkyrhythmbox_2.12.tar.gz
That uses dbus to talk to rhythmbox, like so:
bus = dbus.SessionBus()
remote_object_shell = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell')
iface_shell = dbus.Interface(remote_object_shell, 'org.gnome.Rhythmbox.Shell')
remote_object_player = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Player')
iface_player = dbus.Interface(remote_object_player, 'org.gnome.Rhythmbox.Player')
You can call a number of functions on iface_player to get the required information. It looks like you'll have to poll from this example though. If you want to receive a message from dbus on track change you'll have to do that in a different way. This discusses from avenues to explore:
http://ubuntuforums.org/showthread.php?t=156706
I am using Ubuntu 14.04.1 and the above script is deprecated for Rhythmbox 3. I am using this script to write the current song to ~/.now_playing for BUTT to read, but you can update it for your needs. Rhythmbox uses MPRIS now and you can get info here:
http://specifications.freedesktop.org/mpris-spec/latest/index.html
#!/usr/bin/python
import dbus
import dbus.mainloop.glib
import glib
# This gets called whenever Rhythmbox sends the playingUriChanged signal
def playing_song_changed (Player,two,three):
global iface
global track
global home
track2 = iface.Get(Player,"Metadata").get(dbus.String(u'xesam:artist'))[0] + " - "+ iface.Get(Player,"Metadata").get(dbus.String(u'xesam:title'))
if track != track2:
track = iface.Get(Player,"Metadata").get(dbus.String(u'xesam:artist'))[0] + " - "+ iface.Get(Player,"Metadata").get(dbus.String(u'xesam:title'))
f = open( home + '/.now_playing', 'w' )
f.write( track + '\n' )
f.close()
dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
bus = dbus.SessionBus ()
from os.path import expanduser
home = expanduser("~")
player = bus.get_object ("org.mpris.MediaPlayer2.rhythmbox", "/org/mpris/MediaPlayer2")
iface = dbus.Interface (player, "org.freedesktop.DBus.Properties")
track = iface.Get("org.mpris.MediaPlayer2.Player","Metadata").get(dbus.String(u'xesam:artist'))[0] + " - "+ iface.Get("org.mpris.MediaPlayer2.Player","Metadata").get(dbus.Strin$
f = open( home + "/.now_playing", 'w' )
f.write( track + '\n' )
f.close()
iface.connect_to_signal ("PropertiesChanged", playing_song_changed)
# Run the GLib event loop to process DBus signals as they arrive
mainloop = glib.MainLoop ()
mainloop.run ()
Something like:
from time import sleep
execute = True
while execute:
your_function_call()
sleep(30) # in seconds; prevent busy polling
Should work just fine. If that was hooked up to something that listened to signals (import signal) so that you could set execute to False when someone ctrl-c's the application, that'd be basically what you're after.
Otherwise, have a Google for daemonisation (which involves forking the process a couple of times); from memory, there's even a decent Python library now (which, from memory, requires 2.5/2.6 with statements) which would help make that side of things easier :).