populating listbox from selection, python - macos

Hi to all that look and might be able to help. I'm new to Python, and to coding in general. I'm working on a program that the basic concept of it is to have a few lists, make a selection from one list, and then another list is populated based on that first choice. I have been able to create the GUI, I've been able to create various different forms of "Listbox", I've been able to follow tutorials that show how to retrieve the indicies of that "Listbox", but I haven't been able to get the 2nd Listbox to fill in with the list I created for a choice made in the 1st box. I've tried checkboxes too, I did get closer on that one, but still no dice.
The supplied code below works in the sense that I can print the 2nd list into the python shell, but when I get a listbox set up in my GUI I can't get it to populate there. Nothing every happens. And I know that I don't have a listbox in this code to have it be populated with the 2nd list. So in this code, I would like the 'brand' choice if 'Apples', to populate the list from 'modelA' in a listbox. Or if the checkboxes actually weren't there and the items in 'brand' where in their own listbox. Any direction might help a lot more than what I've been able to do. Thanks again.
Python 3.3.2
Mac OS X 10.8.5
from tkinter import *
#brand would be for first listbox or checkboxes
brand = ['Apples','Roses', 'Sonic', 'Cats']
#model* is to be filled into the 2nd listbox, after selection from brand
modelA = ['Ants', 'Arrows', 'Amazing', 'Alex']
modelR = ['Early', 'Second', 'Real']
modelS= ['Funny', 'Funky']
modelC= ['Cool', 'Daring', 'Double']
#create checkboxes
def checkbutton_value():
if(aCam.get()):
print("Models are: ", modelA)
if(rCam.get()):
print("Models are: ", modelR)
if(sCam.get()):
print("Models are: ", modelS)
if(cCam.get()):
print("Models are: ", modelC)
#create frame, and check checkbuttons state, print value of model
root = Tk()
aCam = IntVar()
rCam = IntVar()
sCam = IntVar()
cCam = IntVar()
#Checkbutton functions
apples = Checkbutton(root, text = "Apples", variable=aCam, command=checkbutton_value)
apples.pack(anchor="w")
roses = Checkbutton(root, text = "Roses", variable=rCam, command=checkbutton_value)
roses.pack(anchor="w")
sonic = Checkbutton(root, text = "Sonic", variable=sCam, command=checkbutton_value)
sonic.pack(anchor="w")
cats = Checkbutton(root, text = "Cats", variable=cCam, command=checkbutton_value)
cats.pack(anchor="w")
#general stuff for GUI
root.title('My Brand')
root.geometry("800x300")
root.mainloop()

To populate a Listbox based on the selection of another Listbox, you need to bind a method to the 1st Listbox's selection. Here's an example using makes/models of cars:
import Tkinter
class Application(Tkinter.Frame):
def __init__(self, master):
Tkinter.Frame.__init__(self, master)
self.master.minsize(width=512, height=256)
self.master.config()
self.pack()
self.main_frame = Tkinter.Frame()
self.main_frame.pack(fill='both', expand=True)
self.data = {
'Toyota': ['Camry', 'Corolla', 'Prius'],
'Ford': ['Fusion', 'Focus', 'Fiesta'],
'Volkswagen': ['Passat', 'Jetta', 'Beetle'],
'Honda': ['Accord', 'Civic', 'Insight']
}
self.make_listbox = Tkinter.Listbox(self.main_frame)
self.make_listbox.pack(fill='both', expand=True, side=Tkinter.LEFT)
# here we bind the make listbox selection to our method
self.make_listbox.bind('<<ListboxSelect>>', self.load_models)
self.model_listbox = Tkinter.Listbox(self.main_frame)
self.model_listbox.pack(fill='both', expand=True, side=Tkinter.LEFT)
# insert our items into the list box
for i, item in enumerate(self.data.keys()):
self.make_listbox.insert(i, item)
def load_models(self, *args):
selection = self.make_listbox.selection_get()
# clear the model listbox
self.model_listbox.delete(0, Tkinter.END)
# insert the models into the model listbox
for i, item in enumerate(self.data[selection]):
self.model_listbox.insert(i, item)
root = Tkinter.Tk()
app = Application(root)
app.mainloop()

Related

How to create an input box with iron python using windows.forms?

