pythontkintercolumnspan

Tkinter - Columnspan does not bring desired result: How to get widgets to their desired place?


I am buildung a GUI for a file oranizer program. The program itself works, but I am having issues with getting my widgets into the right spot. The problem: I have too much space between my scrollbars and my textboxes, as you can see in the screenshot attached (how it looks like and what I want it too look like):enter image description here

Screenshot of my program

I am certain the problem lies with the columnspan: Every coordinate in my original grid is times 10.

My first column is column=10

My second column is column=20

My third column is column=30 ...

My first row is row=10

My second row is row=20

My third row is row=30

and so on...

Using columnspan I figured this would make it easier to squeeze other widgets in later on. I think I messed this all up somewhere, because now a widget is not going where I want it to go and I cannot figure out why. I overlooked something, but I just don't see it. I know it's a lot of code, but the only thing relevant really is the coordinates/grid system. The delete empty folder Checkbox and the textbox scrollbars. Your help is very much appreciated and I thank you very much in advance.

The link to the project on Github: https://github.com/kormuch/python_file_organizer/tree/main/file%20organizer%20v2.22

the code:

from tkinter import *
from tkinter import ttk
import tkinter.font as TkFont
import json
import os

root = Tk()
root.title('File Organiser V0.1')
root.geometry("1600x730")


#directories with relative paths
dir_source_files = r'sourcefiles'
dir_destination = r'destination'
dir_logfiles = r'logfiles'

main_frame = Frame(root)
main_frame.pack(fill=BOTH, expand=1)


# Create A Canvas
main_canvas = Canvas(main_frame)
main_canvas.pack(side=LEFT, fill=BOTH, expand=1)

# Configure The Canvas
# Add A Scrollbar To the main canvas
main_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=main_canvas.yview)
main_scrollbar.pack(side=RIGHT, fill=Y)
main_canvas.configure(yscrollcommand=main_scrollbar.set, scrollregion=main_canvas.bbox("all"))
main_canvas.bind_all('<MouseWheel>', lambda event: main_canvas.yview_scroll(int(-1*(event.delta/120)), "units"))
main_canvas.bind('<Configure>', lambda e: main_canvas.configure(scrollregion = main_canvas.bbox("all")))



# Create ANOTHER Frame INSIDE the Canvas
second_frame = Frame(main_canvas)

# Add that New frame To a Window In The Canvas
main_canvas.create_window((0,0), window=second_frame, anchor="nw")


#font for labels
helv12_bold = TkFont.Font(family="Helvetica",size=12,weight="bold")
font_textbox = TkFont.Font(family="Helvetica",size=9,weight="bold")


# configure the grid
instructions = Label(second_frame,
                     text=" 1. Place your files in the source folder\n 2. Check/Uncheck your sorting options\n 3. Press 'Run File Organizer'",
                     font=(helv12_bold),
                     bd=1, 
                     justify="left")
instructions.grid(column=1, row=5, sticky=W, pady=10, padx=10, ipadx=1, ipady= 10)





#creating a listbox with sourcefiles
label_sourcefiles = Label(second_frame, text=f"Sourcefiles:", font=helv12_bold)
label_sourcefiles.grid(column=1, columnspan=9, row=30, sticky=W, pady=(10,0), padx=10, ipadx=1, ipady= 0)
listbox_sourcefiles = Listbox(second_frame, width=60, height=30, borderwidth=3)
listbox_sourcefiles.grid(column=1, columnspan=9, row=40, rowspan=100, sticky=W, pady=0, padx=(10,0), ipadx=1, ipady= 1)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=10, columnspan=9, row=40, rowspan=100, sticky=NS)
scrollbar.config(command = listbox_sourcefiles.yview)
listbox_sourcefiles.config(font = (font_textbox), 
                             yscrollcommand=scrollbar.set)
scrollbar = Scrollbar(second_frame, orient = 'horizontal')
scrollbar.grid(column=1, columnspan=9, row=140, sticky=EW, padx=(10,0))
scrollbar.config(command = listbox_sourcefiles.xview)
listbox_sourcefiles.config(xscrollcommand=scrollbar.set)


