What is the best way to display system notifications with Python, preferably using tkinter for cross platform implementation (I am on OS X, so I'm also open to implementations that would allow integration with Notification Center)?
I want to show a self-destroying message, I mean something that would remain on screen for a few seconds and then would vanish way, but without interfering with user interaction. I don't want to use a messagebox because in requires the user to click in a button to dismiss the message window.
What do you recommend?
This works for me. It shows the message as a popup and exits after 2 seconds.
from tkinter import *
from sys import exit
def popupError(s):
popupRoot = Tk()
popupRoot.after(2000, exit)
popupButton = Button(popupRoot, text = s, font = ("Verdana", 12), bg = "yellow", command = exit)
popupButton.pack()
popupRoot.geometry('400x50+700+500')
popupRoot.mainloop()
Related
I've been trying to create a message box when a button turns from disabled to active but when the button actually turns from disabled to active for some reason my callback is not even being called I've tried to get it working so for quite a bit of time now and I'm stuck.
Here is an example of the problem:
from tkinter import *
from tkinter import Tk
def disable_and_activate():
b.config(state = DISABLED)
b.config(state = ACTIVE)
def is_working(event):
print('working')
root = Tk()
b = Button (root, text = 'click me', command = disable_and_activate)
b.pack()
b.bind('<Activate>', is_working)
root.mainloop()
Console:
the button is clicked but there's nothing printed on the console
The <Activate> event is not triggered when you set the state of the button to "active". The event is triggered when the window becomes the active window.
For example, when I run your code on my OSX machine, if I click on some other application to give it focus and then I click back to the tkinter window, the event will fire when the tkinter window becomes the active window.
This is explained in the canonical tcl/tk documentation which says this:
Activate, Deactivate
These two events are sent to every sub-window of a toplevel when they change state. In addition to the focus Window, the Macintosh platform and Windows platforms have a notion of an active window (which often has but is not required to have the focus). On the Macintosh, widgets in the active window have a different appearance than widgets in deactive windows. The Activate event is sent to all the sub-windows in a toplevel when it changes from being deactive to active. Likewise, the Deactive event is sent when the window's state changes from active to deactive. There are no useful percent substitutions you would make when binding to these events.
Here the problem was just the code inside the function , It seems like you needed to call EventGenerate('<<Activate>>') I also recommend adding 2 << and 2 >>
So I rewrote the code and its now working perfectly fine:
from tkinter import *
from tkinter import Tk
import tkinter
def disable_and_activate():
b.configure(state=tkinter.DISABLED)
b.configure(state=tkinter.ACTIVE)
b.event_generate("<<Activate>>")
def is_working(event):
print('working')
root = Tk()
b = Button (root, text = 'click me', command = disable_and_activate)
b.pack()
b.bind('<<Activate>>', is_working)
root.mainloop()
I am coding a sign in and I would like there to be no way out unless signin is complete. But in order to do that I need to disable the Windows key so they cannot leave the window. I is has no header, I disabled the WM delete window protocol, I have automatic full screen. I also need to make it dynamically set itself to the middle but I am not that far. Messagebox import works.
My Code:
from tkinter import *
import messagebox
from win32api import GetSystemMetrics
def getfullscreensize():
global width
width = GetSystemMetrics(0)
global height
height = GetSystemMetrics(1)
def donothing():
pass
root = Tk()
root.attributes('-fullscreen', True)
root.protocol("WM_DELETE_WINDOW", donothing)
root.overrideredirect(1)
root.bind("<key>", lambda e: "break")
root.mainloop()
How to disable Windows key using tkinter?
In short, you can't. Tkinter does not have any features that allow it to disable OS-level features like the windows key.
In order to disable this key you'll have to find some other platform-specific solution.
This is my first question.
I have a python program that recognize voice and reply with voice.
I wish to add a little GUI for my program (it should have only an image on background and a button to quit the program)
I would like that when I launch my code from terminal, it opened a Tkinter window and at the same time the python program start.
I’m working on Mac Os.
I use speech_recognition package to recognize voice and I use NSS speaker to let my computer speak.
This is a example of my code:
import speech_recognition as sr
from AppKit import NSSpeechSynthesizer
#VARIABLES
L = sr.Recognizer() #LISTENING
nssp = NSSpeechSynthesizer #SPEAKING
S = nssp.alloc().init()
while True:
audio = L.listen(source)
s = L.recognize_google(audio, language="en-US")
if s == "hi":
S.startSpeakingString_("Hello!!!")
Where do I have to write the Tkinter instructions to make sure that when I run my code it opens only a Tkinter window (while my program goes on) and not a shell's one?
You'll find it difficult to introduce your GUI as your code has already been written, note that everything in Tkinter has to be stored in some sort of Label or Widget and so you can't just print what you already have onto the Tkinter screen.
Here is some code to create a basic Tkinter window. Try searching online and playing around with how to present your variables within said window
import tkinter
from tkinter import *
root = tkinter.Tk()
root.configure(background = "#66ffdd") #here you can use any hex color code or just leave it blank and configure as default
root.title("Voice Program") #use the name of your program (this is the window header/title)
root.geometry("800x500") #these are your window dimensions
welcome = tkinter.Message(root, text = "Welcome to my program")
button = tkinter.Button(root, text="This button", command=print("hello")) #here insert a function for the button to perform i.e quit
welcome.pack()
button.pack() #packing presents your variables to the window - you can also use other geometry managers like grid
This site is really useful for showing you what widgets are available and what you can do with them - try searching any issues or posting a more specific question in the future if you struggle.
http://effbot.org/tkinterbook/button.htm
I am trying to get keypresses in Python (2.7.10), bit I had no luck with getch(), as ord(getch()) was returning 255 constantly, so I am now using Tkinter. (I believe that Tkinter is also cross-platform so that should help as i plan to run this script on a Linux device).
I need to be able to get keypresses, even if they are not pressed while the Tkinter window is not active.
Here is my code:
from Tkinter import *
import time, threading
x = "Hi!"
def callback(event):
x = "key: " + event.char
print(x)
def doTk():
root = Tk()
root.bind_all("<Key>", callback)
root.withdraw()
root.mainloop()
thread1 = threading.Thread(target=doTk)
thread1.deamon = True
thread1.start()
I am not reveiving any errors, it is not not registering keypresses. I have also tried this without using threading, but it still does not work.
Please also note that I cannot use raw_input() as I need this to be able to run in the background and still get keypresses.
I am aware that this does not produce a frame, I do not want it to.
Thanks in advance for any help :)
PS: I have looked to other answers on StackOverflow and other sites, but they all either don't work or give solutions where keypresses are only registered when the tkinter frame is active.
I am creating a little time management tool, using Tkinter, so I can keep on task at work. I am having trouble with one aspect that I cannot seem to get working. I'm using the error box so that it is displayed in front of all other windows.
As it is now, the program starts a new thread on a function that keeps track of time, and compares it to the time the user entered for their task. Once real time > the time entered by the user, it starts another thread to spawn the tkMessageBox. I have tried this without starting a new thread to spawn the tkMessageBox, and the problem is the same. If the user enters the same time for 2 separate tasks, the error pop up freezes. I'm having trouble finding information on this topic specifically... The behaviour is odd because if I have 2 alerts, lets say 1 at 0600 and one at 0601, but I do not close the first error box that pops up and let it stay up until the second alert triggers, the second alert will just replace the first one(I would like multiple error boxes to pop up if possible). It's only the alerts that have the same trigger time that cause the pop up to freeze though.
This is my first GUI program and only started learning the concept of threading, and GUIs in the past 24 hours, so I'm not sure if this is a problem with threading or the tkMessageBox. Because of the behaviour of the error box, I’m thinking it is the thread module combined with the tkMessageBox module. The command I'm using is:
tkMessageBox.showerror('TIMER ALERT!!!', comp_msg)
Here is the source I put comments in there to help. The tkMessageBox I’m talking about is line 56.
I guess I'm not sure if I can even do what I am trying to do with the pop-up box, if I can, I'm not sure how. If I can't, is there a alternative way to spawn multiple error type pop-up boxes with Tkinter? I just want multiple boxes to be able to appear at any given time.
Thanks in advance, and I really appreciate any help at all.
EDIT:
import thread
from Tkinter import *
#Spawns Error Box. Runs in it's own thread.
def message_box(comp_msg,q): # q is an empty string because of thread module.
print "Spawning Error Box..."
eb =Toplevel()
eb.config(master=None,bg="red")
pop_l = Label(eb,text="ALERT!!!")
pop_l2=Label(eb,text=comp_msg)
pop_l.pack(pady=10,padx=10)
pop_l2.pack(pady=15,padx=10)
return eb
thread.start_new_thread(message_box,(comp_msg,""))
tkmessageBox default dialog boxes are modal. You could implement a simple none modal dialog box for this application. Here is a good document about creating custom dialog boxes.
This way you can create as many new custom dialog boxes as your app requires, since each one is just a new Toplevel.
Here is a simple Tkinter app that shows the clock on the main window. When you click on the button it starts new tkMessageBox dialog boxes in new threads. (If you run it) You could see that the main thread that runs the TK event loop is working (since the time is getting updated), but the error boxes are not showing up as expected.
#!/usr/bin/env python
import datetime
import threading
from Tkinter import *
import tkMessageBox
class MyApp(Frame):
def __init__(self, root=None):
if not root:
root = Tk()
self.time_var = StringVar()
self.time_var.set('starting timer ...')
self.root = root
Frame.__init__(self, root)
self.init_widgets()
self.update_time()
def init_widgets(self):
self.label = Label(self.root, textvariable=self.time_var)
self.label.pack()
self.btn = Button(self.root, text='show error', command=self.spawn_errors)
self.btn.pack()
def update_time(self):
self.time_var.set( str(datetime.datetime.now()) )
self.root.after(1000, self.update_time)
def spawn_errors(self):
for i in range(3):
t = threading.Thread(target=self.show_error)
t.start()
def show_error(self):
now = datetime.datetime.now()
tkMessageBox.showerror('Error: %s' % (str(now)), now)
if __name__ == '__main__':
app = MyApp()
app.mainloop()