Using Python to create a simulation - python

I have these five lists:
list_1 = ['1','2','3','4','5']
list_2 = ['2','4','6','8','10']
list_3 = ['3','6','9','12','18']
list_4 = ['1','3','5','7','9']
list_5 = ['2','3','5','7','8']
What I am trying to do is make a simulation that will have drop down menus, where each menu 1 through 5 is correlated with each list 1 through 5 respectively.
But, the trick is that if there is a string value that is already choosen and present in one of the menus, the other menus that has the same string value will no longer have that as an option.
For example, '3' is present in list_1, list_3, list_4, and list_5.If I choose '3' for menu 4, then the option of '3' will no longer be available for list_1, list_3, and list_5.
What I have done:
I imported the itertools library, so I could find all possible combinations of the lists, respective to each menu.
import itertools
combos = list(itertools.product(list_1, list_2, list_3, list_4, list_5))
I know this might not be useful for the actual code later, but I thought it would be a good reference point. Next, I started looking into libraries that might be useful for this approach, I found tkinter was a good library.
import tkinter as tk
# Creating the main window
window = tk.Tk()
After this point, I'm sort of confused. How should I go about trying to code? I'm using the following documentation:
https://docs.python.org/3/library/tk.html
I've tried playing around with it, and was able to make a click me button, though this is not what I want:
import tkinter as tk
# Creating the main window
window = tk.Tk()
# Click me button to the main window
button = tk.Button(window, text="Click Me")
button.pack()
# Running Tkinter loop for button
window.mainloop()

This is an example of a Tkinter window that enables and disables menu items as per your description. If menu_item 3 is selected, then that menu is disabled, and the rest are enabled.
Here is the code:
Code:
from tkinter import *
from tkinter import ttk, messagebox
import copy
def disable_menuitem(menu_item):
enable_all_menus()
for i, m in enumerate(menu_list_items):
if menu_item in m:
menus[i].entryconfig(m.index(menu_item)+1, state="disabled")
print(f"List{i} - menu value {menu_item}")
# Function to enable all of the menu items
def enable_all_menus():
for i, m in enumerate(menu_list_items):
for j in m:
menus[i].entryconfig(m.index(j), state="normal")
# Create the Frame and menubar
root = Tk(className=' Example by ScottC')
root.geometry("200x200")
ttk.Entry(root).grid()
menubar = Menu(root)
# Create the menu widgets
menu1 = Menu(menubar)
menu2 = Menu(menubar)
menu3 = Menu(menubar)
menu4 = Menu(menubar)
menu5 = Menu(menubar)
menus = [menu1, menu2, menu3, menu4, menu5]
# Add menu widgets to the menubar
for i, m in enumerate(menus):
menubar.add_cascade(menu=m, label=f"List{i+1}")
# Define the names of each menu
list_1 = ['1','2','3','4','5']
list_2 = ['2','4','6','8','10']
list_3 = ['3','6','9','12','18']
list_4 = ['1','3','5','7','9']
list_5 = ['2','3','5','7','8']
menu_list_items = [list_1, list_2, list_3, list_4, list_5]
# Add menu items to the menu widgets
for i, l in enumerate(menu_list_items):
for item in l:
menus[i].add_command(label=item, command=lambda y=item: disable_menuitem(y))
root['menu'] = menubar
root.mainloop()
Output when 3 is selected:

Related

How to select one chech menu at one time in tkinter python