# creating labels and Textboxes with keywords
#textbox 1
label_keywords_text_box_01 = Entry(second_frame, width=40)
label_keywords_text_box_01.grid(column=30, columnspan=9, row=30, sticky=W, pady=(10,0), padx=25, ipadx=1, ipady= 0)
label_keywords_text_box_01.config(background = "white", font = font_textbox)
display_keywords_text_box_01 = Text(second_frame, width=50, height=5, borderwidth=3)
display_keywords_text_box_01.grid(column=30, columnspan=9, row=40, sticky=W, pady=0, padx=(25,0), ipadx=1, ipady= 1)
display_keywords_text_box_01.config(background = "white", font = font_textbox)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=40, columnspan=1, row=40, sticky=NS)
scrollbar.config(command = display_keywords_text_box_01.yview)
display_keywords_text_box_01.config(yscrollcommand=scrollbar.set)

#textbox 2
label_keywords_text_box_02 = Entry(second_frame, width=40)
label_keywords_text_box_02.grid(column=30, columnspan=9, row=60, sticky=W, pady=(10,0), padx=25, ipadx=1, ipady= 0)
label_keywords_text_box_02.config(background = "white", font = font_textbox)
display_keywords_text_box_02 = Text(second_frame, width=50, height=5, borderwidth=3)
display_keywords_text_box_02.grid(column=30, columnspan=9, row=70, sticky=W, pady=0, padx=(25,0), ipadx=1, ipady= 1)
display_keywords_text_box_02.config(background = "white", font = font_textbox)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=40, row=70, sticky=NS)
scrollbar.config(command = display_keywords_text_box_02.yview)
display_keywords_text_box_02.config(yscrollcommand=scrollbar.set)

#textbox 3
label_keywords_text_box_03 = Entry(second_frame, width=40)
label_keywords_text_box_03.grid(column=30, columnspan=9, row=90, sticky=W, pady=(10,0), padx=25, ipadx=1, ipady= 0)
label_keywords_text_box_03.config(background = "white", font = font_textbox)
display_keywords_text_box_03 = Text(second_frame, width=50, height=5, borderwidth=3)
display_keywords_text_box_03.grid(column=30, columnspan=9, row=100, sticky=W, pady=0, padx=(25,0), ipadx=1, ipady= 1)
display_keywords_text_box_03.config(background = "white", font = font_textbox)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=40, row=100, sticky=NS)
scrollbar.config(command = display_keywords_text_box_03.yview)
display_keywords_text_box_03.config(yscrollcommand=scrollbar.set)





# creating dst listboxes
# listbox 1
dst_folder_name_01 = Label(second_frame, text=f"1")
dst_folder_name_01.grid(column=80, row=30, sticky=W, pady=(10,0), padx=10, ipadx=1, ipady= 0)
display_files_list_box_01 = Listbox(second_frame, width=60, height=5, borderwidth=3)
display_files_list_box_01.grid(column=80, row=40, sticky=W, pady=0, padx=(10,0), ipadx=1, ipady= 1)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=90, row=40, sticky=NS)
scrollbar.config(command = display_files_list_box_01.yview)
display_files_list_box_01.config(font = (font_textbox), 
                             yscrollcommand=scrollbar.set)
scrollbar = Scrollbar(second_frame, orient = 'horizontal')
scrollbar.grid(column=80, row=50, sticky=EW, padx=(10,0))
scrollbar.config(command = display_files_list_box_01.xview)
display_files_list_box_01.config(xscrollcommand=scrollbar.set)

# listbox 2
dst_folder_name_02 = Label(second_frame, text=f"2")
dst_folder_name_02.grid(column=80, row=60, sticky=W, pady=(10,0), padx=10, ipadx=1, ipady= 0)
display_files_list_box_02 = Listbox(second_frame, width=60, height=5, borderwidth=3)
display_files_list_box_02.grid(column=80, row=70, sticky=W, pady=0, padx=(10,0), ipadx=1, ipady= 1)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=90, row=70, sticky=NS)
scrollbar.config(command = display_files_list_box_02.yview)
display_files_list_box_02.config(font = (font_textbox), 
                             yscrollcommand=scrollbar.set)
