How to create multiple checkbox in loop using tkinter - python-3.x

I am New to use Tkinter.I want to create multiple checkbox from loop.I refer Tkinter checkboxes created in loop but i don't understand it.
I want to display all files as a checkbox located in a directory.
Help me and tell me what i need to change ?
Code:
from tkinter import filedialog,Checkbutton
import tkinter,os
window = tkinter.Tk()
def browse():
filez = filedialog.askdirectory(parent=window,title='Choose a file')#I choose a directory
ent1.insert(20,filez)#insert the path of directory to text box
dirs = os.listdir(filez)#gives all files of direcory
for file in dirs:
print(file)#Getting all files
var = tkinter.IntVar()
c = tkinter.Checkbutton(window,text=file,variable=var)#Create files to checkox
c.place(x=0,y=100)
window.title("First Gui")
window.geometry("400x400")
window.wm_iconbitmap("path of icon")
lbl = tkinter.Label(window,text="path")
lbl.place(x=0,y=60)
ent1 = tkinter.Entry(window)
ent1.place(x=80,y=60)
btn1 = tkinter.Button(window,text="Set Path",command=browse)
btn1.place(x=210,y=57)
window.mainloop()
After click on button set path i want to to display all files of directory as a checkbox using browse function

I see three problems
you use c.place(x=0,y=100) for all Checkbuttons so you can see only last one - other are hidden behind last one.
every Checkbutton need own IntVar which you can keep on list or in dictionary.
when you select new path then you have to remove previous Checkbuttons so you have to remember them on list or in dictionary.
Example shows how you could use pack() instead of place() to easily put all Checkbuttons. It also show how to uses dictionary to keep IntVars and check which was selected, and how to use list to keep Checkbuttons and remove them later from window.
import tkinter
import tkinter.filedialog
import os
# --- functions ---
def browse():
filez = tkinter.filedialog.askdirectory(parent=window, title='Choose a file')
ent1.insert(20, filez)
dirs = os.listdir(filez)
# remove previous IntVars
intvar_dict.clear()
# remove previous Checkboxes
for cb in checkbutton_list:
cb.destroy()
checkbutton_list.clear()
for filename in dirs:
# create IntVar for filename and keep in dictionary
intvar_dict[filename] = tkinter.IntVar()
# create Checkbutton for filename and keep on list
c = tkinter.Checkbutton(window, text=filename, variable=intvar_dict[filename])
c.pack()
checkbutton_list.append(c)
def test():
for key, value in intvar_dict.items():
if value.get() > 0:
print('selected:', key)
# --- main ---
# to keep all IntVars for all filenames
intvar_dict = {}
# to keep all Checkbuttons for all filenames
checkbutton_list = []
window = tkinter.Tk()
lbl = tkinter.Label(window, text="Path")
lbl.pack()
ent1 = tkinter.Entry(window)
ent1.pack()
btn1 = tkinter.Button(window, text="Select Path", command=browse)
btn1.pack()
btn1 = tkinter.Button(window, text="Test Checkboxes", command=test)
btn1.pack()
window.mainloop()

Related

Python3, difficulty with classes and tkinter