I created a menu with checkbutton in my tkinter program but i wanted to select only one menu at one time below is code
def menu(self):
menubar = Menu(bg="black",fg="white")
self.file_menu = Menu(menubar,tearoff=0)
self.file_menu.add_command(label="Save",command=self.Save)
self.edit_menu = Menu(menubar, tearoff=0)
self.edit_menu.add_command(label="Undo",command=self.Undo)
self.edit_menu.add_command(label="Redo",command=self.Redo)
self.edit_menu.add_separator()
self.edit_menu.add_command(label="Cut",command=self.Cut)
self.edit_menu.add_command(label="Copy",command=self.Copy)
self.edit_menu.add_command(label="Paste",command=self.Paste)
self.edit_menu.add_separator()
self.edit_menu.add_command(label="Find",command=self.Find)
self.edit_menu.add_command(label="Replace",command=self.Replace)
self.Run_menu = Menu(menubar,tearoff=0)
self.Run_menu.add_command(label="Run",command=self.Run)
Language_menu = Menu(tearoff=0)
Language_menu.add_checkbutton(label="Python")
Language_menu.add_checkbutton(label="Java")
self.Run_menu.add_cascade(label="Language ",menu=Language_menu)
menubar.add_cascade(label="File",menu=self.file_menu)
menubar.add_cascade(label="Edit",menu=self.edit_menu)
menubar.add_cascade(label="Run",menu=self.Run_menu)
self.config(menu=menubar)
i wants that if i will select python or java any one of them then other automatically got deselect
thanks in advance
If you must use check buttons but want these to function such that clicking one unchecks the other then you can do so by creating variables to track the state of the check buttons and updating these as appropriate when clicked.
Menu with check buttons: Here is an example of this:
import tkinter as tk
parent = tk.Tk()
# create variables to track the state of check buttons
check_python = tk.BooleanVar()
check_java = tk.BooleanVar()
# handle the check buttons being clicked by unchecking others
def check_python_clicked():
check_python.set(True)
check_java.set(False)
def check_java_clicked():
check_python.set(False)
check_java.set(True)
# create and display the menu
menu_bar = tk.Menu(bg="black", fg="white")
run_menu = tk.Menu(tearoff=0)
language_menu = tk.Menu(run_menu)
language_menu.add_checkbutton(label='Python', variable=check_python, command=check_python_clicked)
language_menu.add_checkbutton(label='Java', variable=check_java, command=check_java_clicked)
run_menu.add_cascade(label='Language', menu=language_menu)
menu_bar.add_cascade(label="Run", menu=run_menu)
parent.config(menu=menu_bar)
parent.mainloop()
Menu with radio buttons: However, you can use radio buttons and achieve the same functionality with less code. This would be a better approach in this case as your options are mutually exclusive:
import tkinter as tk
parent = tk.Tk()
menu_bar = tk.Menu(bg="black", fg="white")
run_menu = tk.Menu(tearoff=0)
language_menu = tk.Menu(run_menu)
language_menu.add_radiobutton(label='Python')
language_menu.add_radiobutton(label='Java')
run_menu.add_cascade(label='Language', menu=language_menu)
menu_bar.add_cascade(label="Run", menu=run_menu)
parent.config(menu=menu_bar)
parent.mainloop()

Why does my selection callback get called on my second Listbox?