scrollbar = Scrollbar(second_frame, orient = 'horizontal')
scrollbar.grid(column=80, row=80, sticky=EW, padx=(10,0))
scrollbar.config(command = display_files_list_box_02.xview)
display_files_list_box_02.config(xscrollcommand=scrollbar.set)

# listbox 3
dst_folder_name_03 = Label(second_frame, text=f"3")
dst_folder_name_03.grid(column=80, row=90, sticky=W, pady=(10,0), padx=10, ipadx=1, ipady= 0)
display_files_list_box_03 = Listbox(second_frame, width=60, height=5, borderwidth=3)
display_files_list_box_03.grid(column=80, row=100, sticky=W, pady=0, padx=(10,0), ipadx=1, ipady= 1)
scrollbar = Scrollbar(second_frame)
scrollbar.grid(column=90, row=100, sticky=NS)
scrollbar.config(command = display_files_list_box_03.yview)
display_files_list_box_03.config(font = (font_textbox), 
                             yscrollcommand=scrollbar.set)
scrollbar = Scrollbar(second_frame, orient = 'horizontal')
scrollbar.grid(column=80, row=110, sticky=EW, padx=(10,0))
scrollbar.config(command = display_files_list_box_03.xview)
display_files_list_box_03.config(xscrollcommand=scrollbar.set)




def save_content_textboxes():
    dict_textBox_01={label_keywords_text_box_01.get(): display_keywords_text_box_01.get('1.0','end-1c')}
    dict_textBox_02={label_keywords_text_box_02.get(): display_keywords_text_box_02.get('1.0','end-1c')}
    dict_textBox_03={label_keywords_text_box_03.get(): display_keywords_text_box_03.get('1.0','end-1c')}

    list_of_dict_textBoxes =[dict_textBox_01, dict_textBox_02, dict_textBox_03]
    json_content = json.dumps(list_of_dict_textBoxes)
    with open("saved keywords raw.json", "w") as outfile:
        outfile.write(json_content)    

    dict_textBoxes = {
        label_keywords_text_box_01.get(): display_keywords_text_box_01.get('1.0','end-1c'),
        label_keywords_text_box_02.get(): display_keywords_text_box_02.get('1.0','end-1c'),
        label_keywords_text_box_03.get(): display_keywords_text_box_03.get('1.0','end-1c'),
        }    
    with open("saved keywords raw.json") as infile:
        dicts_textBoxes_CLEAN = {}    
        data = json.load(infile)
        for entry in data:
            for key_raw, value_raw in entry.items():
                if key_raw == "":
                    break
                value_raw.replace("\\t", "").replace("\\n", "").replace("\\r", "")
                value_raw = "".join(value_raw.split("\n"))
                value_raw = "".join(value_raw.split("\t"))
                value_raw = "".join(value_raw.split("\r"))
                dicts_textBoxes_CLEAN[key_raw] = value_raw
        json_content = json.dumps(dicts_textBoxes_CLEAN, indent = 4)
        with open("saved keywords clean.json", "w") as outfile:
            outfile.write(json_content)


