How to update a Tix.ComboBox's text? - python

I have a Tix.ComboBox with an editable text field. How do I force the variable holding the value for the text to update?
Let me give a more concrete explanation. I have a combo box and a button. When I click the button, it pops up a message box with the value of the combo box. Let's say the combo box text field currently has the value "thing1". If I type "new" into the box and then click on the button with my mouse, it will pops up the message "thing1". If I type "new" in the box and then tab focus away from the combo box and then click the button the pop up message says "new".
Ho do I force the combo box to update it's value to new without requiring that I tab away from the combo box?
I have included sample code.
import Tix
import tkMessageBox
class App(object):
def __init__(self, window):
window.winfo_toplevel().wm_title("test")
self.window = window
self.combo = Tix.ComboBox(window)
self.combo.insert(Tix.END, 'thing1')
self.combo.insert(Tix.END, 'thing2')
self.combo.entry['state'] = "normal"
self.combo['editable'] = True
self.combo.pack()
button = Tix.Button(window)
button['text'] = "Go"
button['command'] = self.go
button.pack()
def go(self):
tkMessageBox.showinfo('info', self.combo['value'])
if __name__ == '__main__':
root = Tix.Tk()
App(root)
root.mainloop()

woo!
solved it on my own.
Use
self.combo['selection']
instead of
self.combo['value']

NOTE: copy of Moe's answer that can be selected as chosen answer
woo!
solved it on my own.
Use
self.combo['selection']
instead of
self.combo['value']

Related

Tkinter window title as a variable

I want to be able to dynamically change the window title based on the data being displayed in the window. I display a window with a selected weather alert. In the window title, I want to put the alert event name. Each selected alert will have its own event name.
I created a small test to show using a variable in the title works.
from tkinter import *
root = Tk()
mytitle='MYTITLE'
root.title(mytitle)
root.mainloop()
However when I apply what I think is the same setup in my popup window I get title "PY_VAR0".
def msgwindow(x):
print('in message window')
alert_info = Toplevel(root) # Child window
alert_info.geometry("600x700") # Size of the window
alert_row = alert_tree.item(alert_tree.focus()) # selected value to display
alert_row_title = tk.StringVar()
alert_row_title.set(alert_row['values'][1])
print('value1:', alert_row['values'][1], 'title:', alert_row_title)
alert_info.title(alert_row_title)
alert_row_value = tk.StringVar()
alert_row_value.set(alert_row['values'][4])
alert_label = tk.Label(alert_info, textvariable=alert_row_value, justify=LEFT)
alert_label.grid(row=1, column=0, sticky=N+W)
I added a 'print' which shows my title variable has the intended value but the same variable used in title shows PY_VAR0
value1: High Surf Advisory title: PY_VAR0
The the data in alert_row_value displays as intended. This must be simple...what am I doing wrong?
alert_info.title() requires a str, not a StringVar. So, you need to use alert_row_title.get() to get a str that you can pass in. So, your code just needs to be:
alert_info.title(alert_row_title.get())

What does the 'tearoff' attribute do in a tkinter Menu?