For a simple Gui in Iron python I need a simple dialog box with an input text field and OK and cancel button and return value of input text, equivalent to Visual Basic input box.
So basically, dialog pops up, you enter value, hit OK an dialog box closes and returns value to calling function.
I could not find anything in the windows forms library.
I guess you need to create a form yourself from scratch, using text box, etc..?
Is there really no input box in winforms?
If so, could anyone share how to create one with winforms and iron python?
Thanks for help!
Nils
I am new to Ironpython and GUI programming, therefore the following solution might not be elegant neither complete, but it seems to work.
Any ideas for improvement?
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Drawing import Point
from System.Windows.Forms import Button, Form, Label, TextBox, FormStartPosition, FormBorderStyle
class MyInputBoxClass(Form):
def __init__(self,message, title, defaultText):
#Creates Input Box with text Input Field
#define form
self.Text = title
self.Width = 600
self.Height = 110
self.StartPosition = FormStartPosition.CenterScreen;
self.FormBorderStyle = FormBorderStyle.FixedDialog
self.MinimizeBox = False;
self.MaximizeBox = False;
#define label
self.label = Label()
self.label.Text = message
self.label.Location = Point(10, 10)
self.label.Height = 30
self.label.Width = 250
#define text box
self.textbox = TextBox()
self.textbox.Text = defaultText
self.textbox.Location = Point(10, 40)
self.textbox.Width = 500
#define button
self.button1 = Button()
self.button1.Text = 'ok'
self.button1.Location = Point(510, 40)
self.AcceptButton = self.button1
#define dialog result
self.button1.DialogResult = DialogResult.OK;
#add controls to form
self.Controls.Add(self.label)
self.Controls.Add(self.textbox)
self.Controls.Add(self.button1)
#Todo: Handel Close Input Box Event
def MyInputBox(message, title, defaultText):
form = MyInputBoxClass(message, title, defaultText)
form.ShowDialog()
#Application.Run(form2) #this is not working, you need ShowDialog for modal form
return form.textbox.Text
def TestGui(analysis_obj):
#This function is beeing called from API
inputTextFromDialogBox = MyInputBox("Please Enter Example Text","ExampleInputBox","Its working but I'm not convinced")
print ("Input Box Return Value is '%s'"%inputTextFromDialogBox)
#ExtAPI.Log.WriteMessage("Input Box Return Value is '%s'"%inputTextFromDialogBox)

Adding a check next to the selected item in tkinter OptionMenu

How could I add a check sign next to the currently selected item (or highlight it) in a OptionMenu in a tkinter GUI? The idea is that when I click again to select another item, I can see easily which one is selected (similar to the following picture)
I just added a new example:
from tkinter import *
OptionList = [
"Aries",
"Taurus",
"Gemini",
"Cancer"
]
app = Tk()
app.geometry('100x200')
variable = StringVar(app)
variable.set(OptionList[0])
opt = OptionMenu(app, variable, *OptionList)
opt.config(width=90, font=('Helvetica', 12))
opt.pack(side="top")
labelTest = Label(text="", font=('Helvetica', 12), fg='red')
labelTest.pack(side="top")
def callback(*args):
labelTest.configure(text="The selected item is {}".format(variable.get()))
variable.trace("w", callback)
app.mainloop()
Just use ttk widgets for this modern looking style, try saying something like:
from tkinter import ttk
....
#arguments - master variable default *values
opt = ttk.Optionmenu(app, variable, OptionList[0], *OptionList)
The effect given by this is pretty similar or maybe identical to what your trying to achieve.
You might notice an additional third positional argument here, it is actually default=OptionList[0] argument specified here(specific to just ttk.Optionmenu), it is just the default value that the optionmenu will display, ignoring this might lead to some bugs in the looks of optionmenu, like this.
And also keep in mind, it does not have a font option too. To overcome this, check this out
Hope this was of some help to you, do let me know if any errors or doubts.
Cheers
You can get similar effect using tk.OptionMenu:
from tkinter import *
OptionList = [
"Aries",
"Taurus",
"Gemini",
"Cancer"
]
app = Tk()
app.geometry('300x200')
variable = StringVar(app)
variable.set(OptionList[0])
opt = OptionMenu(app, variable, None) # need to supply at least one menu item
opt.config(width=90, font=('Helvetica', 12))
opt.pack(side="top")
# populate the menu items
menu = opt['menu']
menu.delete(0) # remove the None item
for item in OptionList:
menu.add_radiobutton(label=item, variable=variable)
labelTest = Label(text="", font=('Helvetica', 12), fg='red')
labelTest.pack(side="top")
def callback(*args):
labelTest.configure(text="The selected item is {}".format(variable.get()))
variable.trace("w", callback)
app.mainloop()