def display_dst_listboxes():    
    json_object_open = open("saved keywords clean.json")
    saved_keywords_clean_json = json.load(json_object_open)
    list_of_dicts_dstFolderNames_and_keywords = []
    list_seen_sourcefiles = []
    list_seen_sourcefiles_and_matching_keywords = []
    for key, value in saved_keywords_clean_json.items():
        dict_dstFolder_and_keywords = {key:value}
        list_of_dicts_dstFolderNames_and_keywords.append(dict_dstFolder_and_keywords)
    print("List of dictionaries with Foldernames and Keywords generated, here is the list:")
    print(str(list_of_dicts_dstFolderNames_and_keywords))
    print("")
    print("Now iterating through the list of dictionaries from textboxes")
    
    try:
        for dstFolderName, keywords_with_hashtags in list_of_dicts_dstFolderNames_and_keywords[0].items():
            list_unseenSrcFiles_and_therefore_to_be_moved = []
            for sourcefile in os.scandir(dir_source_files):
                if sourcefile in list_seen_sourcefiles:
                    print(f"file {sourcefile.name} was already seen")
                    continue
                else:
                    keywords_without_hashtags = keywords_with_hashtags.rstrip().split('#') #automatically creates list and removes the hashtag from every keyword
                    keywords_without_hashtags.remove('') #removes empty entries from list
                    keywords_without_hashtags
                    for keyword in keywords_without_hashtags:
                        keyword=keyword.rstrip()
                        if keyword.lower() in sourcefile.name.lower():
                            print(f"keyword '{keyword}' found in sourcefile '{sourcefile.name}'")
                            list_seen_sourcefiles.append(sourcefile)
                            list_seen_sourcefiles_and_matching_keywords.append("#" + keyword + ": " + sourcefile.name)
                            list_seen_sourcefiles=list(set(list_seen_sourcefiles))
                            list_unseenSrcFiles_and_therefore_to_be_moved.append(sourcefile)
            print(f"the following files will be moved:")
            print(list_unseenSrcFiles_and_therefore_to_be_moved)
            dst_folder_name_01.config(text=dstFolderName)
            display_files_list_box_01.delete(0,END)
            for sourcefile_to_be_moved in list_unseenSrcFiles_and_therefore_to_be_moved:
                print(f"Willl move {sourcefile_to_be_moved} to destination folder")
            for sourcefile_name_and_matching_keyword in list_seen_sourcefiles_and_matching_keywords:
                display_files_list_box_01.insert(END, sourcefile_name_and_matching_keyword)
    except IndexError:
            pass
    
    try:
        for dstFolderName, keywords_with_hashtags in list_of_dicts_dstFolderNames_and_keywords[1].items():
            list_unseenSrcFiles_and_therefore_to_be_moved = []
            for sourcefile in os.scandir(dir_source_files):
                if sourcefile in list_seen_sourcefiles:
                    print(f"file {sourcefile.name} was already seen")
                    continue
                else:
                    keywords_without_hashtags = keywords_with_hashtags.rstrip().split('#') #automatically creates list and removes the hashtag from every keyword
                    keywords_without_hashtags.remove('') #removes empty entries from list
                    keywords_without_hashtags
                    for keyword in keywords_without_hashtags:
                        keyword=keyword.rstrip()
                        if keyword.lower() in sourcefile.name.lower():
                            print(f"keyword '{keyword}' found in sourcefile '{sourcefile.name}'")
                            list_seen_sourcefiles.append(sourcefile)
                            list_seen_sourcefiles=list(set(list_seen_sourcefiles))
                            list_unseenSrcFiles_and_therefore_to_be_moved.append(sourcefile)
            print(f"the following files will be moved:")
            print(list_unseenSrcFiles_and_therefore_to_be_moved)
            display_files_list_box_02.delete(0,END)
            for sourcefile_name in list_unseenSrcFiles_and_therefore_to_be_moved:
                display_files_list_box_02.insert(END, sourcefile_name.name)
    except IndexError:
            pass
        
    try:
        for dstFolderName, keywords_with_hashtags in list_of_dicts_dstFolderNames_and_keywords[2].items():
            list_unseenSrcFiles_and_therefore_to_be_moved = []
            for sourcefile in os.scandir(dir_source_files):
                if sourcefile in list_seen_sourcefiles:
                    print(f"file {sourcefile.name} was already seen")
                    continue
                else:
                    keywords_without_hashtags = keywords_with_hashtags.rstrip().split('#') #automatically creates list and removes the hashtag from every keyword
                    keywords_without_hashtags.remove('') #removes empty entries from list
                    keywords_without_hashtags
                    for keyword in keywords_without_hashtags:
                        keyword=keyword.rstrip()
                        if keyword.lower() in sourcefile.name.lower():
                            print(f"keyword '{keyword}' found in sourcefile '{sourcefile.name}'")
                            list_seen_sourcefiles.append(sourcefile)
                            list_seen_sourcefiles=list(set(list_seen_sourcefiles))
                            list_unseenSrcFiles_and_therefore_to_be_moved.append(sourcefile)
            print(f"the following files will be moved:")
            print(list_unseenSrcFiles_and_therefore_to_be_moved)
            display_files_list_box_03.delete(0,END)
            for sourcefile_name in list_unseenSrcFiles_and_therefore_to_be_moved:
                display_files_list_box_03.insert(END, sourcefile_name.name)
    except IndexError:
            pass
        
            






