Tkinter Listbox with Entry
Solution 1
you could give the user some entries then create a listbox from that input
but you cant just change a listboxes text like that
maybe try a different GUI Library like WX
EDIT
here is something you can do:
from Tkinter import *
root = Tk()
opt_list = ['opt1','opt2','opt3','opt4','opt5']
sel_list = []
def get_sel():
sel_list.append(Lb1.curselection())
root.destroy()
def change_opt():
entry = E.get()
change = entry.split(" ")
print change
Lb1.insert(int(change[0]),change[1])
root.update()
def cancel():
root.destroy()
E = Entry(root)
A = Button(root, text ="Change", command = change_opt)
B = Button(root, text ="Submit", command = get_sel)
C = Button(root, text ="Cancel", command = cancel)
Lb1 = Listbox(root, selectmode=MULTIPLE)
for i,j in enumerate(opt_list):
Lb1.insert(i,j)
Lb1.pack()
B.pack()
C.pack()
E.pack()
A.pack()
root.mainloop()
this will make a listbox with the options in opt_list
then when you type for example 5 hello
the entry and press Change it will add the option hello
to the fifth place
thats the only way i can think of
Solution 2
I know it has been a while since this question, but I have created a widget called 'ListboxEditable', which is able to act as a listbox and, when double-clicking on an item, the user can type anything inside an entry. Then, when the user clicks another row, the information is saved on the corresponding modified cell. Note that the user can use the up and down keys to browse the entire given list (the selected row has a different background color).
This code has been developed based on the answer from @Bryan Oakley.
Minimal working case
# Imports
from tkinter import *
from tkinter.ttk import *
# Import for the listboxEditable
from ListboxEditable import *
# Colors
colorActiveTab="#CCCCCC" # Color of the active tab
colorNoActiveTab="#EBEBEB" # Color of the no active tab
# Fonts
fontLabels='Calibri'
sizeLabels2=13
# Main window
root = Tk()
# *** Design *****
frame_name=Frame(root,bg=colorActiveTab) # Column frame
frame_name_label=Frame(frame_name,bg='blue') # Label frame
label_name=Label(frame_name_label, text="Header", bg='blue', fg='white', font=(fontLabels, sizeLabels2, 'bold'), pady=2, padx=2, width=10)
frame_name_listbox=Frame(frame_name,bg='blue') # Label frame
list_name=['test1','test2','test3']
listBox_name=ListboxEditable(frame_name_listbox,list_name)
# *** Packing ****
frame_name.pack(side=LEFT,fill=Y)
frame_name_label.pack(side=TOP, fill=X)
label_name.pack(side=LEFT,fill=X)
frame_name_listbox.pack(side=TOP, fill=X)
listBox_name.placeListBoxEditable()
# Infinite loop
root.mainloop()
ListboxEditable class
# Author: David Duran Perez
# Date: May 26, 2017
# Necessary imports
from tkinter import *
from tkinter import ttk
# Colors
colorActiveTab="#CCCCCC" # Color of the active tab
colorNoActiveTab="#EBEBEB" # Color of the no active tab
# Fonts
fontLabels='Calibri'
sizeLabels2=13
class ListboxEditable(object):
"""A class that emulates a listbox, but you can also edit a field"""
# Constructor
def __init__(self,frameMaster,list):
# *** Assign the first variables ***
# The frame that contains the ListboxEditable
self.frameMaster=frameMaster
# List of the initial items
self.list=list
# Number of initial rows at the moment
self.numberRows=len(self.list)
# *** Create the necessary labels ***
ind=1
for row in self.list:
# Get the name of the label
labelName='label'+str(ind)
# Create the variable
setattr(self, labelName, Label(self.frameMaster, text=self.list[ind-1], bg=colorActiveTab, fg='black', font=(fontLabels, sizeLabels2), pady=2, padx=2, width=10))
# ** Bind actions
# 1 left click - Change background
getattr(self, labelName).bind('<Button-1>',lambda event, a=labelName: self.changeBackground(a))
# Double click - Convert to entry
getattr(self, labelName).bind('<Double-1>',lambda event, a=ind: self.changeToEntry(a))
# Move up and down
getattr(self, labelName).bind("<Up>",lambda event, a=ind: self.up(a))
getattr(self, labelName).bind("<Down>",lambda event, a=ind: self.down(a))
# Increase the iterator
ind=ind+1
# Place
def placeListBoxEditable(self):
# Go row by row placing it
ind=1
for row in self.list:
# Get the name of the label
labelName='label'+str(ind)
# Place the variable
getattr(self, labelName).grid(row=ind-1,column=0)
# Increase the iterator
ind=ind+1
# Action to do when one click
def changeBackground(self,labelNameSelected):
# Ensure that all the remaining labels are deselected
ind=1
for row in self.list:
# Get the name of the label
labelName='label'+str(ind)
# Place the variable
getattr(self, labelName).configure(bg=colorActiveTab)
# Increase the iterator
ind=ind+1
# Change the background of the corresponding label
getattr(self, labelNameSelected).configure(bg=colorNoActiveTab)
# Set the focus for future bindings (moves)
getattr(self, labelNameSelected).focus_set()
# Function to do when up button pressed
def up(self, ind):
if ind==1: # Go to the last
# Get the name of the label
labelName='label'+str(self.numberRows)
else: # Normal
# Get the name of the label
labelName='label'+str(ind-1)
# Call the select
self.changeBackground(labelName)
# Function to do when down button pressed
def down(self, ind):
if ind==self.numberRows: # Go to the last
# Get the name of the label
labelName='label1'
else: # Normal
# Get the name of the label
labelName='label'+str(ind+1)
# Call the select
self.changeBackground(labelName)
# Action to do when double-click
def changeToEntry(self,ind):
# Variable of the current entry
self.entryVar=StringVar()
# Create the entry
#entryName='entry'+str(ind) # Name
self.entryActive=ttk.Entry(self.frameMaster, font=(fontLabels, sizeLabels2), textvariable=self.entryVar, width=10)
# Place it on the correct grid position
self.entryActive.grid(row=ind-1,column=0)
# Focus to the entry
self.entryActive.focus_set()
# Bind the action of focusOut
self.entryActive.bind("<FocusOut>",lambda event, a=ind: self.saveEntryValue(a))
# Action to do when focus out from the entry
def saveEntryValue(self,ind):
# Find the label to recover
labelName='label'+str(ind)
# Remove the entry from the screen
self.entryActive.grid_forget()
# Place it again
getattr(self, labelName).grid(row=ind-1,column=0)
# Change the name to the value of the entry
getattr(self, labelName).configure(text=self.entryVar.get())
Some sreenshots
Solution 3
No, tkinter doesn't support in-place editing of items in a listbox. Of course, if you don't really need a listbox, you can always stack labels or entry widgets on top of each other to get a similar effect.
en_Knight
Updated on June 04, 2022Comments
-
en_Knight almost 2 years
Is there a way to have the items of a Tkinter Listbox be Entry Widgets? The result would be that you could dynamically modify the text in an Listbox entry. If your Listbox looks like:
-------- | Apples | | Pears | | Oranges | ---------
then you would want to be able to click on Apples and write some arbitrary text - you could then bind the Enter key, say, to trigger a function based on the new text.
-
en_Knight almost 11 yearsThis is what I assumed, but I'll have the itch until I see why not - does it say this somewhere?
-
Serial almost 11 yearshmm i dont think it is really written anywhere its more of like Tk isnt advanced enough to do that kind of thing... ill look around though
-
en_Knight almost 11 yearsThis is what I had (more or less), but if the listbox was far away from the entries it was slow to click back and forth, and if it was right next to them it looked messy. Not a big deal, and this style is a pretty good way of writing the solution. Thanks!
-
Serial almost 11 yearsyou can edit the layout i just typed that up real quick from some code i had glad i could help:)
-
lukehawk over 5 yearsI know its been years - but, you made the
ListBoxEditable
a subclass ofobject
instead ofFrame
. I have seen this before, but curious why? If I want to use this class, how do I usepack
orgrid
to place it in the master frame? Is it as easy as changing the declaration toclass ListboxEditable(Frame)
instead ofclass ListboxEditable(object):
? I apologize if this is a stupid question - I am new here. -
David Duran over 5 years@lukehawk, in this case, the listbox I created had a method to place it called 'placeListBoxEditable()'. You just have to call it when you want to place it. It is based on a grid system.
-
razdi over 3 yearsIt would be great if you could add some explanation around your code and how it is different from the accepted answer. Just dumping code is not always the best.