My toplevel window in tkinter is no longer being destroyed. It was working fine until I tried changing other aspects of my function

I'm trying to get a popup window to display random text and a picture every time a button is pressed in tkinter. My original code was going to use an if/elif statement to do this. It worked as intended but I thought it might be easier to pair the data in a dictionary since there would be 50 elif statements otherwise (is it frowned upon to use so many? I actually found it easier to read).I was able to get this working but now the toplevel window in tkinter is not being destroyed like it was in the original function. A new Label is just being created on top of it and I can't figure out why. The function code is below. Thanks in advance, any help would be appreciated!
def Add_Gemstone2():
global Addstone
#destroy the previous window if there is one.
try:
AddStone.destroy()
except(AttributeError, NameError):
pass
#create the window.
AddStone=Toplevel()
AddStone.configure(bg='White', height=200, width=325)
AddStone.geometry('325x180+10+100')
# add gemstones to list from file.
gem_stones = open('gemstones.txt')
all_gem_stones = gem_stones.readlines()
gemstones = []
for i in all_gem_stones:
gemstones.append(i.rstrip())
# Add pictures to list.
path = r'C:\Users\Slack\Desktop\PYTHON WORKS\PYTHON GUI PROJECT\gems'
gempictures = []
# r=root, d=directories, f = files
for r,d,f in os.walk(path):
for file in f:
if '.gif' in file:
gempictures.append(os.path.join(r, file))
#create dictionary from lists.
gemdiction = dict(zip(gemstones, gempictures))
key, val = random.choice(list(gemdiction.items()))
# create the labels.
glbl1 = Label(AddStone, text=key, bg='gold', wraplength=300)
glbl1.pack()
image = ImageTk.PhotoImage(Image.open(val))
glbl2 = Label(AddStone, image=image)
glbl2.image = image
glbl2.pack()

Updating a kivy label on a screen when dynamically generating it through a list?

