Getting the text of label once button is clicked (Tkinter) - python-2.7

I am new to Python and Tkinter so I am trying to create a sample program to explore.
The program basically shows the names as a Label then 4 buttons will be put right next to the Label.
One of the buttons is "Delete" and what I want to do is, the button will get the name of the Label that is right next to that 'Delete" button.
The code is :
from Tkinter import *
class GUI():
def __init__(self):
self.namelist = ["Mark","Anna","Jason","Lenna",
"Leo","Zucharich","Robinson",
"AReallyLongNameThatMightExist"]
self.canvas = Canvas(width=1200,height=700)
self.canvas.pack(expand=YES,fill=BOTH)
def Friends(self):
frame = Frame(self.canvas)
frame.place(x=600,y=300)
#Frame for showing names of friends
row = 0
for x in self.namelist:
label = Label(frame,text="%s "%x)
chatButton = Button(frame,text="Chat")
delButton = Button(frame,text="Delete")
setcloseButton = Button(frame,text="Set Close")
setgroupButton = Button(frame,text="Set Group")
label.grid(row=row, column=0, sticky="W")
chatButton.grid(row=row, column=1)
delButton.grid(row=row, column=2)
setcloseButton.grid(row=row, column=3)
setgroupButton.grid(row=row, column=4)
row = row + 1
mainloop()
GUI = GUI()
GUI.Friends()
Example: If you run the code, then when you click "Delete" button next to "Mark", then the button will return "Mark".
Thanks!

Tk buttons have a command option to allow you to specify code to be run when the button is clicked. In this case you just want to pass the sibling widget name to your function. You can do this by capturing the widget name at creation time:
label = ...
delButton = Button(frame,text="Delete",
command=self.makeClosure(label))
...
def makeClosure(self, labelWidget):
return lambda: self.onClick(labelWidget)
def onClick(self, labelWidget):
print(labelWidget["text"])
In this example, when we create the delButton widget, the command is defined as a lambda that creates a closure including the label variable as it is defined at the time when this lambda is defined. Now when the delButton is clicked, this value will be passed to the onClick function which can use this to call methods on the widget at runtime.

Related

Treeview removing highlight when using an update loop

I have a Treeview table that calls records from an external MongoDB collection, which changes frequently, so I need to use an update loop to reflect the changes in my table. Whenever I highlight a row with the cursor, it displays the highlighted row with the selected background colour.
The problem is when the loop updates, the highlight disappears. I was wondering if someone could show me a method for keeping the highlight in place, regardless of the table updates?
If you run this code, you'll see what I mean:
from Tkinter import *
import Tkinter
import ttk as TTK
root = Tk()
style = TTK.Style()
tv = TTK.Treeview()
def highlight_row(event):
tree = event.widget
item = tree.identify_row(event.y)
tree.tk.call(tree, "tag", "remove", "highlight")
tree.tk.call(tree, "tag", "add", "highlight", item)
tv.grid(row=1, column=0)
tv.tag_configure('highlight', background='orange')
tv.bind("<Motion>", highlight_row)
style.configure("Treeview", font=(None, 12))
style.configure("Treeview", foreground= '#3F3F3F',
background= '#3F3F3F',
fieldbackground='#3F3F3F')
tv['columns'] = ('a','b','c')
tv.heading('a', text='a')
tv.column('a', anchor='center', width=100)
tv.heading('b', text='b')
tv.column('b', anchor='center', width=175)
tv.heading('c', text='c')
tv.column( 'c', anchor='center', width=90)
external_db = [{'x':1,'y':2, 'z':3},
{'x':4,'y':5, 'z':6},
{'x':7,'y':8, 'z':9}]
def update():
try:
for j in tv.get_children():
tv.delete(j)
for j, k in enumerate(external_db):
tv.insert('', 'end', text=str(j), values=(k['x'],k['y'],k['z']) ,tags = ('col'))
tv.tag_configure('col', foreground = 'white')
except Exception, e:
print e, 'Update Exception'
pass
root.after(1500,update)
update()
root.mainloop()
i.e. there is an orange background highlight that disappears every time root.after(1500,update) is called.
Any suggestions? Thanks.
#_____________________
Here is what root.configure(background="#3F3F3F") does for me:

wxpython how to set a bind event on a button which gets enable upon clicking on other button

which consist a combo box 4 buttons. Once i select an entry from combo box, it will enable a button upon clicking one button it enables the rest. I want to send a command once the buttons is enabled on clicking it.
Below is my code:
import wx
import xlrd
import os,sys,time
folderpath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
print folderpath
site_lib_path = os.path.join(folderpath, "site_lib")
files = os.listdir(site_lib_path)
for file in files:
sys.path.append(os.path.join(site_lib_path, file))
from printercx import printercx
from resttestservice.resttestservice import UITest
class ui(wx.Frame):
"""
This Class will create a Sample Frame and Create Two Buttons on tha Panel.
"""
def __init__(self,parent,id):
"""
This Fucntion will create a Frame and a Panel which has Two buttons: "OK" and "Cancel"
"""
"""-----SALQE Connecttion-----------"""
self.connection = printercx.deviceConnection()
self.ui = UITest(self.connection)
"""-----------Window Bar Name------"""
wx.Frame.__init__(self,parent,id,'GEN-2 Tool',size=(600,500))
panel=wx.Panel(self)
"""-----------Heading-------"""
header_text = wx.StaticText(panel, label="GEN-2 Tool", pos=(250,30))
font = wx.Font(15, wx.DECORATIVE, wx.NORMAL, wx.BOLD)
header_text.SetFont(font)
wx.StaticLine(panel, pos=(10, 75), size=(690,3))
"""-----------Buttons-------"""
self.pre_button=wx.Button(panel,label="Precondition",pos=(50,250),size=(100,40))
self.act_button=wx.Button(panel,label="Action",pos=(450,250),size=(100,40))
self.pass_button=wx.Button(panel,label="Pass",pos=(50,350),size=(100,40))
self.fail_button=wx.Button(panel,label="Fail",pos=(450,350),size=(100,40))
"""-------------------------------Excel-------------------------------------------------------"""
self.mainList=[]
self.val_list=[]
dic={}
book=xlrd.open_workbook("Reference_Mapping.xlsx")
sheet=book.sheet_by_name("TestCases")
n_row= sheet.nrows-1
n_col=sheet.ncols
row=1
while row<=n_row:
smallList=[]
col=0
while col<n_col:
cel=sheet.cell(row,0)
if cel.value!="":
self.val_list.append(cel.value)
key=sheet.cell(0,col).value
val=sheet.cell(row,col).value
dic[key]=val
col+=1
smallList.append(dic.copy())
self.mainList.append(smallList)
row+=1
self.val_list= list(set(self.val_list))
"""-------------------------------------------------------------------------------------------------"""
"""-----------Combo Box with Text-------"""
text=wx.StaticText(panel, label="Test Case: ", pos=(150,130))
font = wx.Font(10,wx.DECORATIVE, wx.NORMAL, wx.BOLD)
text.SetFont(font)
self.val_list.insert(0, "Select")
self.combobox=wx.ComboBox(panel, value=self.val_list[0], pos=(300,130), choices=self.val_list,style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.onTestCaseSelection, self.combobox)
print "-----------"
def onTestCaseSelection(self,event):
if self.combobox.GetSelection()>0:
print self.combobox.GetValue()
"""---------- Compairing Key's values--------------"""
for each in range(len(self.mainList)):
for every in range(len(self.mainList[each])):
if self.mainList[each][every]['TC_ID']==self.combobox.GetValue():
if self.mainList[each][every]['Ref_ID_Pre']=="":
if self.mainList[each][every]['Ref_ID_Post']!="":
self.pre_button.Enable(False)
self.act_button.Enable(True)
self.Bind(wx.EVT_BUTTON,self.send_udw,self.act_button)
self.pass_button.Enable(True)
self.fail_button.Enable(True)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']=="":
self.pre_button.Enable(True)
self.Bind(wx.EVT_BUTTON,self.send_udw,self.pre_button)
self.act_button.Enable(False)
self.pass_button.Enable(False)
self.fail_button.Enable(False)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']!="":
action_button_cmd=self.mainList[each][every]['Ref_ID_Post']
self.pre_button.Enable(True)
self.Bind(wx.EVT_BUTTON,self.send_udw,self.pre_button)
self.act_button.Enable(False)
self.pass_button.Enable(False)
self.fail_button.Enable(False)
else:
self.disableAllControls(without=None)
def disableAllControls(self, without=None):
if without==None:
self.pre_button.Enable(False)
self.act_button.Enable(False)
self.pass_button.Enable(False)
self.fail_button.Enable(False)
def send_udw(self,event):
for each in range(len(self.mainList)):
for every in range(len(self.mainList[each])):
if self.mainList[each][every]['TC_ID']==self.combobox.GetValue():
if self.mainList[each][every]['Ref_ID_Pre']=="":
if self.mainList[each][every]['Ref_ID_Post']!="":
if self.act_button.IsEnabled()==True:
post_command=self.mainList[each][every]['Ref_ID_Post']
post_udw="ui_v3.move_to_state "+post_command+" 1"
self.connection.udw(post_udw)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']=="":
if self.pre_button.IsEnabled()==True:
post_command=self.mainList[each][every]['Ref_ID_Pre']
post_udw="ui_v3.move_to_state "+post_command+" 1"
self.connection.udw(post_udw)
if self.mainList[each][every]['Ref_ID_Pre']!="":
if self.mainList[each][every]['Ref_ID_Post']!="":
if self.pre_button.IsEnabled()==True:
post_command=self.mainList[each][every]['Ref_ID_Pre']
post_udw="ui_v3.move_to_state "+post_command+" 1"
print post_udw
self.connection.udw(post_udw)
"""----Enabling button---"""
self.pre_button.Enable(False)
self.act_button.Enable(True)
self.pass_button.Enable(True)
self.fail_button.Enable(True)
time.sleep(1)
I want to send a command once this button self.act_button.Enable(True) gets enabled.
You can bind the button's to events before you disable them. They aren't going to react to events (other than maybe mouse events) until you enable them. There is no reason to bind events when you enable the button.
If you want to call a function after the enabling process (i.e. self.act_button.Enable(True)), then just call the function right after that:
self.act_button.Enable(True)
self.myFunction(*args, **kwargs)
If you want to create some kind of custom event, then you'll want to look into how to use wx.PostEvent and wx.lib.newevent. The following resources might interest you as well:
https://wiki.wxpython.org/CustomEventClasses
https://wxpython.org/Phoenix/docs/html/events_overview.html
http://wiki.ozanh.com/doku.php?id=python:misc:wxpython_postevent_threading