First of all to kick it off,
I'm not great at programming,
I have difficulty with understanding most basics,
I always try doing my uterly best to solve things like this myself.
I'm trying to create a simple gui that makes json files. Everything works fine. Fine in the sense that I'm able to create the files.
Now I wanted to get my code cleaned up and to the next level. I have added tabs to the tkinter screen and that is where the troubles starts. Because when I'm, on a differend tab, the function doesn't get the current selected items, so I added buttons to save that list and then move to different tab.
I have a function(Save_List_t), which looks at the selected items from the listbox(a_lsb1) and saves them to a list(choice_list_t). This function runs when I press button(a_button).
After doing that I got a problem, I don't want to use "global" but I need the list in a other function(Mitre_Gen_Techs) to generate the files. This function runs when I press a button on the third tab.(c.button1)
To tackel this problem, I saw a post where someone uses a class to fix it. However even after reading to the documentation about classes I still don't truely get it.
Now I'm stuck and get the error. Which I don't find that strange, it makes sense to me why it gives the error but what am I doing wrong or how do I solve this issue.
The error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\thans\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
TypeError: Save_List_t() missing 1 required positional argument: 'self'
The code I wrote:
from tkinter import *
from attackcti import attack_client
from mitretemplategen import *
from tkinter import ttk
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mitre ATT&Ck
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ac = attack_client()
groups = ac.get_groups()
groups = ac.remove_revoked(groups)
techs = ac.get_enterprise_techniques()
techs = ac.remove_revoked(techs)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Tkinter screen setup
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
root = Tk()
root.title("Mitre Att&ck")
root.minsize(900, 800)
root.wm_iconbitmap('')
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Functions / classes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class Screen(object):
def __init__(self):
self.choice_list_t = []
self.choice_list_g = []
def Save_List_t(self):
for item in a_lsb2.curselection():
self.choice_list_t.append(a_lsb2.get(item))
print(self.choice_list_t)
def Save_List_g(self):
choice_list_g = []
for item in b_lsb1.curselection():
self.choice_list_g.append(b_lsb1.get(item))
print(self.choice_list_g)
def Mitre_Gen_Techs(self):
# Gen the json file
# mitre_gen_techs(self.choice_list_t, techs)
#testing class
print(self.choice_list_t)
def Mitre_Gen_Groups(self):
# Gen the json file
# mitre_gen_groups(self.choice_list_g, groups)
#testing class
print(self.choice_list_g)
def main():
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# First Tkinter tab
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
rows = 0
while rows < 50:
root.rowconfigure(rows, weight=1)
root.columnconfigure(rows, weight=1)
rows += 1
# Notebook creating tabs
nb = ttk.Notebook(root)
nb.grid(row=1, column=0, columnspan=50, rowspan=50, sticky='NESW')
# Create the differend tabs on the notebook
tab_one = Frame(nb)
nb.add(tab_one, text='APG')
tab_two = Frame(nb)
nb.add(tab_two, text='Actors')
tab_gen = Frame(nb)
nb.add(tab_gen, text='test')
# =-=- First Tab -=-=
# List box 1
a_lsb1 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
# List with techs
a_lsb2 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
for t in techs:
a_lsb2.insert(END, t['name'])
# Save list, to later use in Screen.Mitre_Gen_Techs
a_button = Button(tab_one, text="Save selected", command=Screen.Save_List_t)
# =-=- Second Tab -=-=
# List with TA's
b_lsb1 = Listbox(tab_two, height=30, width=30, selectmode=MULTIPLE)
for g in groups:
b_lsb1.insert(END, g['name'])
# Save list, to later use in Screen.Mitre_Gen_Groups
b_button = Button(tab_two, text="Save selected", command=Screen.Save_List_g)
# =-=- Third tab -=-=
c_button = Button(tab_gen, text="Print group json", command=Screen.Mitre_Gen_Groups)
c_button1 = Button(tab_gen, text="Print techs json", command=Screen.Mitre_Gen_Techs)
# Placing the items on the grid
a_lsb1.grid(row=1, column=1)
a_lsb2.grid(row=1, column=2)
b_lsb1.grid(row=1, column=1)
a_button.grid(row=2, column=1)
b_button.grid(row=2, column=1)
c_button.grid(row=2, column=1)
c_button1.grid(row=2, column=2)
root.mainloop()
# If main file then run: main()
if __name__ == "__main__":
main()
The application:
Image
I found someone who explained what was wrong.
Credits to Scriptman ( ^ , ^ ) /
simply adding:
sc = Screen()
And changing:
Button(tab_apg, text="Save selected", command=sc.Save_List_t)
Resolved the issue.

Image not showing up when file updated/changed Tkinter