from tkinter import *
from tkinter.ttk import *
root = Tk()
listbox = None
listboxMultiple = None
listboxStr = None
listboxMultipleStr = None
def main():
global root
global listboxStr
global listboxMultipleStr
global listbox
global listboxMultiple
root.protocol("WM_DELETE_WINDOW", exitApplication)
root.title("Title Name")
root.option_add('*tearOff', False) # don't allow tear-off menus
root.geometry('1600x300')
listboxStr = StringVar()
listboxStr.set("ABCD")
listbox = Listbox(root, name="lb1", listvariable=listboxStr, width=120)
listbox.pack(side=LEFT)
listbox.bind("<<ListboxSelect>>", selectListItemCallback)
listboxMultipleStr = StringVar()
listboxMultipleStr.set("")
listboxMultiple = Listbox(root, name="lb2", listvariable=listboxMultipleStr, width=120)
listboxMultiple.pack(side=LEFT)
root.mainloop()
def selectListItemCallback(event):
global listboxMultipleStr
global listbox
global listboxMultiple
print("event.widget is {} and listbox is {} and listboxMultiple is {}\n".format(event.widget, listbox, listboxMultiple))
selection = event.widget.curselection()
listboxMultipleStr.set("")
if selection:
index = selection[0]
data = event.widget.get(index)
newvalue = "{}\n{}".format(data,"SOMETHING")
print("selected \"{}\"\n".format( data ))
print("newvalue is \"{}\"\n".format( newvalue ))
listboxMultiple.insert(END, "{}".format(data))
listboxMultiple.insert(END, "SOMETHING")
#listboxMultipleStr.set( newvalue )
else:
pass
def exitApplication():
global root
root.destroy()
if __name__ == "__main__":
main()
Using python3 on Windows 7. I've setup a callback "selectListItemCallback" for one of my two listbox widgets. And yet, when I click on the text in "lb1" it works as expected, I update "lb2" with the same selected text plus I add another line to "lb2".
The issue is, when I then select the item in "lb2", it still calls the callback and the event.widget is "lb1" and not "lb2".
My intent is to have a list of items in 'lb1' and when I select any of them, then 'lb2' gets filled with info related to the selected 'lb1' item. And, I don't want a selection callback invoked in my 'lb2' widget.
Can you see what I'm doing wrong that could be causing this strange behavior?
Thank you.
I've posted the code; and this does run on my Windows 7 machine using python3. Python 3.8.6 to be exact.
It is because the event fires when the first list box loses the selection when you click on the other list box. The event fires whenever the selection changes, not just when it is set.
If you don't want the first listbox to lose its selection when you click in the second listbox, set exportselection to False for the listboxes. Otherwise, tkinter will only allow one to have a selection at a time.

Tkinter Listbox make a selection

I am trying to create a pop-up box to select multiple years. I have the box created but I cannot figure out how to make a button to actually select multiple years. The goal is to take that selection and store it in a list.
from tkinter import *
import pandas as pd
import tkinter as tk
test_years = ["2016", "2017", "2018", "2019"]
root = tk.Tk()
root.title("Test Year Selection")
lb = Listbox(root, selectmode=MULTIPLE, height = len(test_years), width = 50) # create Listbox
for x in test_years: lb.insert(END, x)
lb.pack() # put listbox on window
root.mainloop()
To clarify I am looking to select lets say 2017 and 2018 and have that selection stored in a list using tkinter listbox.
Any assistance would be greatly appreciated.
A example to get the value you select when you press the Start button:
from tkinter import *
# import pandas as pd
import tkinter as tk
def printIt():
SelectList = lb.curselection()
print([lb.get(i) for i in SelectList]) # this will print the value you select
test_years = ["2016", "2017", "2018", "2019"]
root = tk.Tk()
root.title("Test Year Selection")
lb = Listbox(root, selectmode=MULTIPLE, height = len(test_years), width = 50) # create Listbox
for x in test_years: lb.insert(END, x)
lb.pack() # put listbox on window
tk.Button(root,text="Start",command=printIt).pack()
root.mainloop()
Basically you want to add the value of selected item of listbox to a list. you need to call bind() method on the listbox widget. here is the code from this amazing tutorial on tkinter listbox
def get_value(event):
# Function to be called on item click
# Get the index of selected item using the 'curseselection' method.
selected = l.curselection()
if selected: # If item is selected
print("Selected Item : ",l.get(selected[0])) # print the selected item
# Create a listbox widget
l = Listbox(window)
l.bind('<>',get_value)
l.pack()

Order of file selection in Tkinter is not order in python program