Why is this Python 2.7 code generating excessive labels?

I'm working with Python 2.7 using idle.
I have a getVar Button, to get whatever text is in Entry
and put it in myEmpty Label, using a btnWork function. I only want one myEmpty Label.
However, in the following code if I put myEmpty Label in the function, I get labels everytime I click the button. This is not what I want.
from Tkinter import *
myGui=Tk()
myGui.geometry("200x100")
myGui.title("basicGUI")
myGui.configure(bg="gray")
entryVar = StringVar()
entryVar.set("")
entry = Entry(textvariable=entryVar, width=10)
entry.pack()
eV = StringVar()
def btnWork():
global eV
eV = StringVar()
myBtn=Button(text="getVar", command=btnWork)
myBtn.pack()
myEmpty = Label(textvariable=eV, width=10)
myEmpty.pack()
mainloop()
How can I prevent this?
When you click the button you need to get the information with .get() then update the label
from Tkinter import *
myGui=Tk()
myGui.geometry("200x100")
myGui.title("basicGUI")
myGui.configure(bg="gray")
eV=''
entry = Entry(width=10)
entry.pack()
def btnWork():
eV = entry.get()
myEmpty.config(text=eV)
myBtn=Button(text="getVar", command=btnWork)
myBtn.pack()
myEmpty = Label(text=eV, width=10)
myEmpty.pack()
myGui.mainloop()