I have an image that I have placed, which works perfectly fine, but when I want to change it to a different image it doesn't change. The cards images have the same names as the ones in the list, i.e. 2C = 2 of Clubs.
root=Toplevel()
root.state('zoomed')
root.config(bg='#1b800b')
root.title('PokerChamp')
all_cards = ['2C','3C','4C','5C','6C','7C','8C','9C','10C','JC','QC','KC','AC','2D','3D','4D','5D','6D','7D','8D','9D','10D','JD','QD','KD','AD','2S','3S','4S','5S','6S','7S','8S','9S','10S','JS','QS','KS','AS','2H','3H','4H','5H','6H','7H','8H','9H','10H','JH','QH','KH','AH']
play_card1 = PhotoImage(file='files/cards/red_back.png')
card6 = Label(root, image=play_card1, bd=0)
card6.place_forget()
select_cards()
def select_cards():
card6.place(relx=0.45, rely=0.75)
player_card1 = random.choice(all_cards)
play_card1 = PhotoImage(file = f'files/cards/{player_card1}.png')
root.update()
When you load the first image you give it the name play_card1 in the global namespace.
The function select_cards() is a local namespace and when you assign a value to player_card1 it is a local name is not associated with the label and which will be garbage collected when the function ends.
The usual way to do this is to assign the new image to the label and then to save a reference to the image in the label object so the reference to tha image will not be lost as the function exits. See my example (I used slightly different images than you...):
from tkinter import *
import random
root = Toplevel()
root.config(bg='#1b800b')
root.title('PokerChamp')
all_cards = ['chapman','cleese','gilliam','idle','jones','palin']
play_card1 = PhotoImage(file='images/beer.png')
card6 = Label(root, image=play_card1, bd=0)
card6.place_forget()
def select_cards():
card6.place(relx=0.5, rely=0.5, anchor='center')
player_card1 = random.choice(all_cards)
play_card1 = PhotoImage(file = f'images/{player_card1}.png')
card6.config(image=play_card1) # Assign new image to label card6
card6.image = play_card1 # Keep a reference to image
root.update()
select_cards()
Also I would advise against using the name root for a Toplevel() window as root is usually used for the root window.

Returning variable from a function

I have a main function page and i linked the next page with a button
when i click the button it executes a function in the main page but.
i want to use the result from the function in another file as a variable
########main.py
class Main(object):
def __init__(self,master):
self.master = master
mainFrame = Frame(self.master)
mainFrame.pack()
topFrame= Frame(mainFrame,width=1050,height =50, bg="#f8f8f8",padx =20, relief =SUNKEN,
borderwidth=2)
topFrame.pack(side=TOP,fill = X)
self.btnselfolder= Button(topFrame, text="Select Folder", compound=LEFT,
font="arial 12 bold", command=self.selectFolder)
self.btnselfolder.pack(side=LEFT)
def selectFolder(self):
print("folder")
return folder
################# selectfolder page
class Page2(Toplevel):
def __init__(self):
Toplevel.__init__(self)
self.geometry("450x300")
self.title("page2")
self.resizable(False,False)
self.topFrame = Frame(self, width=350,height=150, bg="white")
self.topFrame.pack(fill=X)
# call the function from main.py and it will give me the same output folder
y = selectFolder()
Since the selectFolder method is not static, you'll have to access it using instance. Like this:
main = Main()
folder = main.selectFolder()
folder should hold the value you returned.
I'm afraid when i just copied and pasted your code into my IDLE directly, it immediately presented me with naming errors. Not even a Tkinter window popped up. So to clear things up I would go about making a Tkinter window like the following. Also bare in mind I don't really use or know how to integrate classes with Tkinter itself, but I quickly learned how to by your mistakes :)
# import tkinter from the libraries
from tkinter import *
import os
# the Zen of Python
#import this
# declare the tkinter window variable
# scroll to bottom to see mainloop
root = Tk()
########main.py
# folder is not defined as a variable
# but i recommend looking into
# using system of which i imported
# for you. You can research how to
# use it yourself for good practice
# i am sorry if i am wrong about this
# but my impression is you're trying to
# use the OS to select a folder from a
# directory. So the 'selectFolder' function
# should not be declared as a method within the class
# therefore rendering the Page2 class useless.
def selectFolder():
print("folder")
# return will result in an error
# because it has not been declared as a variable
# return folder
class Main():
# all instances instantiated (created)
# within the __init__ method
# must be declared in the parentheses
def __init__(self, topFrame, btnselfolder):
# instantiate the topFrame object
self.topFrame = topFrame
# instantiate the btnselfolder
self.btnselfolder = btnselfolder
# pro tip - when having multiple
# arguments within an object, then
# to keep it clean and easy to read
# space out the code like i have for
# you. You should also read the "Zen of Python"
# which is at the top as 'import this'
# however i have commented it out for you
topFrame = Frame(root,
width=1050,
height = 50,
bg = "#f8f8f8",
padx = 20,
relief = SUNKEN,
borderwidth=2)
topFrame.pack(side=TOP, fill = X)
btnselfolder = Button(topFrame,
text = "Select Folder",
compound=LEFT,
font = "arial 12 bold",
command = selectFolder).pack()
# mainloop() method will keep the window open
# so that it doesn't appear for a millisecond
# and dissapear :)
root.mainloop()
# I hope this has been a big help
# Thanks for posting this question! :-)
# Enjoy your day, good luck and be safe in Lockdown!
Thanks again for the question, I thoroughly enjoyed solving it or at least giving you some guidence! :)