# Get State functions
def get_state_extract_from_folders():
    if state_extract_boolean.get():
        print("Extract files from folders is set TRUE")
        return(True)
    if not state_extract_boolean.get():
        print("Extract files from folders is set FALSE")
        return(False)

def get_state_delete_emptyFolders():
    if state_delete_boolean.get():
        print("Delete empty folders after moving files is set TRUE")
        return(True)
    if not state_delete_boolean.get():
        print("Delete empty folders after moving files is set FALSE")
        return(False)
        
state_extract_boolean=IntVar()
Checkbutton(second_frame, text = "Extract files\n from parentfolders", variable=state_extract_boolean, onvalue=1, 
            offvalue=0, command=get_state_extract_from_folders).grid(column=30, columnspan=1, row=5, sticky=W, padx=(10,0), ipadx=10, ipady= 10)

state_delete_boolean=IntVar()
Checkbutton(second_frame, text = "Delete\nempty folders", variable=state_delete_boolean, onvalue=1, 
            offvalue=0, command=get_state_delete_emptyFolders).grid(column=35, columnspan=1, row=5, sticky=W, padx=(10,0), ipadx=10, ipady= 10)


button_check_for_keywords = Button(second_frame,
                               text = "Match Keywords",
                               bg = "lightblue",
                               font= ('Arial 12'),
                               command = lambda:[
                                   save_content_textboxes(),
                                   display_dst_listboxes(),
                                   print("button_check_for_keywords pressed")
                                   ]
                               )
button_check_for_keywords.grid(column=1, row=10, sticky=W, padx=(10,0), pady=(10,10), ipadx=10, ipady=10)


button_Run_File_Organizer = Button(second_frame,
                               text = "Run File Organizer",
                               font= ('Arial 12'),
                               command = lambda:[
                                   get_state_extract_from_folders(),
                                   get_state_delete_emptyFolders(),
                                   #create_folders_and_move_files()
                                   ]
                               )
button_Run_File_Organizer.grid(column=1, row=1, sticky=W, padx=(10,0), pady=(10,10), ipadx=10, ipady=10)


# The setup - filling the textboxes at the start
for sourcefile in os.scandir(dir_source_files):
    listbox_sourcefiles.insert(END,sourcefile.name)

try:
    json_object_open = open("saved keywords raw.json")
    json_object_data = json.load(json_object_open)
    for key_textbox_label, value_textbox_keywords in json_object_data[0].items():
        label_keywords_text_box_01.insert(END,key_textbox_label)
        display_keywords_text_box_01.insert(END, value_textbox_keywords)
    for key_textbox_label, value_textbox_keywords in json_object_data[1].items():
        label_keywords_text_box_02.insert(END,key_textbox_label)
        display_keywords_text_box_02.insert(END, value_textbox_keywords)
    for key_textbox_label, value_textbox_keywords in json_object_data[2].items():
        label_keywords_text_box_03.insert(END,key_textbox_label)
        display_keywords_text_box_03.insert(END,value_textbox_keywords)
except ValueError:
    pass



root.mainloop()

Solution

  • I found it: #textbox 6 lacked columnspan=9.