Tabbed GUI keeps hanging on entry box

I have a very primitive GUI built with Tkinter. This is my first attempt at a GUI so I am struggling to understand what is going on (and with syntax). Here is what I have:
from __future__ import division, print_function
import os, ttk, tkFileDialog, Tkconstants
import Tkinter as tk
import datetime as dt
Tkinter = tk
# define OS version
version = '0.0.2'
class TestGUI(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
# try building list of instruments and sites
if os.path.isfile('config'):
with open(''config','r') as config:
config = dict( [(r.split('=')[0].strip(), r.split('=')[1].strip()) for r in config.read().split('\n') if r[0]<>'#'] )
self.datapath = config['datapath']
else:
self.datapath = '../'
def initialize(self):
self.grid()
# set up tabs
self.geometry( "%dx%d+%d+%d" % (1500, 900, 200, 50) )
nb = ttk.Notebook(self)
nb.pack(fill='both',expand='yes')
f1 = tk.Frame(bg='green')
f2 = tk.Frame(bg='blue')
f3 = tk.Frame(bg='red')
f1.grid()
f2.grid()
f3.grid()
nb.add(f1, text='General'.ljust(12,' '))
nb.add(f2, text='Plot'.ljust(12,' '))
nb.add(f3, text='Analysis'.ljust(12,' '))
button = tk.Button(f2,text='I AM A BUTTON!')
button.pack(side='left', anchor='nw', padx=3, pady=5)
# insert button and text box for specifying data location
path_button = tk.Button(f1,text='Browse',command=self.askdirectory).pack(side='left', anchor='nw', padx=10, pady=15)
self.path_entry = tk.StringVar()
self.entry = tk.Entry(f1,textvariable=self.path_entry)
self.entry.grid(column=12,row=8,columnspan=10)
self.entry.bind("<Return>", self.OnPressEnter)
self.path_entry.set(u"Sites directory path...")
def OnButtonClick(self):
print("You clicked the button !")
def OnPressEnter(self,event):
print("You pressed enter !")
def askdirectory(self):
"""Returns a selected directoryname."""
self.datapath = tkFileDialog.askdirectory()
self.path_entry.set(self.datapath)
if __name__ == "__main__":
app = TestGUI(None)
app.title(version)
app.mainloop()
My problem is centered around the addition of an entry box here:
self.path_entry = tk.StringVar()
self.entry = tk.Entry(f1,textvariable=self.path_entry)
self.entry.grid(column=12,row=8,columnspan=10)
self.entry.bind("<Return>", self.OnPressEnter)
self.path_entry.set(u"Sites directory path...")
If I run the code as-is, it just hangs (it also hangs if I use "f2"; I suspect it is getting caught in the infinite loop without actually doing anything). However, if I change the parent from "f1" to "f3" or it works (the entry box is now in frame 3 instead of frame 1, but it at least does not hang on me). There is another issue even when f3 is used: the entry box's width/position never change despite my changing of column/row/columnspan values.
Does anyone know why the code is hanging when I specify "f1" or "f2" and how to fix it?
Does anyone know why my entry box position/size is not changing?
You have put widgets in f1 and f2 using the pack geometry manager:
button = tk.Button(f2,text='I AM A BUTTON!')
button.pack(side='left', anchor='nw', padx=3, pady=5)
#and
path_button = tk.Button(f1,text='Browse',command=self.askdirectory).pack(side='left', anchor='nw', padx=10, pady=15)
Mixing geometry managers can lead to your program hanging, so using grid to put in the Entry does exactly that.
From effbot.org:
Warning: Never mix grid and pack in the same master window. Tkinter will happily spend the rest of your lifetime trying to negotiate a solution that both managers are happy with. Instead of waiting, kill the application, and take another look at your code. A common mistake is to use the wrong parent for some of the widgets.
The problem you describe of the Entry not changing position is because it is the only widget there, so the row(s) and column(s) in which the entry is are the only ones which do not have a width and height of 0. To make rows and columns without widgets take up space, use grid_rowconfigure(index, weight=x) where x is non-zero. An example is given in this answer.
Again from effbot.org:
weight=
A relative weight used to distribute additional space between rows. A row with the weight 2 will grow twice as fast as a row with weight 1. The default is 0, which means that the row will not grow at all.

How do I wait for a certain number of buttons to be clicked in Tkinter/Python?

I'm trying to write a simple 'Simon' game, but I have hit a road block here, and honestly have no idea how to get around it.
So here, I made a class for the four buttons in the GUI:
class button:
def buttonclicked(self):
self.butclicked= True
def checkIfClicked(self):
if self.butclicked== True:
global pressed
pressed.append(self.color)
self.butclicked= False
def __init__(self, color1):
self.color= color1
self.button= tk.Button(root, text=' '*10, bg= self.color, command= self.buttonclicked)
self.button.pack(side='left')
self.butclicked=False
I then created four instances of this class in blue, red, yellow, and green as bb, rb, yb, and gb.
Once everything is packed into the Tk() module, it enters a while loop that appends a random color to a list activecolors. I try to use the following loop to wait until the list pressed is at least as long as the list activecolors before comparing the two to see if the user was correct:
while len(pressed)<len(activecolors):
sleep(.25)
print('In the check loop')
bb.checkIfClicked()
rb.checkIfClicked()
yb.checkIfClicked()
gb.checkIfClicked()
However, since it is stuck inside the while loop, the program can't tell that the button has been clicked. I thought adding the sleep method into the loop would allow the code to have time to do other things (such as process button clicks), but this is not the case. Any help is appreciated.
Here is the link to the full code, if you would like to see it. A warning though: it's not pretty.
Edit:
I ended up just changing the code to check the list only after a new button was clicked, telling the computer the code was ready. I've updated the Google Document if you'd like to see it.
You are making it too complicated. This program uses partial from functiontools to allow a variable to be passed to the function so one function handles all clicks (Python 2.7).
from Tkinter import *
from functools import partial
class ButtonsTest:
def __init__(self):
self.top = Tk()
self.top.title('Buttons Test')
self.top_frame = Frame(self.top, width =400, height=400)
self.colors = ("red", "green", "blue", "yellow")
self.colors_selected = []
self.num_clicks = 0
self.wait_for_number = 5
self.buttons()
self.top_frame.grid(row=0, column=1)
Button(self.top_frame, text='Exit',
command=self.top.quit).grid(row=2,column=1, columnspan=5)
self.top.mainloop()
##-------------------------------------------------------------------
def buttons(self):
for but_num in range(4):
b = Button(self.top_frame, text = str(but_num+1),
command=partial(self.cb_handler, but_num))
b.grid(row=1, column=but_num+1)
##----------------------------------------------------------------
def cb_handler( self, cb_number ):
print "\ncb_handler", cb_number
self.num_clicks += 1
this_color = self.colors[cb_number]
if (self.num_clicks > self.wait_for_number) \
and (this_color in self.colors_selected):
print "%s already selected" % (this_color)
self.colors_selected.append(this_color)
##===================================================================
BT=ButtonsTest()