I am trying to make a program which enables comparison of data from selected files in one graph. The order in which they are depcited as well as the distance between them is important. However the order in which I select them in the window created by using Tkinter is not the same as the order in which they are passed to the program. The order in which I have to select them in order to get the correct order is 2, 3, 4, 5, 1 this results in order 1, 2, 3, 4, 5 in the program.
It is not a big problem once you know it but the intention is that others will be using the program as well so I need it to work as simple and robust as possible. Below is the snippet of the code that I use where Tkinter is involved.
root = Tkinter.Tk()
filez = tkFileDialog.askopenfilenames(parent=root,title='Choose a file')
filez= root.tk.splitlist(filez)
root.destroy()
There are no options for controlling the order in listed in the documentation. Your best bet is to use multiple file selection dialogs one after another.
tkFileDialog doesn't have function to remeber order of selected files so you can build own FileDialog or...
... build some Dialog to select order of files after you get files from tkFileDialog
import Tkinter as tk
import tkFileDialog
def Selector(data):
def append(widget, element, results, display):
# append element to list
results.append(element)
# disable button
widget['state'] = 'disabled'
# add element to label
current = display['text']
if current:
current += '\n'
display['text'] = current + element
# create window
root = tk.Tk()
# list for correct order
results = []
# label to display order
tk.Label(root, text='ORDER').pack()
l = tk.Label(root, anchor='w', justify='left')
l.pack(fill='x')
# buttons to select elements
tk.Label(root, text='SELECT').pack()
for d in data:
b = tk.Button(root, text=d, anchor='w')
b['command'] = lambda w=b, e=d, r=results, d=l:append(w, e, r, d)
b.pack(fill='x')
# button to close window
b = tk.Button(root, text='Close', command=root.destroy)
b.pack(fill='x', pady=(15,0))
# start mainloop
root.mainloop()
return results
# --- main ---
root = tk.Tk()
filez = tkFileDialog.askopenfilenames(parent=root,title='Choose a file')
root.destroy()
print(filez)
filez = Selector(filez)
print(filez)

ComboBox clears unrelated ListBox tkinter python

I have a really simple GUI program written in python with tkinter:
from Tkinter import *
from ttk import Combobox
class TestFrame(Frame):
def __init__(self, root, vehicles):
dropdownVals = ['test', 'reallylongstring', 'etc']
listVals = ['yeaaaah', 'mhm mhm', 'untz untz untz', 'test']
self.dropdown = Combobox(root, values=dropdownVals)
self.dropdown.pack()
listboxPanel = Frame(root)
self.listbox = Listbox(listboxPanel, selectmode=MULTIPLE)
self.listbox.grid(row=0, column=0)
for item in listVals:
self.listbox.insert(END, item) # Add params to list
self.scrollbar = Scrollbar(listboxPanel, orient=VERTICAL)
self.listbox.config(yscrollcommand=self.scrollbar.set) # Connect list to scrollbar
self.scrollbar.config(command=self.listbox.yview) # Connect scrollbar to list
self.scrollbar.grid(row=0, column=1, sticky=N+S)
listboxPanel.pack()
self.b = Button(root, text='Show selected list values', command=self.print_scroll_selected)
self.b.pack()
root.update()
def print_scroll_selected(self):
listboxSel = map(int, self.listbox.curselection()) # Get selections in listbox
print '=========='
for sel in listboxSel:
print self.listbox.get(sel)
print '=========='
print ''
# Create GUI
root = Tk()
win = TestFrame(root, None)
root.mainloop();
The GUI looks like this:
I click in a few items in the ListBox and hit the button.
The output I get is as expected:
==========
untz untz untz
==========
==========
yeaaaah
untz untz untz
==========
I now choose a value from the ComboBox and suddenly the selection in the ListBox is gone. Hitting the button shows that no value is selected in the ListBox:
==========
==========
My question is: why does the selection of a ComboBox item clear the selection of the ListBox? They are in no way related so this bug really puzzles me!
I finally found the answer. I will leave this question here in case someone else finds it.
The problem was not in the ComboBox but in the ListBox. This becomes clear if I use two (unrelated) ListBoxes. With two ListBoxes the selection will clear when the focus is changed.
From this question and its accepted answer I found that adding exportselection=0 to a ListBox disables the X selection mechanism where the selection is exported.
From effbot listbox about X selection mechanism: selects something in one listbox, and then selects something in another, the original selection disappears.

Categories

Resources