Firstly, disclaimer: I am terribly new to programming and am trying to build my understanding with this project. Additionally, let me say I have searched the forums and found similar posts to mine, but none have the issue of updating a label that has been dynamically generated through a list.
My question is in my code, commented out, but to summarize: I generate buttons and labels for each item in a list. Then the buttons should add and subtract from the linked value in a dictionary. Currently the code does this, but the labels on screen don't update to reflect the new values. Can someone please assist with updating the value for "ordlayout.add_widget(ordlayout.lbl[str(i)])" when calling to updateup and updatedown?
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
from kivy.base import runTouchApp
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from functools import partial
#The first screen the app opens to. Contains all other screen branches.
class MainScreen(Screen):
pass
#NewOrder will be the screen used for choosing which
#items/and how many of each the customer wants added.
class NewOrder(Screen):
def __init__(self, **kwargs):
super(NewOrder, self).__init__(**kwargs)
#This will eventually read/create a list of strings from a user-modified file.
self.foods = ["Puppy", "Cat", "Fish"]
#I create a dictionary linking a number to each item.
self.countfoods = {}
for i in self.foods:
self.countfoods[i] = 0
#Now I create a grid layout to put on the screen.
ordlayout = GridLayout()
ordlayout.cols = 8
ordlayout.row_default_height=20
ordlayout.buttons={}
ordlayout.btns1 = {}
ordlayout.lbl = {}
#The items I want on the screen are 1.)First item from list. 2.) Minus button.
#3.) Current number of the item. 4.) Plus button.
#I want these four buttons for each item.
for i in self.countfoods:
#Adds text for first item.
ordlayout.add_widget(Label(text=i))
#Adds a button for minus, linked to a unique dict value.
ordlayout.buttons[str(i)] = Button(text="-")
ordlayout.lbl[str(i)] = Label(text=str((self.countfoods[i])))
#The below assigns the specific object location of each label
#to a variable for passing to ocuntup and countdown.
tempPlacement = str(ordlayout.lbl[str(i)])
ordlayout.buttons[str(i)].bind(on_press=partial(self.updatedown, i))
ordlayout.add_widget(ordlayout.buttons[str(i)])
#Add the value that I want to update.
ordlayout.add_widget(ordlayout.lbl[str(i)])
#Adds a button for addition, but doesn't properly link it to a specific value.
ordlayout.btns1[str(i)] = Button(text="+")
ordlayout.btns1[str(i)].bind(on_press=partial(self.updateup, i))
ordlayout.add_widget(ordlayout.btns1[str(i)])
#Add that grid wit
h values to the screen.
self.add_widget(ordlayout)
#Function used to change value down by one.
def updatedown(self, event, i):
self.countfoods[event] -= 1
print (self.countfoods)
#Function used to change value up by one.
def updateup(self, event, i):
self.countfoods[event] += 1
print (self.countfoods)
#AdminOpt will be the screen used for
class AdminOpt(Screen):
def __init__(self, **kwargs):
super(AdminOpt, self).__init__(**kwargs)
#Will allow for opening and checking of created orders.
class OrdHist(Screen):
pass
#This is purely the class used for managing the other screens.
class ScreenManagement(ScreenManager):
pass
Main = Builder.load_file("Order Handler2.kv")
class Customer:
def __init__(self, name, pricelist):
self.name = name
self.pricelist = pricelist
class SimpleKivy(App):
def build(self):
return Main
if __name__== "__main__":
SimpleKivy().run()
Haven't been able to test this (your question is missing your kv file), but something like this might work:
#Function used to change value down by one.
def updatedown(self, i, button):
self.countfoods[i] -= 1
self.ordlayout.lbl[str(i)].text = str(self.countfoods[i])
print (self.countfoods)
#Function used to change value up by one.
def updateup(self, i, button):
self.countfoods[i] += 1
self.ordlayout.lbl[str(i)].text = str(self.countfoods[i])
print (self.countfoods)
You will also need to replace every occurence of ordlayout with self.ordlayout in the __init__() method.
As an aside, you don't need to do str(i) for your dictionary keys. In fact, you can use lists instead of dictionaries, if you prefer.

.get() not able to get results of checkboxes

See the following snippet of code:
def choose_ID():
import ttk
global single_ID
id = BooleanVar()
toplevel = Toplevel()
label1 = Label(toplevel, text = "Choose a User ID.", width = 40).pack(anchor=W, pady=5)
for items in range(len(single_ID)):
id = Checkbutton(toplevel, text=single_ID[items], variable=single_ID[items])
id.pack(anchor=W, padx=5)
single_run_but = Button(toplevel, text = "Run", width=10, height=1, command=run_command).pack(anchor=S, pady=5)
id.get()
Its purpose is to open a popup window with a number of checkboxes (the number could be anything from 1 to 100) containing user id's that have been passed to the function from earlier in the script.
The problem is with the id.get() line at the end. When it runs it errors, saying "Checkbutton instance has no attribute 'get'"
What do I need to change to be able to note which of the checkboxes have been checked (it could be only one or multiple boxes)?
Many thanks,
Chris.
The last time you set id is in the for loop. During this, you set id to be a checkbutton, which does not have the get() method.
What you want to do is use the get() method on an IntVar that is associated with the checkbutton through the variable attribute. You can keep references to these variables in a list. I've made a small example of how to dynamically create checkbuttons and still be able to get their values.
from Tkinter import *
def run_command():
selected_ids = []
for i, id_var in enumerate(id_var_list):
if id_var.get():
selected_ids.append(id_list[i])
print selected_ids
root = Tk()
Label(root, text = "Choose a User ID.", width = 40).pack(anchor=W, pady=5)
id_list = ['ID1', 'ID2', 'ID100']
id_checkbutton_list = []
id_var_list = []
for item in id_list:
id_var = IntVar()
id_checkbutton = Checkbutton(root, text=item, variable=id_var)
id_checkbutton.pack(anchor=W, padx=5)
id_var_list.append(id_var)
id_checkbutton_list.append(id_checkbutton)
Button(root, text = "Run", width=10, height=1, command=run_command).pack(anchor=S, pady=5)
root.mainloop()

Resources