Tkinter Python listbox - python

I am a new python user. I'm used to programing on matlab.
I've trying to make a simple GUI with Tkinter pack, but I'm having some problems with that. I had already read and searched what i want but I couldn't develop it.
What I'm trying to do is to make a listbox and when I choose one (or more) options the index be returned (and stored) as a variable (array or vector) that could be used to indexing another array.
The best result I got was a listbox where the index were printed, but not stored as a variable (at least it hasn't been shows in the variables list)
I'm using spyder (anaconda).
I tryied a lot of codes and I don't have this anymore.
Sorry for the dumb question. I guess I still thinking in a Matlab way to write

To keep this application simple, your best option is to get the listbox selection when you want to do something with it:
from tkinter import Tk, Listbox, MULTIPLE, END, Button
def doStuff():
selected = lb.curselection()
if selected: # only do stuff if user made a selection
print(selected)
for index in selected:
print(lb.get(index)) # how you get the value of the selection from a listbox
def clear(lb):
lb.select_clear(0, END) # unselect all
root = Tk()
lb = Listbox(root, selectmode=MULTIPLE) # create Listbox
for n in range(5): lb.insert(END, n) # put nums 0-4 in listbox
lb.pack() # put listbox on window
# notice no parentheses on the function name doStuff
doStuffBtn = Button(root, text='Do Stuff', command=doStuff)
doStuffBtn.pack()
# if you need to add parameters to a function call in the button, use lambda like this
clearBtn = Button(root, text='Clear', command=lambda: clear(lb))
clearBtn.pack()
root.mainloop()
I've also added a button to clear the listbox selection because you cannot unselect items by default.

First, import tkinter, then, create the listbox. Then, you can use curselection to get the contents of the listbox.
import tkinter as tk
root = tk.Tk() #creates the window
myListbox = tk.Listbox(root, select=multiple) #allows you to select multiple things
contentsOfMyListbox = myListbox.curselection(myListbox) #stores selected stuff in tuple
See the documentation here.

Related

Conceptual question (and optimization) of creating a bunch of buttons in Tkinter

I am making a personal project using Tkintr to create an interactive Periodic Table of Elements. Instead of making each Button for each element individually, I used the following code to create a bunch of buttons (beginner coder so sorry for formatting, etc):
from tkinter import *
from tkinter import messagebox
import pandas as pd
raw_csv = pd.read_csv('data/elements.csv')
el_symbols = {row.Number: row.Symbol for (index, row) in raw_csv.iterrows()}
img_ref_dict = {f'{sym}_img': f'images/{num}.png' for num, sym in el_symbols.items()}
window = Tk()
window.title("Periodic Table of Elements")
window.config(width=1202, height=676)
# All da buttons
# Creating population for button assignment
for name, path in img_ref_dict.items():
exec(f'{name} = PhotoImage(file="{path}")')
exec(f'{name}_button = Button(image={name}, highlightthickness=0, command=lambda: popup())')
window.mainloop()
To my understanding, the code contained within .mainloop() is continuously looping so is my for loop creating the buttons repeatedly? Would it be better to just create each button one by one? This method is just so much cleaner to me.
As per #acw1668's advice, you're on the right track but are better off doing something like:
for path in img_ref_dict.values(): # you don't really need 'name'
img = PhotoImage(file=path)
btn = Button(image=img, highlightthickness=0, command=lambda: popup())
btn.pack() # add the button to the UI (you'll probably want to tweak this a bit)
Minor Edit to say that unless you really need the name for each button image, you could tweak img_ref_dict to create a list of image paths instead, like so:
img_refs = [f'images/{num}.png' for num in el_symbols.keys()]
...and then modify the for loop slightly:
for path in img_refs:
# yadda yadda

Hi , How can I change a string number from Entry of tkinter into int number?

Hi i'm a beginner in python and I really got int trouble with some methods, I wanna give some number from Entry of tkinter class and show them with a chart,
but the thing is that I cant get int number:
so the chart wont work [here is the picture of my code , I get some bumber from entry but i cant make them integer number]
1: https://i.stack.imgur.com/2Vuvn.jpg
2: https://i.stack.imgur.com/Pa23V.jpg
Welcome. I'm posting a complete, I think, answer to this question but there are a couple of etiquette things you should know:
Please don't post screenshots of your code. Copy and paste into the editor.
Please post just enough code to show your problem, but which is complete enough that we can just copy it into our own editors / IDEs and run without a lot of modification.
The previous commenters are correct that this question has probably been answered a hundred times, so please try to search through previous answers before posting your question.
Having said that, I have not answered this question before, so here's my rendition. I know you're a beginner so I've tried to keep it as simple as possible, but you're also tackling TKinter so I've not made it overly simplistic.
import tkinter as tk
def main():
global entryVar, lableVar
#create a tkinter window:
rootWin = tk.Tk() #creates a root window
rootWin.title('Entry Test') #shows text on the title bar
rootWin.geometry('500x200') #sets the displayable size of the window
#we'll need these variables and they MUST be tk.StringVar()
entryVar = tk.StringVar() #variable to hold the entry value
lableVar = tk.StringVar() #variable to hold the lable value
#create an entry widget:
entry = tk.Entry(
rootWin,
width = 5,
textvariable = entryVar
)
entry.pack(expand=1)
entry.bind('<Return>', getEntryValue) #bind enter key to widget
entry.bind('<KP_Enter>', getEntryValue, add='+') #bind the other enter key to widget
#create a lable widget
lable = tk.Label(
rootWin,
textvariable = lableVar
)
lable.pack(expand=1)
lableVar.set("This is where the lable is.")
entry.focus_set() #set focus on the entry widget for convenience
rootWin.mainloop()
def getEntryValue(event):
global entryVar, lableVar
x = entryVar.get() #get the value from Entry
x = int(x) #change it to an int
lableVar.set(x) #set the lable variable
entryVar.set("") #clear the entry variable
if __name__ == "__main__":
main()
So, what's going on here is that we make a window in the usual way. I've created both an Entry() widget to get some input, and a Label() widget to show whatever has been input. I've broken the Entry() and Label() declarations up over multiple lines just to make them easier to read.
You can attach variables to many TKinter widgets to that you can .get() and .set() their values more easily, but they almost always need to be TKinter variable types such as StringVar() or IntVar(). I've created two such variables, one for the Entry() widget and another for the Label() widget.
I've also added "bindings" to the Entry() widget to both show how that works and to make data entry a bit more convenient. I don't know if you have a separate number pad on your computer keyboard so I've bound both the main <enter> key as well as the number pad's <enter> key. When you hit either one of those keys, the Entry() widget will call the getEntryValue() function which does the work of getting the value and displaying it on the window.
For convenience, entry.focus_set() immediately puts the focus on the Entry() widget, then the TKinter window enters the .mainloop() to do its stuff.
The getEntryValue() function is called by the events which we set on the Entry() widget. I broke it down into more lines than necessary to illustrate what needs to happen. First we retrieve the value of the Entry() widget through its variable, entryVar. You do that using entryVar's .get() method: x = entryVar.get(). That returns a string value which you will have to convert to an integer using the normal int() function available in Python. For this purposes of this demonstration I've chosen to display that value to a Label() widget which I've placed in the window, so I use the Label() widget's variable lableVar: lableVar.set(x). You don't have to convert the integer back into a string before doing this.
I then clear out the entryVar variable so that there isn't anything left in the Entry() widget to get in the way of our next entry.
I've used entryVar and lableVar as globals just to simplify the example.
And that's how you do it.
I guess the problem is here:
a=str(e3.get())
Try something like this:
a=int(e3.get())
Since what you want is an integer

How to create a combobox that includes checkbox for each item?

Fairly new to tkinter and python I was wondering how to achieve a button that would act like this :
Click on button drops down a list (so that's a combobox)
Each line of the list has a checkbox.
Finally if a checkbox is clicked run a function, or (even better) once combobox is no more dropped run a function with items checked as args.
UPDATE
The button/menuButton will have to act like a filter. When menu is dropped down user can uncheck multiple options (without the menu to disappear each time an item is clicked) he don't want. Therefore it's really important to be able to see checkboxes so as the user know which options are currently active.
I finally used the idea of Bryan by creating a top level frame. Here is what I have :
There is no widget to do what you want. You'll have to create a toplevel window with a bunch of checkbuttons. You can then trigger the appearance with a normal button.
I don't think the OptionMenu is intended to hold anything but strings. It sounds like you want the functionality of a Listbox, which has options to allow for multiple selections, get all selected items, and so on.
This gives you an OptionMenu with checkboxes in the contained Menu. Check whichever items you like, then right-click in the tkinter window to print the values of the checkboxes to the console.
from tkinter import *
master = Tk()
var = StringVar(master)
var.set("Check")
w = OptionMenu(master, variable = var, value="options:")
w.pack()
first = BooleanVar()
second = BooleanVar()
third = BooleanVar()
w['menu'].add_checkbutton(label="First", onvalue=True,
offvalue=False, variable=first)
w['menu'].add_checkbutton(label="Second", onvalue=True,
offvalue=False, variable=second)
w['menu'].add_checkbutton(label="Third", onvalue=1,
offvalue=False, variable=third)
master.bind('<Button-3>', lambda x: print("First:", first.get(), " Second:",
second.get(), " - Third:", third.get()))
mainloop()
See also this.

Checking if the user presses 'Return' while selected in an Entry box Tkinter

I'm using Tkinter to create a GUI for a simple geometry calculator I'm creating.
Basically, what I have is an Entry box. What I want is for the program/GUI/system to detect when the user of the program hits the 'Enter' or 'return' key WHILE they are in the Entry box. When this is detected, I want the contents of the Entry box to be appended to a list I have defined earlier. I also want a simple label to be created on the GUI that displays the contents of the list (including the appended item(s)). Note that the list begins with nothing in it.
Here is my code so far:
from tkinter import *
#Window setup(ignore this)
app = Tk()
app.title('Geometry Calculator')
app.geometry('384x192+491+216')
app.iconbitmap('Geo.ico')
app.minsize(width=256, height=96)
app.maxsize(width=384, height=192)
app.configure(bg='WhiteSmoke')
#This is the emtry list...
PointList = []
#Here is where I define the variable that I will be appending to the list (which is the object of the Entry box below)
StrPoint = StringVar()
def list_add(event):
#I don't really know how the bind-checking works and how I would implement it; I want to check if the user hits enter while in the Entry box here
if event.char == '':
PointList.append(StrPoint)
e1 = Entry(textvariable=StrPoint).grid(row=0, column=0)
app.bind('<Return>', list_add)
mainloop()
I don't really know the proper way to check for 'Return' and then use it in an if statement.
I hope you understand what I'm trying to get help with, and I've looked all around for an explanation that I could understand with no success.
Instead of binding with the app just bind it with the Entry widget object,i.e,e1
from tkinter import *
#Window setup(ignore this)
app = Tk()
app.title('Geometry Calculator')
app.geometry('384x192+491+216')
app.iconbitmap('Geo.ico')
app.minsize(width=256, height=96)
app.maxsize(width=384, height=192)
app.configure(bg='WhiteSmoke')
#This is the emtry list...
PointList = []
#Here is where I define the variable that I will be appending to the list (which is the object of the Entry box below)
StrPoint = StringVar()
def list_add(event):
print ("hello")
#I don't really know how the bind-checking works and how I would implement it; I want to check if the user hits enter while in the Entry box here
if event.char == '':
PointList.append(StrPoint)
e1 = Entry(textvariable=StrPoint)
e1.grid(row=0, column=0)#use grid in next line,else it would return None
e1.bind('<Return>', list_add)# bind Entry
mainloop()
The solution is to set the binding on the widget itself. That way, the binding will only apply while focus is on that widget. And since you're binding on a specific key, you don't need to check for the value later. You know the user pressed return, because that's the only thing that will cause the binding to fire.
...
e1.bind('<Return>', list_add)
...
You have another problem in that your list_add function needs to call the get method of the variable rather than accessing the variable directly. However, since you aren't using any of the special features of a StringVar, you really don't need it -- it's just one more thing you have to manage.
Here's how to do it without the StringVar:
def list_add(event):
PointLit.append(e1.get())
...
e1 = Entry(app)
e1.grid(row=0, column=0)
e1.bind('<Return>', list_add)
Note that you need to create the widget and lay out the widget in two steps. Doing it the way you did it (e1=Entry(...).grid(...) will cause e1 to be None since that is what .grid(...) returns.

Make Tkinter.Listbox selection persist

I have a program where I need to take a selection from Tkinter.Listbox and an entry field and do something with that data. However, if I highlight any text within the entry field (i.e., to delete previous entry), the Listbox selection is cleared. How can I overcome it so that the Listbox selection persists?
import Tkinter as tk
master = tk.Tk()
listbox = tk.Listbox(master)
listbox.grid(row=0, column=0)
items = ['a', 'b', 'c']
for item in items:
listbox.insert(tk.END, item)
efield = tk.Entry(master)
efield.grid(row=1, column=0)
tk.mainloop()
Steps to reproduce:
Type something in the entry field.
Select something in the listbox.
Highlight whatever you entered in the entry field => selection in the listbox gets cleared.
This related question with similar issue How to select at the same time from two Listbox? suggests to use exportselection=0, which doesn't seem to work for me. In such case selection = listbox.selection_get() throws an error while the right line is still highlighted.
I know this is an old question, but it was the first google search result when I came across the same problem. I was seeing odd behavior using 2 list boxes when using selection_get() and also the selection persistence issue.
selection_get() is a universal widget method in Tkinter, and was returning selections that were last made in other widgets, making for some really strange behavior. Instead, use the ListBox method curselection() which returns the selected indices as a tuple, then you can use the ListBox's get(index) method to get the value if you need.
To solve the persistence issue, set exportselection=0 when instantiating the ListBox instance.
list_box = tk.Listbox(master, exportselection=False)
...
selected_indices = list_box.curselection()
first_selected_value = list_box.get(selected_indices[0])
As for now, I wasn't able to cleanly overcome the problem. One way around is to create a variable which will store the selected list value on click:
selected = None
def onselect(e):
global selected
selected = listbox.selection_get()
listbox.bind('<<ListboxSelect>>', onselect)
This doesn't keep the highlight, but the selection is now stored in a variable and can be used further.

Categories

Resources