-2

I am trying to create an app using the Tkinter Python library, and I created a preferences popup. I want to add checkboxes to it, and I want to do it in Frames via pack(). I want something like this:

Expected Result (IK it's Edited but Proof of Concept)

This is what I'm getting:

Actual Result (Look at Bottom of Image)

This is what I wrote:

# Import Libraries
from tkinter import *
from tkinter import ttk
from tkinter import simpledialog, messagebox
from tkinter.filedialog import asksaveasfile
from pygame import mixer as playsound
from datetime import datetime as date
from time import sleep
import pyttsx3
import json
import os

# Set Initial Window
window = Tk()
window.title("TTSApp")
window.geometry('500x580')
window.resizable(width=False,height=False)
playsound.init()

# Settings and Menu
preferences = {}
def preferencesHandler():
    if os.path.exists('preferences.pref'):
        preferences = {'AutoSave':True,'AutoSavePrompt':True,'AutoSaveAutomaticLoad':False}
        with open('preferences.pref', 'w') as pref:
            json.dump(preferences, pref)

    else:
        preferences = json.load(open('preferences.pref', 'r'))
    pref.close()
sessionOptions = {'SessionName':'Untitled','VoiceSpeed':100}

def topmenucommands_file_newsession():
    messagebox.showerror("New Session", "I haven't done this yet... you shouldn't even be able to see this...")

def topmenucommands_file_preferences():
    preferencesWin = Toplevel(window)
    preferencesWin.geometry("350x500")
    preferencesWin.title("Preferences")

    preferences_autosave = BooleanVar()
    preferences_autosaveprompt = BooleanVar()
    preferences_autosaveautomaticload = BooleanVar()
    def topmenucommands_file_preferences_changed(*args):
        with open('preferences.pref') as pref:
            preferences['AutoSave'] = preferences_autosave.get()
            preferences['AutoSavePrompt'] = preferences_autosaveprompt.get()
            preferences['AutoSaveAutomaticLoad'] = preferences_autosaveautomaticload.get()
            json.dump(preferences, pref)
            pref.close()
            
    
    Label(preferencesWin, text="Preferences", font=('helvetica', 24, 'bold')).pack()
    autosave_container = Frame(preferencesWin,width=350).pack()
    Label(autosave_container, text="Create Autosaves:", font=('helvetica', 12, 'bold')).pack(side=LEFT)
    ttk.Checkbutton(autosave_container,command=topmenucommands_file_preferences_changed,variable=preferences_autosave,onvalue=True,offvalue=False).pack(side=RIGHT)
    window.wait_window(preferencesWin)
    pref.close()

def topmenucommands_session_renamesession():
    topmenucommands_session_renamesession_value = simpledialog.askstring(title="Rename Session",prompt="New Session Name:")
    sessionOptions['SessionName'] = topmenucommands_session_renamesession_value

topmenu = Menu(window)
topmenu_file = Menu(topmenu, tearoff=0)
#topmenu_file.add_command(label="New Session")
#topmenu_file.add_command(label="Save Session")
#topmenu_file.add_command(label="Save Session As...")
topmenu_file.add_command(label="Preferences", command=topmenucommands_file_preferences)
topmenu.add_cascade(label="File", menu=topmenu_file)
topmenu_session = Menu(topmenu, tearoff=0)
topmenu_session.add_command(label="Rename Session", command=topmenucommands_session_renamesession)
topmenu.add_cascade(label="Session", menu=topmenu_session)

# Create All of the Widgets and Buttons and Kiknacks and Whatnot
    # Input Window
inputText = Text(window,height=20,width=62)
inputText.pack()

    # Label for Speed Slider
speedText = Label(window, text='Voice Speed', fg='black', font=('helvetica', 8, 'bold'))
speedText.pack()

    # Speed Slider
speed = Scale(window, from_=50, to=200, length=250, tickinterval=25, orient=HORIZONTAL, command=speedslidersavestate)
speed.set(100)
speed.pack()

    # Dropdown for Voice Selection
voice = OptionMenu(window, voiceSelection, *voiceNames.keys())
voice.pack()

    # Warning/Notice Label
warning = Label(window, text='', fg='red', font=('helvetica', 12, 'bold'))
warning.pack()

    # Container for All Preview and Save (and PreviewRaw)
buttons = Frame(window)
buttons.pack()

    # PreviewRaw Button; Huh... There's Nothing Here


    # Preview Button
preview = Button(buttons,text='Preview',height=5,width=25,command=preview)
preview.pack(side=LEFT)

    # Save Button
save = Button(buttons,text='Save to File',height=5,width=25,command=save)
save.pack(side=RIGHT)

window.config(menu=topmenu)
preferencesHandler()
window.mainloop()

Did I do something wrong or is there a better way to go about this or is this question a mess (this is my first time doing this)? Also, I clipped out all of the unnecessary content.

Edit: Added More Code

  • 1
    The code you posted doesn't include the related parts of the issue. The Label and checkbutton seems in the center of your problem. Why do you show us different code than this ? Please read [ask] and how to create a [mre] in order to get help. – Thingamabobs Oct 05 '22 at 22:54
  • 1
    If the widgets are going to the root window, then you are either not passing a parent to the widget, or the parent you are passing is `None`. None of the code you posted creates any widgets except a `Toplevel` so it's impossible for us to diagnose it. – Bryan Oakley Oct 05 '22 at 22:59
  • @BryanOakley to add an odd practice, sometimes I see `_in` as optional argument to the geometry methods, which leads to absolutely confusing code examples. – Thingamabobs Oct 05 '22 at 23:05
  • @Thingamabobs: it's `in_`. I personally don't see it as confusing, but I don't use it much in tkinter. I used to use `in` fairly often when I was a tcl/tk coder. – Bryan Oakley Oct 05 '22 at 23:52
  • @BryanOakley I do understand that there can be scenarios where the need for `in_` arises. But to have a defined master in one class and change the holding frame in a different class or script doesn't meet my fairly limited understanding of a good coding practice. It seems easier to make it wrong than right in my opinion. – Thingamabobs Oct 06 '22 at 00:04
  • 1
    @Thingamabobs: for tkinter I largely agree. For tcl, it comes in handy. Even in tkinter, however, there are times when you want to make a widget the child of a main controlling widget (for example, so all widgets can be found with `winfo_children`) but want to visually place it inside some other frame. A simple example is being able to drag and drop a widget on one of several frames. – Bryan Oakley Oct 06 '22 at 00:29
  • I’m just going to put the whole script here, is that okay? – Hipposgrumm Oct 06 '22 at 11:55
  • Look at [this answers](https://stackoverflow.com/questions/1101750/tkinter-attributeerror-nonetype-object-has-no-attribute-attribute-name) and read @BryanOakley comment again. If you still not know what is wrong, type `print(autosave_container)` and see if that leads you to a conclusion. – Thingamabobs Oct 06 '22 at 16:04
  • 1
    No, it's not OK to put your whole script. You need to create a [mcve] specifically for this question. Often, the act of creating the [mcve] will cause you to understand the problem better, and that often leads to a solution without having to ask anybody. – Bryan Oakley Oct 06 '22 at 16:16
  • I don't know that is needed and what isn't and the question is resolved. – Hipposgrumm Oct 06 '22 at 16:41

1 Answers1

1

I figured it out. Apparently, I needed to pack() the Frame separately. The answer was:

autosave_container = Frame(preferencesWin,width=350)
autosave_container.pack()

Instead of:

autosave_container = Frame(preferencesWin,width=350).pack()