Defining a list of files using Tkinter to use for analysis. Having a hard time accessing the variables globally. (Python 3)

I hope all is well. Fairly new to programming, so please bear with me.
I am working on a GUI using tkinter that would prompt me to select a set of files that would be used to perform some analysis. I wish to store these files in a list that I can reference later. There are two required files, a DBC file and an ASC file. What I am having issues with is being able to reference the file(s) outside of the functions I have defined. I have tried defining it as a global variable (which I have read is not advisable as it can lead to problems down the road). I get an error saying dbfiles or ascfiles is not defined when just trying to print. Below is what I have written so far:
import tkinter as tk
from tkinter import messagebox
from tkinter import filedialog
root = tk.Tk()
root.geometry("500x700")
def dbbutton():
dbfiles = filedialog.askopenfilenames(parent=root, title='Select .DBC File(s)')
dbfiles = root.tk.splitlist(dbfiles)
for file1 in dbfiles:
L1.insert(tk.END, file1)
return dbfiles
def ascbutton():
ascfiles = filedialog.askopenfilenames(parent=root, title='Select .ASC File(s)')
ascfiles = root.tk.splitlist(ascfiles)
for file2 in ascfiles:
L2.insert(tk.END, file2)
return ascfiles
b1 = tk.Button (root, text= "Select Database File(s)", command = dbbutton)
b1.pack()
L1 = tk.Listbox(root, selectmode = "multiple", height = 10, width = 80)
L1.pack()
b2 = tk.Button (root, text = "Select ASC File(s)", command = ascbutton)
b2.pack()
L2 = tk.Listbox(root, selectmode = "multiple", height = 10, width = 80 )
L2.pack()
root.mainloop()
What is the most effective way for me to reference these files outside of the functions?
Create the file list outside the function and then append to it inside the function:
ascfile_list = [] # Create list to hold filenames
def ascbutton():
filename_list = filedialog.askopenfilenames(parent=root, title='Select .ASC File(s)')
for filename in filename_list:
L2.insert(tk.END, filename)
ascfile_list.append(filename) # Append filename to list

Combining browse method with os.listdir file sorting script

I'm a novice python programmer and i found two pieces of code that combined would basically do what i want from the program i am building. But i have a problem to get them working together. browse_button is a directory browse method that gives me the directory that i would want to do my other method search the sort_button. It would sort files into and if they do not exist it makes the folders. Then it puts the files with specified extensions into those folders.
I have tried to make this work for a few days and i feels stuck. I dont get the second part of the program working with the browse part. Now i get this error when i press the sort button:
"
names = os.listdir(path)
FileNotFoundError: [Errno 2] No such file or directory: ''
"
But i feel dont know why it doesnt have the directory since i can view the directory on the screen before i press the sort button. Can someone explain the problem for me please? <3
""" Filesortingprogramm """
import os
import shutil
from tkinter import filedialog
from tkinter import *
def browse_button():
# Allow user to select a directory and store it in global var
# called folder_path
global folder_path
filename = filedialog.askdirectory()
folder_path.set(filename)
print(filename)
root = Tk()
folder_path = StringVar()
label0 = Label(root, text="Filesorter")
label0.config(font=("Courier", 25))
label0.grid(row=0 ,column=2)
label1 = Label(root, text="open folder to be sorted")
label1.config(font=("Courier", 10))
label1.grid(row=1, column=2)
lbl1 = Label(master=root,textvariable=folder_path)
lbl1.grid(row=2, column=1)
button2 = Button(text="Browse", command=browse_button)
button2.grid(row=3, column=3)
def sort_button()
path = folder_path
path = str()
folder_name = ['text','kalkyl']
names = os.listdir(path)
for x in range(0,2):
if not os.path.exists(path+folder_name[x]):
os.makedirs(path+folder_name[x])
for files in names:
if ".odt" in files and not os.path.exists(path + 'text/' + files):
shutil.move(path+files, path+'text/'+files)
if ".ods" in files and not os.path.exists(path + 'kalkyl/' + files):
shutil.move(path+files, path+'kalkyl/'+files)
button3 = Button(text="Sort", command=sort_button)
button3.grid(row=4, column=3)
mainloop()

Resources