I often see Tkinter applications initialize Menu widgets using tearoff=0 in the constructor.
import tkinter as tk
root = tk.Tk()
menubar = tk.Menu(root)
filemenu = tk.Menu(menubar, tearoff=0)
effbot.org's documentation for Menu specifies that the default value for tearoff is 1, but it doesn't explain what the value is used for.
tearoff=
Default value is 1. (tearOff/TearOff)
tearoffcommand=
No default value. (tearOffCommand/TearOffCommand)
What does the tearoff attribute do when initializing a tkinter Menu widget?
The official python docs admit that they're a little light on details:
The tkinter package is a thin object-oriented layer on top of Tcl/Tk. To use tkinter, you don’t need to write Tcl code, but you will need to consult the Tk documentation, and occasionally the Tcl documentation.
The Tk documentation for tearoff gives you what you're looking for:
tearoff allows you to detach menus for the main window creating floating menus. If you create a menu you will see dotted lines at the top when you click a top menu item. If you click those dotted lines the menu tears off and becomes floating.
Here you can see a tkinter Menu tear-off with the code for it in the background. I'm not sure how useful this is going to be but according to New Mexico Tech:
Normally, a menu can be torn off: the first position (position 0) in the list of choices is occupied by the tear-off element, and the additional choices are added starting at position 1. If you set tearoff=0, the menu will not have a tear-off feature, and choices will be added starting at position 0.
Try this if you want to test the floating menu if you are using Windows.
from tkinter import *
import re
class HoverInfo(Menu):
def __init__(self, parent, text, command=None):
self._com = command
Menu.__init__(self,parent, tearoff=1)
if not isinstance(text, str):
raise TypeError('Trying to initialise a Hover Menu with a non string type: ' + text.__class__.__name__)
toktext=re.split('\n', text)
for t in toktext:
self.add_command(label = t)
self._displayed=False
self.master.bind("<Enter>",self.Display )
self.master.bind("<Leave>",self.Remove )
def __del__(self):
self.master.unbind("<Enter>")
self.master.unbind("<Leave>")
def Display(self,event):
if not self._displayed:
self._displayed=True
self.post(event.x_root, event.y_root)
if self._com != None:
self.master.unbind_all("<Return>")
self.master.bind_all("<Return>", self.Click)
def Remove(self, event):
if self._displayed:
self._displayed=False
self.unpost()
if self._com != None:
self.unbind_all("<Return>")
def Click(self, event):
self._com()
class MyApp(Frame):
def __init__(self, parent=None):
Frame.__init__(self, parent)
self.grid()
self.lbl = Label(self, text='testing')
self.lbl.grid()
self.hover = HoverInfo(self, 'while hovering press return \n for an exciting msg', self.HelloWorld)
def HelloWorld(self):
print('Hello World')
app = MyApp()
app.master.title('test')
app.mainloop()
This example is Hover Class by Gogo. Display message when hovering over something with mouse cursor in Python
I Just set tear-off to 1 to see the floating effect.
By default, the choices in the menu start taking place from position 1. If we set the tearoff = 1, then it will start taking place from 0th position

Tkinter Browse Button Self Deleting

I am trying to create a browse button in tkinter. I have created the open folder dialog box but when i set it to the button it will exit out of the window.
My ultimate goal is to:
1) click on the button and bring up the file dialogue box
2) select a file
3) insert the file name into an Entry Widget for later use
I should note that I am using multiple window frames for the code that follows is summed up.
import os
import sys
import Tkinter as tk
from tkFileDialog import askopenfilename
def openFile(entryWidgetName):
tk.Tk().withdraw()
filename = askopenfilename()
entryWidgetName.delete(0,tk.END)
entryWidgetName.insert(0,filename)
return
class Welcome():
def __init__(self,master):
self.buttonNewTemplate = tk.Button(self.master, text = 'Create a New Template', command = self.gotoNewTemplate).place(x=100, y=250)
def gotoNewTemplate(self):
root2 = tk.Toplevel(self.master)
newTemplate = NewTemplate(root2)
class NewTemplate():
def __init__(self, master):
#Entry Windows
self.uploadFile = tk.Entry(self.sectionFrame2, width = 80).grid(row=4, column = 1, sticky = 'w')
#Buttons
self.buttonBrowse=tk.Button(self.sectionFrame2, text='Browse', fg='blue', command=lambda:openFile(uploadFile)).grid(row=4, column = 0, padx = 10, sticky = 'w')
Every time I click the browse button the second window destroys itself bringing me back to the main page.
Does anyone have any suggestions?
A tkinter application can only have a single instance of Tk. You are creating at least two: one explicitly in openFile, and one from somewhere else in your code either implicitly or explicitly.
Since the only way to call openFile is from a button click, and the only way to have a button click is to have a button, and the only way to have a button is to already have a root window, you need to remove the statement tk.Tk().withdraw() since that is creating a new root window.
There may be other problems in your code, but it's impossible to know based on the incomplete code in the question.

Tkinter Toplevel : Destroy window when not focused

