I have placed multiple Combobox in the grid as shown below.
These comboboxes are stored in array with corresponding row, column for eg as shown below.
self.c_arr[row,column] = ttk.Combobox(what_ev,
textvariable=self.c_it_val[row,column],
values=list(self.c_list[row,column].keys()))
self.c_arr[row,column].bind("<<ComboboxSelected>>", lambda
x:self.c_capture(what_ev, <Want to pass row, column information as well>))
Whenever the function bound to the combobox is called/triggered, I wanted to pass the respective row, column number to the called function along with other variables.
How to get/retrieve the respective widgets row,column number/location details placed on the grid?
UPDATE: Adding with an Example code below.
The below code create a 3x3 COmbobox and binded with a function to get called when any of the respective combobox is selected. When gets selected I wanted to get the value selected in that box and print it.
Example Code:
import Tkinter
from Tkinter import *
from Tkinter import Tk, StringVar
import ttk
import tkFont
class Application:
def __init__(self, parent):
self.parent = parent
self.sco1 = None
self.c_int_val = StringVar()
self.box = {}
self.box_value = {}
self.box_int_list = {}
self.combo()
def combo(self):
for row in range (3):
for column in range(3):
self.box_int_list[row,column] = {key: None for key in range(1,10)}
self.box_value[row,column] = StringVar()
self.box_value[row,column].set("0")
self.box[row,column] = ttk.Combobox(self.parent, textvariable=self.box_value[row,column], values = list(self.box_int_list[row,column].keys()), state='readonly', width=39)
self.box[row,column].bind("<<ComboboxSelected>>", lambda x:self.print_selected_value("Eurekaa", len(self.box_int_list[row,column])))
self.box[row,column].grid(row=row, column=column)
def print_selected_value(self, what_name, list_len, *args):
print "Value selected is: %s"%(self.box[row,column].get())
print what_name
print list_len
if __name__ == '__main__':
root = Tk()
app = Application(root)
root.mainloop()
But since I wasnt able to get the row,column info, was unable to get the value from the selected combobox. How can that be done ?
If you pass the event to your callback, you can use grid_info on the widget associated with the event.
def callback(event, row, column):
print(row, column)
cb.bind("<<ComboboxSelected>>", callback)
If you want to pass the information, there's nothing preventing you from doing that using lambda or functools.partial:
c.bind("<<ComboboxSelected>>",
lambda event, row=row, column=column: callback(event, row, column))
What im trying to do is that whenever cursor is on label it must show the time elapsed since when it is created it does well by subtracting (def on_enter(i)) the value but i want it to be ticking while cursor is still on label.
I tried using after function as newbie i do not understand it well to use on dynamic labels.
any help will be appreciated thx
code:
from Tkinter import *
import datetime
date = datetime.datetime
now = date.now()
master=Tk()
list_label=[]
k=[]
time_var=[]
result=[]
names=[]
def delete(i):
k[i]=max(k)+1
time_var[i]='<deleted>'
list_label[i].pack_forget()
def create():#new func
i=k.index(max(k))
for j in range(i+1,len(k)):
if k[j]==0:
list_label[j].pack_forget()
list_label[i].pack(anchor='w')
time_var[i]=time_now()
for j in range(i+1,len(k)):
if k[j]==0:
list_label[j].pack(anchor='w')
k[i]=0
###########################
def on_enter(i):
list_label[i].configure(text=time_now()-time_var[i])
def on_leave(i):
list_label[i].configure(text=names[i])
def time_now():
now = date.now()
return date(now.year,now.month,now.day,now.hour,now.minute,now.second)
############################
for i in range(11):
lb=Label(text=str(i),anchor=W)
list_label.append(lb)
lb.pack(anchor='w')
lb.bind("<Button-3>",lambda event,i=i:delete(i))
k.append(0)
names.append(str(i))
lb.bind("<Enter>",lambda event,i=i: on_enter(i))
lb.bind("<Leave>",lambda event,i=i: on_leave(i))
time_var.append(time_now())
master.bind("<Control-Key-z>",lambda event: create())
mainloop()
You would use after like this:
###########################
def on_enter(i):
list_label[i].configure(text=time_now()-time_var[i])
list_label[i].timer = list_label[i].after(1000, on_enter, i)
def on_leave(i):
list_label[i].configure(text=names[i])
list_label[i].after_cancel(list_label[i].timer)
However, your approach here is all wrong. You currently have some functions and a list of data. What you should do is make a single object that contains the functions and data together and make a list of those. That way you can write your code for a single Label and just duplicate that. It makes your code a lot simpler partly because you no longer need to keep track of "i". Like this:
import Tkinter as tk
from datetime import datetime
def time_now():
now = datetime.now()
return datetime(now.year,now.month,now.day,now.hour,now.minute,now.second)
class Kiran(tk.Label):
"""A new type of Label that shows the time since creation when the mouse hovers"""
hidden = []
def __init__(self, master=None, **kwargs):
tk.Label.__init__(self, master, **kwargs)
self.name = self['text']
self.time_var = time_now()
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)
self.bind("<Button-3>", self.hide)
def on_enter(self, event=None):
self.configure(text=time_now()-self.time_var)
self.timer = self.after(1000, self.on_enter)
def on_leave(self, event=None):
self.after_cancel(self.timer) # cancel the timer
self.configure(text=self.name)
def hide(self, event=None):
self.pack_forget()
self.hidden.append(self) # add this instance to the list of hidden instances
def show(self):
self.time_var = time_now() # reset time
self.pack(anchor='w')
def undo(event=None):
'''if there's any hidden Labels, show one'''
if Kiran.hidden:
Kiran.hidden.pop().show()
def main():
root = tk.Tk()
root.geometry('200x200')
for i in range(11):
lb=Kiran(text=i)
lb.pack(anchor='w')
root.bind("<Control-Key-z>",undo)
root.mainloop()
if __name__ == '__main__':
main()
More notes:
Don't use lambda unless you are forced to; it's known to cause bugs.
Don't use wildcard imports (from module import *), they cause bugs and are against PEP8.
Put everything in functions.
Use long, descriptive names. Single letter names just waste time. Think of names as tiny comments.
Add a lot more comments to your code so that other people don't have to guess what the code is supposed to do.
Try a more beginner oriented forum for questions like this, like learnpython.reddit.com
I translated TreeView gtk2 tooltip in Gtk3
It's almost running but I have problem to manage coordinate of tooltip window.
I Would like the tooltip window locate near the mouse et follow it near. Instead of my project where the tooltip window is located in the corner of screen
my code is
#!/usr/bin/env python
# coding: utf-8
'''
warning data not update !!!!!!!!!!!!!
TreeViewTooltips.py
Provides TreeViewTooltips, a class which presents tooltips for cells,
columns and rows in a Gtk.TreeView.
------------------------------------------------------------
This file includes a demo. Just execute the file:
python TreeViewTooltips.py
------------------------------------------------------------
To use, first subclass TreeViewTooltips and implement the get_tooltip()
method; see below. Then add any number of Gtk.TreeVew widgets to a
TreeViewTooltips instance by calling the add_view() method. Overview
of the steps:
# 1. subclass TreeViewTooltips
class MyTooltips(TreeViewTooltips):
# 2. overriding get_tooltip()
def get_tooltip(...):
...
# 3. create an instance
mytips = MyTooltips()
# 4. Build up your Gtk.TreeView.
myview = Gtk.TreeView()
...# create columns, set the model, etc.
# 5. Add the view to the tooltips
mytips.add_view(myview)
How it works: the add_view() method connects the TreeView to the
"motion-notify" event with the callback set to a private method.
Whenever the mouse moves across the TreeView the callback will call
get_tooltip() with the following arguments:
get_tooltip(view, column, path)
where,
view: the Gtk.TreeView instance.
column: the Gtk.TreeViewColumn instance that the mouse is
currently over.
path: the path to the row that the mouse is currently over.
Based on whether or not column and path are checked for specific
values, get_tooltip can return tooltips for a cell, column, row or the
whole view:
Column Checked Path Checked Tooltip For...
Y Y cell
Y N column
N Y row
N N view
get_tooltip() should return None if no tooltip should be displayed.
Otherwise the return value will be coerced to a string (with the str()
builtin) and stripped; if non-empty, the result will be displayed as
the tooltip. By default, the tooltip popup window will be displayed
centered and just below the pointer and will remain shown until the
pointer leaves the cell (or column, or row, or view, depending on how
get_tooltip() is implemented).
'''
from gi.repository import Gtk
class TreeViewTooltips_gtk3:
"""tooltip atttach to Treeview in Gtk3
this window is moving to follow row of Treeview"""
def __init__(self):
self.win = Gtk.Window()
self.win.set_decorated(False)
self.win.set_default_size(-1, -1)
self.label = Gtk.Label()
self.win.add(self.label)
# by default, the tooltip is enabled
self.__enabled = True
def __show(self, tooltip, x, y):
"""in order to move the tooltip near row of Treeview"""
self.label.set_markup(tooltip)
w,h = self.win.get_preferred_width()
# move the window
self.win.move(*self.location(x,y,w,h))
# show it
self.win.show_all()
return self.win
def __leave_handler(self, view, event):
"""when the pointer leaves the view, hide the tooltip"""
self.win.hide()
def enable(self):
'Enable the tooltip'
self.__enabled = True
def disable(self):
'Disable the tooltip'
self.__enabled = False
def location(self, x, y, w, h):
'''Given the x,y coordinates of the pointer and the width and
height (w,h) demensions of the tooltip window, return the x, y
coordinates of the tooltip window.
The default location is to center the window on the pointer
and 4 pixels below it.
# en clair c'est un décalage de position de la fenetre qui s'ouvre qui donne l'info
'''
return x - w/2, y + 4
def tooltip_callback(self,treeview, x, y, keyboard_mode, tooltip):
""" in order to collect miscellaneous elemnt to build data with row of treeview"""
"""3eme règle implementer ça pour afficher un tooltip customisé en fonction des data du tree view"""
x, y = treeview.convert_widget_to_bin_window_coords(x, y)
if not self.__enabled :
"""if you don't want tooltip display just return False !!!!"""
return False
try:
path, column, cell_x, cell_y = treeview.get_path_at_pos(x, y)
iter = model.get_iter(path)
#print 'tooltip=',self.get_tooltip(column, self.cust_col,path)
treeview.set_tooltip_window(self.__show(self.get_tooltip(column, self.cust_col,path),x,y))
# necessary to return True in order to display window tooltip
print "path is valid :-)"
return True
except:
# to prevent case when path it's not valid
print "perhaps path it's not valid ????"
# not possible to display something
return False
def add_view(self, view):
"""add a Gtk.TreeView to the tooltip
check if view is instance of Gtk.TreeView
and build connector and tooltip enable"""
assert isinstance(view, Gtk.TreeView), \
('This handler should only be connected to '
'instances of Gtk.TreeView')
# first condition in gtk3
# set True the property "has-tooltip"
view.set_property("has-tooltip", True)
# second condition in gtk3
view.connect('query-tooltip',self.tooltip_callback)
# hide tooltip when mouse out of widget
view.connect("leave-notify-event", self.__leave_handler)
def get_tooltip(self, view, column, path):
"""in order to secure customized implementation in your projet"""
'See the module doc string for a description of this method'
raise NotImplemented, 'Subclass must implement get_tooltip()'
if __name__ == '__main__':
class DemoTips_Gtk3(TreeViewTooltips_gtk3):
"""demo play how to """
def __init__(self, customer_column):
"""
init class
customer_column is an instance of Gtk.TreeViewColumn and
is being used in the Gtk.TreeView to show customer names."""
self.cust_col = customer_column
# call base class init
TreeViewTooltips_gtk3.__init__(self)
def get_tooltip(self, column,cust_col,path):
"""By checking both column and path we have a cell-based tooltip"""
model = view.get_model()
customer = model[path][2]
if column is cust_col:
"""here there is lot of information on row"""
return '<big>%s %s</big>\n<i>%s</i>' % (customer.fname,
customer.lname,
customer.notes)
else:
"""here basic data only !!!!"""
return ('<big><u>Generic Column Tooltip</u></big>\n'
'Unless otherwise noted, all\n phone number is %s ') % customer.phone
# Here's our customer
class Customer:
def __init__(self, fname, lname, phone, notes):
self.fname = fname
self.lname = lname
self.phone = phone
self.notes = notes
# create a bunch of customers
customers = []
for fname, lname, phone, notes in [
('Joe', 'Schmoe', '555-1212', 'Likes to Morris dance.'),
('Jane', 'Doe', '555-2323',
'Wonders what the hell\nMorris dancing is.'),
('Phred', 'Phantastic', '900-555-1212', 'Dreams of Betty.'),
('Betty', 'Boop', '555-3434', 'Dreams in b&w.'),
('Red Sox', 'Fan', '555-4545',
"Still livin' 2004!\nEspecially after 2006.")]:
customers.append(Customer(fname, lname, phone, notes))
# Build our model and view
model = Gtk.ListStore(str, str, object)
for c in customers:
model.append(['%s %s' % (c.fname, c.lname), c.phone, c])
view = Gtk.TreeView(model)
# two columns, name and phone
cell = Gtk.CellRendererText()
cell.set_property('xpad', 20)
namecol = Gtk.TreeViewColumn('Customer Name', cell, text=0)
namecol.set_min_width(200)
view.append_column(namecol)
cell = Gtk.CellRendererText()
phonecol = Gtk.TreeViewColumn('Phone', cell, text=1)
view.append_column(phonecol)
# finally, connect the tooltip, specifying the name column as the
# column we want the tooltip to popup over.
tips = DemoTips_Gtk3(namecol)
tips.add_view(view)
# We're going to demonstrate enable/disable. First we need a
# callback function to connect to the toggled signal.
def toggle(button):
if button.get_active():
tips.disable()
else:
tips.enable()
# create a checkbutton and connect our handler
check = Gtk.CheckButton('Check to disable view tooltips')
check.connect('toggled', toggle)
check.set_tooltip_markup('This is a standard Gtk tooltip.\n'
'Compare me to the tooltips above.')
# create a VBox to pack the view and checkbutton
vbox = Gtk.VBox()
vbox.pack_start(view,False,False,2)
vbox.pack_start(check,False,False,2)
vbox.show_all()
# pack the vbox into a simple dialog and run it
dialog = Gtk.Dialog('TreeViewTooltips Demo')
close = dialog.add_button(Gtk.STOCK_CLOSE,Gtk.ResponseType.NONE)
# add a tooltip for the close button
close.set_tooltip_markup('Click to end the demo.')
dialog.set_default_size(400,400)
dialog.vbox.pack_start(vbox,False,False,2)
dialog.run()
Who could give me elemnt in order to put tooltip with relative coordinate with TreeView ?
thank by advance
I'am sorry for my bad english
You are working with local coordinates, so you need to refer to the dialog position to get the root coordinates. Another issue with your script is that the main window is a dialog, therefore in the foreground, the tooltips appear below it (I have fixed that but then deleted the code (oops). It works, just change your dialog for a normal window). As a general note, it is good for all widget to know its parent to refer to it when the root coordinates are required.
Please see modified (but not cleaned up) code below:
#!/usr/bin/env python
# coding: utf-8
from gi.repository import Gtk
class TreeViewTooltips_gtk3:
"""tooltip atttach to Treeview in Gtk3
this window is moving to follow row of Treeview"""
def __init__(self):
self.win = Gtk.Window()
self.win.set_decorated(False)
self.win.set_default_size(-1, -1)
self.label = Gtk.Label()
self.win.add(self.label)
# by default, the tooltip is enabled
self.__enabled = True
def __show(self, tooltip, x, y):
"""in order to move the tooltip near row of Treeview"""
self.label.set_markup(tooltip)
w,h = self.win.get_preferred_width()
# move the window
self.win.move(*self.location(x,y,w,h))
# show it
self.win.show_all()
return self.win
def __leave_handler(self, view, event):
"""when the pointer leaves the view, hide the tooltip"""
self.win.hide()
def enable(self):
'Enable the tooltip'
self.__enabled = True
def disable(self):
'Disable the tooltip'
self.__enabled = False
def location(self, x, y, w, h):
'''Given the x,y coordinates of the pointer and the width and
height (w,h) demensions of the tooltip window, return the x, y
coordinates of the tooltip window.
The default location is to center the window on the pointer
and 4 pixels below it.
# en clair c'est un décalage de position de la fenetre qui s'ouvre qui donne l'info
'''
return x - w/2, y + 4
def tooltip_callback(self,treeview, x, y, keyboard_mode, tooltip):
""" in order to collect miscellaneous elemnt to build data with row of treeview"""
"""3eme règle implementer ça pour afficher un tooltip customisé en fonction des data du tree view"""
root_x, root_y = self.dialog.get_position() #get the root coordinates
x, y = treeview.convert_widget_to_bin_window_coords(x, y)
if not self.__enabled :
"""if you don't want tooltip display just return False !!!!"""
return False
try:
path, column, cell_x, cell_y = treeview.get_path_at_pos(x, y)
iter = model.get_iter(path)
#print 'tooltip=',self.get_tooltip(column, self.cust_col,path)
#add the root coordinates to local coordinates
treeview.set_tooltip_window(self.__show(self.get_tooltip(column, self.cust_col,path),root_x+x,root_y+y))
# necessary to return True in order to display window tooltip
print("path is valid :-)")
return True
except:
# to prevent case when path it's not valid
print("perhaps path it's not valid ????")
# not possible to display something
return False
def add_view(self, view):
"""add a Gtk.TreeView to the tooltip
check if view is instance of Gtk.TreeView
and build connector and tooltip enable"""
assert isinstance(view, Gtk.TreeView), \
('This handler should only be connected to '
'instances of Gtk.TreeView')
# first condition in gtk3
# set True the property "has-tooltip"
view.set_property("has-tooltip", True)
# second condition in gtk3
view.connect('query-tooltip',self.tooltip_callback)
# hide tooltip when mouse out of widget
view.connect("leave-notify-event", self.__leave_handler)
def get_tooltip(self, view, column, path):
"""in order to secure customized implementation in your projet"""
'See the module doc string for a description of this method'
raise NotImplemented('Subclass must implement get_tooltip()')
if __name__ == '__main__':
class DemoTips_Gtk3(TreeViewTooltips_gtk3):
"""demo play how to """
def __init__(self, customer_column):
"""
init class
customer_column is an instance of Gtk.TreeViewColumn and
is being used in the Gtk.TreeView to show customer names."""
self.cust_col = customer_column
# call base class init
TreeViewTooltips_gtk3.__init__(self)
def get_tooltip(self, column,cust_col,path):
"""By checking both column and path we have a cell-based tooltip"""
model = view.get_model()
customer = model[path][2]
if column is cust_col:
"""here there is lot of information on row"""
return '<big>%s %s</big>\n<i>%s</i>' % (customer.fname,
customer.lname,
customer.notes)
else:
"""here basic data only !!!!"""
return ('<big><u>Generic Column Tooltip</u></big>\n'
'Unless otherwise noted, all\n phone number is %s ') % customer.phone
# Here's our customer
class Customer:
def __init__(self, fname, lname, phone, notes):
self.fname = fname
self.lname = lname
self.phone = phone
self.notes = notes
# create a bunch of customers
customers = []
for fname, lname, phone, notes in [
('Joe', 'Schmoe', '555-1212', 'Likes to Morris dance.'),
('Jane', 'Doe', '555-2323',
'Wonders what the hell\nMorris dancing is.'),
('Phred', 'Phantastic', '900-555-1212', 'Dreams of Betty.'),
('Betty', 'Boop', '555-3434', 'Dreams in b&w.'),
('Red Sox', 'Fan', '555-4545',
"Still livin' 2004!\nEspecially after 2006.")]:
customers.append(Customer(fname, lname, phone, notes))
# Build our model and view
model = Gtk.ListStore(str, str, object)
for c in customers:
model.append(['%s %s' % (c.fname, c.lname), c.phone, c])
view = Gtk.TreeView(model)
# two columns, name and phone
cell = Gtk.CellRendererText()
cell.set_property('xpad', 20)
namecol = Gtk.TreeViewColumn('Customer Name', cell, text=0)
namecol.set_min_width(200)
view.append_column(namecol)
cell = Gtk.CellRendererText()
phonecol = Gtk.TreeViewColumn('Phone', cell, text=1)
view.append_column(phonecol)
# finally, connect the tooltip, specifying the name column as the
# column we want the tooltip to popup over.
tips = DemoTips_Gtk3(namecol)
tips.add_view(view)
# We're going to demonstrate enable/disable. First we need a
# callback function to connect to the toggled signal.
def toggle(button):
if button.get_active():
tips.disable()
else:
tips.enable()
# create a checkbutton and connect our handler
check = Gtk.CheckButton('Check to disable view tooltips')
check.connect('toggled', toggle)
check.set_tooltip_markup('This is a standard Gtk tooltip.\n'
'Compare me to the tooltips above.')
# create a VBox to pack the view and checkbutton
vbox = Gtk.VBox()
vbox.pack_start(view,False,False,2)
vbox.pack_start(check,False,False,2)
vbox.show_all()
# pack the vbox into a simple dialog and run it
dialog = Gtk.Dialog('TreeViewTooltips Demo')
tips.dialog = dialog #give tips the main window reference
close = dialog.add_button(Gtk.STOCK_CLOSE,Gtk.ResponseType.NONE)
# add a tooltip for the close button
close.set_tooltip_markup('Click to end the demo.')
dialog.set_default_size(400,400)
dialog.vbox.pack_start(vbox,False,False,2)
dialog.run()
AttributeError: MyGUI instance has no attribute 'tk'
Also, how do I make the created window have a fixed size and not be able to resize with the mouse? Or after changing label value by clicking on button.
My code:
from Tkinter import*
class MyGUI(Frame):
def __init__(self):
self.__mainWindow = Tk()
#lbl
self.labelText = 'label message'
self.depositLabel = Label(self.__mainWindow, text = self.labelText)
#buttons
self.hi_there = Button(self.__mainWindow)
self.hi_there["text"] = "Hello",
self.hi_there["command"] = self.testeo
self.QUIT = Button(self.__mainWindow)
self.QUIT["text"] = "QUIT"
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
#place on view
self.depositLabel.pack()
self.hi_there.pack() #placed in order!
self.QUIT.pack()
#What does it do?
mainloop()
def testeo(self):
self.depositLabel['text'] = 'c2value'
print "testeo"
def depositCallBack(self,event):
self.labelText = 'change the value'
print(self.labelText)
self.depositLabel['text'] = 'change the value'
myGUI = MyGUI()
What's wrong?
Thanks
You should invoke the super constructor for Frame. Not sure, but I guess this will set the tk attribute that the quit command relies on. After that, there's no need to create your own Tk() instance.
def __init__(self):
Frame.__init__(self)
# self.__mainWindow = Tk()
Of course, you will also have to change the constructor calls for your widgets accordingly, e.g.,
self.hi_there = Button(self) # self, not self.__mainWindow
or better (or at least shorter): set all the attributes directly in the constructors:
self.hi_there = Button(self, text="Hello", command=self.testeo)
Also add self.pack() to your constructor.
(Alternatively, you could change the quit command to self.__mainWindow.quit, but I think the above is better style for creating Frames, see e.g. here.)
This error typically means you are calling SomeTKSuperClass.__init__ and forgetting the first parameter, which must be self. Remember that __init__ is a class method (static function) in this context, not an instance method, which means that you must explicitly pass it self.