I have a ComboBox written in Python Tkinter that makes the horrible system alert sound when you click off of it without selecting something.
For instance, when you hit the dropdown and select your item, it works fine. But if you hit the drop-down and then decide to click off, it will lose focus as expected, but it makes an alert sound. Can this be disabled in some way so it can gracefully lose focus without complaining? I'm on OSX 10.9 btw
UPDATE -
Minimally working code that produces the alert.
from Tkconstants import *
import ttk
import Tkinter
class PyPrecursor():
def __init__(self,root):
self.root = root
self.TabNotebook()
def TabNotebook(self):
self.main_notebook_frame = ttk.Notebook(self.root, name='main_notebook')
self.main_notebook_frame.enable_traversal()
self.OptionsF = ttk.Frame(self.main_notebook_frame, name='options')
self.length_options_frame = ttk.LabelFrame(
self.OptionsF, labelwidget=ttk.Label(font=('Arial', 15), text="Length Options:"))
self.hcdr3_length_label = ttk.Label(self.length_options_frame, text="HCDR3 Length")
self.HCDR3_Length = Tkinter.StringVar()
self.hcdr3_length_combo = ttk.Combobox(
self.length_options_frame, values=[i for i in xrange(16, 36)],
textvariable=self.HCDR3_Length)
self.hcdr3_length_combo.current(0)
self.length_options_frame.pack(side=TOP,fill=X,pady=5)
self.hcdr3_length_label.pack(side=LEFT)
self.hcdr3_length_combo.pack(side=LEFT,anchor=W)
self.main_notebook_frame.pack(side=TOP,expand=1,fill=BOTH,padx=10,pady=10)
self.main_notebook_frame.add(
self.OptionsF, text="Input Options", underline=0, padding=2)
self.main_notebook_frame.bind("<<NotebookTabChanged>>",self.update_)
def update_(self,event):
self.root.update()
def main():
root = Tkinter.Tk()
PyPrecursor(root)
root.mainloop()
root.update_idletasks()
if __name__ == '__main__':
main()
You might want to try this:
self.hcdr3_length_combo.bell(displayof=1)
Not sure if it should be 1 or 0 though...
If it doesn't work, maybe a containing widget throws the sound. Might want to apply it to the parent widget as well. I'm not familiar with python 2.7 and it doesn't throw a sound when I use python3 with slight modifications.
Usually when you can't find an option for a specific widget, you can find something in the general widget options. Just search "tkinter widget options" and you'll get some place like:
https://effbot.org/tkinterbook/widget.htm
Related
I'm trying to make a drop-down menu for tkinter gui (Combobox). The code has no errors, but drop-down menu is not working. I'm using PyCharm, macOS. Please see the code below.
import tkinter as tk
from tkinter import ttk
import sys
class cpuMon(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry('400x400+1+1')
self.attributes('-alpha', 1)
self.attributes('-topmost', True)
self.resizable(False, False)
self.title('CPU Monitor')
self.set_ui()
def set_ui(self):
exitButton = ttk.Button(self, text='Exit', command=self.exit_app)
exitButton.pack(fill=tk.X)
self.bar2 = ttk.LabelFrame(self, text='Manual')
self.bar2.pack(fill=tk.X)
ttk.Button(self.bar2, text='Move').pack(side=tk.LEFT)
ttk.Button(self.bar2, text='>>>').pack(side=tk.LEFT)
self.combo_win = ttk.Combobox(self.bar2, state='readonly', values=["hide", "don't hide", "min"])
self.combo_win.pack(side=tk.LEFT)
So, I had to fix a few things to get this to run (i.e., instantiating app = cpuMon() and calling app.mainloop(). Likewise, I replaced self.exit_app with self.quit since you didn't share the code for exit_app().
But without modifying the code otherwise, I see that the combo_win dropdown is populated with the values given.
If the issue you're having is that combo_win is empty by default (which it is, using the code given), you'll need to set the initial selection with:
self.combo_win.current(0) # set the combo box to 'hide' by default
I'm trying to open a Toplevel window with tkinter, from a system tray menu.
from cmath import phase
from tkinter import *
from tkinter import messagebox, messagebox
from tracemalloc import start
from pystray import MenuItem as item
import pystray
from PIL import ImageTk,Image
import pickle
def quit_window(icon, item):
icon.stop()
root.destroy()
exit()
def hidden():
global my_img1
top=Toplevel()
top.title("Secret menu, shhh :^)")
top.overrideredirect(True)
top.attributes('-alpha', 0.9)
w = 1100
h = 450
ws = top.winfo_screenwidth()
hs = top.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/3) - (h/2)
top.geometry('%dx%d+%d+%d' % (w, h, x, y))
top.iconbitmap('screen.ico')
my_img1 = ImageTk.PhotoImage(Image.open("ITEXTRA.png"))
label1=Label(top,image=my_img1).place(relx=0.01,rely=0.01)
button2=Button(top,text="Close window",bg='#ff4a65',command=top.destroy, relief=GROOVE).place(relx=0.9,rely=0.9)
# Marks window as used
hiddenwindow=1
pickle.dump(hiddenwindow, open("window.dat", "wb"))
Button(root, text="Developer Options", padx=57, bg="#86b3b3",fg="black", command = hidden).grid(row=3,column=0)
def hide_window():
root.withdraw()
image=Image.open("screen.ico")
menu=(item('Dev window', hidden),item('show window', show_window),item('Exit app', quit_window))
icon=pystray.Icon("ITExtra", image, "Program", menu)
icon.run()
def show_window(icon, item):
icon.stop()
root.after(0,root.deiconify())
root.after(0,root.focus_force)
root = Tk()
root.title("ITextra")
root.geometry("400x400")
root.protocol('WM_DELETE_WINDOW', hide_window)
hidden()
root.mainloop()
But this unfortunately will not work, it won't pull up the toplevel window, nor the main one.
If I then open the root window myself, the toplevel window will open, but be unresponsive.
EDIT
Alright, so I tried adding the topwindow as class, but I keep getting error 'Top' object has no attribute 'tk'.
I pasted the updated code below. Any help is always greatly appreciated!
from cmath import phase
from tkinter import *
from tkinter import messagebox, messagebox
from tracemalloc import start
from pystray import MenuItem as item
import pystray
from PIL import ImageTk,Image
import pickle
class Top():
def __init__(self,master=None):
self.hide = True
def hidden(self):
if self.hide:
global my_img1
self.top=Toplevel(root)
self.top.title("Secret menu, shhh :^)")
self.top.attributes('-alpha', 0.9)
w = 1100
h = 450
ws = self.top.winfo_screenwidth()
hs = self.top.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/3) - (h/2)
self.top.geometry('%dx%d+%d+%d' % (w, h, x, y))
self.top.iconbitmap('screen.ico')
my_img1 = ImageTk.PhotoImage(Image.open("ITEXTRA.png"))
label1=Label(self.top,image=my_img1).place(relx=0.01,rely=0.01)
button2=Button(self.top,text="Close window",bg='#ff4a65',command=self.top.destroy, relief=GROOVE).place(relx=0.9,rely=0.9)
# Marks window as used
hiddenwindow=1
pickle.dump(hiddenwindow, open("window.dat", "wb"))
self.top.mainloop()
def somewhereelse():
top.hide = True
top.hidden()
def quit_window(icon, item):
icon.stop()
root.destroy()
exit()
def show_window(icon, item):
icon.stop()
root.after(0,root.deiconify())
root.after(0,root.focus_force)
def hide_window():
root.withdraw()
image=Image.open("screen.ico")
try:
if pickle.load(open("window.dat","rb")) ==1:
menu=(item('Dev window', top.hidden),
item('show window', show_window),
item('Exit app', quit_window))
else:
menu=(item('Exit app', quit_window))
except:
menu=(item('Exit app', quit_window))
icon=pystray.Icon("ITextra", image, "Program", menu)
icon.run()
root = Tk()
root.title("ITextra")
root.geometry("400x400")
top = Top(root) #in main part
root.protocol('WM_DELETE_WINDOW', hide_window)
Button(root, text="Developer Options", padx=57, bg="#86b3b3",fg="black", command =top.hidden).grid(row=3,column=0)
root.mainloop()
Top window still unresponsive
It's not when root is open, but when top is open by itself, again it remains unresponsive. It responds however when I click a button, and drag my mouse. I tried adding a mainloop in top, but neither a self.top.mainloop nor a root.mainloop will work.
I tried using binds, but they also showed the same behaviour.
Am I creating something that won't work?
The app I'm creating is multithreaded, and my question is; would this complicate things with other classes? I am very new to coding, and quite frankly don't know.
I have the whole project in a pastebin here, for anyone who's interested. I think it's quite a mess, but I'm still pretty proud of it for a beginner.
The Toplevel() remains unresponsive because it has no event loop attached (mainloop()) because in this code the Toplevel acts as a standalone main window.
Need to attach this Toplevel to the root - top = Toplevel(root) where root is passed as argument to hidden(root). This way the root event loop works for all widget children such as a Toplevel. This would help towards your main part of the question.
(#added...) so there is no need for top.mainloop() because now that the root is the master/parent top is inside root.mainloop().
The event loop is for checking in to any events that happen on your widget which you would normally program with bind(). eg
top.bind('<Button>',dosomething) where dosomething is a defined function.
(...#added)
If you want a title for top then you need to create your own title baror label if you are using overrideredirect(True) because this removes the platform window manager.
(#added...)
The platform window manager is not so much removed as it is not being used when using overrideredirect(True). This is probably another reason why your window seems unresponsive with this stage of code. Need to code for events attached to the widget yourself - as you have done with the Button widget to close.
(...#added)
For main part of question:
there is nothing that refers to top widget in show_window in this code.
(#added...)
could look at making top a class and instantiate that in the root. The default status of hidden for top could be an attribute of this class. Then you can change the class attribute to hide or show functionally inside the body of the code somewhereelse.
eg skeleton sketch:
class Top():
def __init__(self,master=None):
...
self.hide = True
...
def hidden(self):
if self.hide:
...
def somewhereelse():
top.hide = true
top.hidden()
top = Top(root) #in main part
!!! obviously very brief general idea that needs work here of a way to maintain your design which seems quite good to me. There are several ways to incorporate the Toplevel widget into the class but that digresses a bit from the original question.
(...#added)
added 28Jan...
I recommend to study class more thoroughly rather than only putting in my example. But here is a bit more
class Top():
def __init__(self,master=None):
super().__init__()
self.master = master
self.hide = True
def hidden(self):
...
self.top = Toplevel(self.master)
...
In my words, but please check Python docs, super().__init__() will call the initialising function of the inherited object which in this case goes back to self.master which is root and then back through to tk.__init__ which is called in Tk().
I recommend looking at the code __init__.py file in the Lib\tkinter\ folder in the Python download to get a good understanding of how tkinter works.
I think this is definitely achievable but might need a different GUI - agree it is an excellent start for a beginner and thus not really a mess!!
Using class is not essential to achieving what you want to do but classes are very useful for encapsulating an object so that any extra attributes and methods relevant to that object can be customised for your project. This makes further or future development easier.
...added 28Jan
when I opened my Top Level window, I always saw an annoying and weird behaviour.. at the end I realized that it was because of my custom icon.
below an exaple code:
from tkinter import *
from tkinter import ttk
class MainWindow:
def __init__(self):
self.parent=Tk()
self.parent.geometry("494x410+370+100")
self.parent.title("My Software - WITH ICON")
self.parent.iconbitmap("icon.ico")
Button = ttk.Button(self.parent, text="open a new widnow", command=self.OpenNewWindow)
Button.place(x=16, y=16)
def OpenNewWindow(self):
self.obj = NewWindow(self)
class NewWindow:
def __init__(self, mw):
self.window, self.mw = Toplevel(mw.parent), mw
self.window.geometry("200x150+360+200")
self.window.title("New Window")
self.window.iconbitmap("icon.ico") # it creates the issue..
self.window.protocol("WM_DELETE_WINDOW", self.on_close)
self.window.focus()
self.mw.parent.attributes('-disabled', 1)
self.window.transient(mw.parent)
self.window.grab_set()
self.mw.parent.wait_window(self.window)
def on_close(self):
self.mw.parent.attributes('-disabled', 0)
self.window.destroy()
def main():
app=MainWindow()
app.parent.mainloop()
if __name__=="__main__":
main()
to make it clear where is the issue, I create a GIF:
here we have two softwares, "without icon.py" and "with icon.py". they are the same, but the first one doesn't use my custom icon for his second window.
as you can see, if I run "with icon.py" the second window will be always affected by something when I will open it, but for "without icon.py" this "something" doesn't exist.
what is the issue? the software opens his second window, focus the root one (it's the issue), and then focus the second window again. you can see it clearly from the GIF.
how can I solve the issue? and why with the default icon this weird behaviour doesn't happen?
I am trying to get a Tkinter popup to display when a button is clicked.My issue is that every thing runs just fine except the popup will not produce. I have tried multiple ways to create the popup using tkMessagebox and Toplevel() but still not luck. The program runs but when the button is click nothing happens. I have referenced similar post but still can not find the issue in my code. Any thoughts?
from tkinter import *
def new():
root2 = Tk()
root2.geometry('250x250')
l = Label(root2,text="Please Scan Tag").pack()
root2.mainloop()
# setting main frame
root = Tk()
root.geometry('800x650')
root.title("Pass")
root.configure(background= "white")
label_0 = Label(root, text="Pass",width=10,font=("bold", 50),fg= "green",bg="white")
label_0.place(x=186,y=76)
Button(root,command="new", text='new',font=
("bold",15),width=15,height=4,bg='blue',fg='white').place(x=155,y=300)
root.mainloop()
The command option requires a reference to a callable function, not a string.
Button(root,command=new, ...)
I'm using Python's TkInter module for a GUI. Below is a simple checkbox code.
def getCheckVal():
print cbVar.get()
windowTime=Tk.Tk()
cbVar = Tk.IntVar()
btnC = Tk.Checkbutton(windowTime, text="Save", variable = cbVar, command=getCheckVal)
btnC.grid()
windowTime.mainloop()
This code works fine. Each time I tick the checkbox, I get 1, else 0.
However, when I run the same code in a function that is called from another TkInter command (when a button is pressed), it stops working. I always get 0 as the value.
class GUIMainClass:
def __init__(self):
'''Create the main window'''
self.window = Tk.Tk()
def askUser(self):
def getCheckVal():
print cbVar.get()
windowTime=Tk.Tk()
cbVar = Tk.IntVar()
btnC = Tk.Checkbutton(windowTime, text="Save", variable = cbVar,
command=getCheckVal)
btnC.grid()
windowTime.mainloop()
def cmdWindow(self):
frameShow=Tk.Frame(self.window)
frameShow.grid()
btnSwitch = Tk.Button(frameShow, text='Show Plots', command=self.askUser)
btnSwitch.grid()
self.window.mainloop()
GUIObj=GUIMainClass()
GUIObj.cmdWindow()
This is very unusual. What could be going wrong?
EDIT: I've used 2 mainloops because I want a separate window (windowTime) to open up when I click "Show Plots" button. This new window should have the checkbox in it.
Your windowTime, cbVar, etc. variables are defined in the function's local scope. When askUser() completes execution, those values are thrown away. Prepend self. to them to save them as instance variables.
There should only be one mainloop() in your program, to run the main Tkinter root object. Try putting it as the very last line in the program. I recommend doing some reading on Effbot for how to set up a Tkinter application.
I'm not sure what all you're trying to do, but one problem is that the TK.IntVar called cbVar that you create in your askUser() method will be deleted when the function returns, so you need to attach it to something that will still exist after that happens. While you could make it a global variable, a better choice would be to make it an attribute of something more persistent and has a longer "lifespan".
Another likely issue is that generally there should only be one call to mainloop() in a single Tkinter application. It appears what you want to do is display what is commonly known as a Dialog Window, which Tkinter also supports. There's some standard ones built-in, plus some more generic classes to simplify creating custom ones. Here's some documentation I found which describes them in some detail. You may also find it helpful to look at their source code.
In Python 2 it's in the /Lib/lib-tk/tkSimpleDialog.py file and
in Python 3 the code's in a file named /Lib/tkinter/simpledialog.py.
Below is code that takes the latter approach and derives a custom dialog class named GUIButtonDialog from the generic one included the Tkinter library which is simply named Dialog.
try:
import Tkinter as Tk # Python 2
from tkSimpleDialog import Dialog
except ModuleNotFoundError:
import tkinter as Tk # Python 3
from tkinter.simpledialog import Dialog
class GUIButtonDialog(Dialog):
"""Custom one Button dialog box."""
def __init__(self, btnText, parent=None, title=None):
self.btnText = btnText
Dialog.__init__(self, parent, title)
def getCheckVal(self):
print(self.cbVar.get())
def body(self, master):
"""Create dialog body."""
self.cbVar = Tk.IntVar()
self.btnC = Tk.Checkbutton(master, text=self.btnText, variable=self.cbVar,
command=self.getCheckVal)
self.btnC.grid()
return self.btnC # Return the widget to get inital focus.
def buttonbox(self):
# Overridden to suppress default "OK" and "Cancel" buttons.
pass
class GUIMainClass:
def __init__(self):
"""Create the main window."""
self.window = Tk.Tk()
def askUser(self):
"""Display custom dialog window (until user closes it)."""
GUIButtonDialog("Save", parent=self.window)
def cmdWindow(self):
frameShow = Tk.Frame(self.window)
frameShow.grid()
btnSwitch = Tk.Button(frameShow, text='Show Plots', command=self.askUser)
btnSwitch.grid()
self.window.mainloop()
GUIObj = GUIMainClass()
GUIObj.cmdWindow()