I have a Toplevel widget that I want to destroy whenever the user clicks out of the window. I tried finding solutions on the Internet, but there seems to be no article discussing about this topic.
How can I achieve this. Thanks for any help !
You can try something like that :
fen is your toplevel
fen.bind("<FocusOut>", fen.quit)
I had a similar problem, and fixed it. The following example works fine.
It displays a Toplevel window on top of the main window, as a customized config menu.
Whenever the user clicks somewhere else, the config menu disappears.
Warning: Don't use .transient(parent) on the Toplevel window, otherwise, the symptom that you described happens: when clicking on the main window, the menu does not disappear. You can try in the example below to uncomment the "self.transient(parent)" line to reproduce your issue.
Example:
import Tix
class MainWindow(Tix.Toplevel):
def __init__(self, parent):
# Init
self.parent = parent
Tix.Toplevel.__init__(self, parent)
self.protocol("WM_DELETE_WINDOW", self.destroy)
w = Tix.Button(self, text="Config menu", command=self.openMenu)
w.pack()
def openMenu(self):
configWindow = ConfigWindow(self)
configWindow.focus_set()
class ConfigWindow(Tix.Toplevel):
def __init__(self, parent):
# Init
self.parent = parent
Tix.Toplevel.__init__(self, parent)
# If you uncomment this line it reproduces the issue you described
#self.transient(parent)
# Hides the window while it is being configured
self.withdraw()
# Position the menu under the mouse
x = self.parent.winfo_pointerx()
y = self.parent.winfo_pointery()
self.geometry("+%d+%d" % (x, y))
# Configure the window without borders
self.update_idletasks() # Mandatory for .overrideredirect() method
self.overrideredirect(True)
# Binding to close the menu if user does something else
self.bind("<FocusOut>", self.close) # User focus on another window
self.bind("<Escape>", self.close) # User press Escape
self.protocol("WM_DELETE_WINDOW", self.close)
# The configuration items
w = Tix.Checkbutton(self, text="Config item")
w.pack()
# Show the window
self.deiconify()
def close(self, event=None):
self.parent.focus_set()
self.destroy()
tixRoot = Tix.Tk()
tixRoot.withdraw()
app = MainWindow(tixRoot)
app.mainloop()
The other solutions didn't work for me when I had 2 <tkinter.Entry>s but I found this:
import tkinter as tk
focus = 0
def focus_in(event):
global focus
focus += 1
def focus_out(event):
global focus
focus -= 1
if focus == 0:
root.destroy()
root = tk.Toplevel()
root.bind("<FocusIn>", focus_in)
root.bind("<FocusOut>", focus_out)
root.mainloop()
It has a counter for the number of times the window is focused. It destroys the window when the counter reaches 0.

How to disable text shaking when I click a button?

I am working with buttons in Tkinter, Python.
The thing is when I click in one button the text of the button shakes. It might be a default behavior for this widget and I don't know how to disable it and make it static.
I assume that you mean the relief change from raised to sunken when you click a button.
This is what I found on http://wiki.tcl.tk/1048 (click 'Show Discussion' to see it):
Unfortunately, the relief used when you click is hardcoded (as
'sunken'), so you can't configure it per-widget without hacking the Tk
internals for the binding for buttons.
So the simplest way around this would be to always make the button appear sunken
MyButton = Tkinter.Button(
self.frame,
text = "Foobar",
command = self.foobar,
relief=Tkinter.SUNKEN
)
The disadvantage of that is that it might make the button look unresponsive.
You can also use a widget other than a button to be used as a clickable item (suggested by Joel Cornett). Here is a simple example with a label used as a button:
import Tkinter
class main:
def __init__(self,root):
# make a label with some space around the text
self.lbl1 = Tkinter.Label(root,
width = 16, height = 4,
text = "Foobar")
self.lbl1.pack()
# Call a function when lbl1 is clicked
# <Button-1> means a left mouse button click
self.lbl1.bind("<Button-1>", self.yadda)
self.lbl1.bind("<Enter>", self.green)
self.lbl1.bind("<Leave>", self.red)
def yadda(self, event):
self.lbl1.config(text="Clicked!")
def green(self, event):
self.lbl1.config(bg="green")
def red(self,event):
self.lbl1.config(bg="red")
if __name__ == "__main__":
root = Tkinter.Tk()
main(root)
root.mainloop()

Categories