Frame in Tkinter Popup Putting Content into Main Window instead of Popup - python

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

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()

Related

Python - Tkinter: Scrollbar not aligning properly

I am working on a python tkinter desktop applicaiton. I need a scrollbar on the right side of the frame with a vertical orientation. I am trying to display a ttk scrollbar but it does not seem to display properly. My table disappears and the height of the scrollbar is not correct either. Also, if possible, the scrollbar needs to appear only when the TreeView overflows and when it doesnt overflow, then the scrollbar should not be displayed.
import tkinter
from turtle import color, width
import win32com.client
import sys
import subprocess
import time
from tkinter import*
from tkinter import ttk
from tkinter import messagebox
class TestingGui():
def __init__(self):
print("testing")
def registerUser(self):
userName = "tim"
userAge = "36"
userGender = "male"
userPosition = "softeware engineer"
userInfo = [userName.upper(),userAge,userGender,userPosition]
tree.column(0,anchor='center')
tree.column(1,anchor='center')
tree.column(2,anchor='center')
tree.column(3,anchor='center')
tree.insert('',0,values=userInfo)
if __name__ == '__main__':
window = Tk()
window.title('Dashboard')
window.geometry('925x500+300+200')
window.configure(bg="#fff")
window.resizable(False,False)
################### Frame (Top)[start] #####################################
frameTop = Frame(window,width=860,height=60,bg='white')
frameTop.place(x=40,y=40)
uploadExcelBtn = Button(frameTop,width=19,pady=7,text='Upload Excel',bg='#787c82',fg='white',cursor='hand2',border=0).place(x=715,y=13)
excelFileInputField = Entry(frameTop,width=58,fg='black',border=1,bg='white',font=('Microsoft YaHei UI Light',15,'bold'))
excelFileInputField.place(x=8,y=14)
################### Frame (Top)[end] #######################################
################### Table (Center)[start] #####################################
columns = ('name','age','gender','position')
frameCenter = Frame(window,width=860,height=315,bg='#f0f0f1')
frameCenter.place(x=40,y=110)
treeScroll = ttk.Scrollbar(frameCenter,orient="vertical")
treeScroll.pack(side=RIGHT,fill="y")
tree = ttk.Treeview(frameCenter,height=13,columns=columns,show="headings",selectmode='browse',yscrollcommand=treeScroll.set)
tree.heading('name',text='Name')
tree.heading('age',text='Age')
tree.heading('gender',text='Gender')
tree.heading('position',text='Position')
tree.place(x=30,y=10)
treeScroll.config(command=tree.yview)
################### Table (Center)[end] #######################################
################### Frame (Bottom)[start] #####################################
frameBottom = Frame(window,width=860,height=60,bg='white')
frameBottom.place(x=40,y=430)
addUserBtn = Button(frameBottom,width=19,pady=7,text='Add User',bg='#57a1f8',fg='white',cursor='hand2',border=0,command= lambda : TestingGui().registerUser()).place(x=30,y=15)
################### Frame (Bottom)[end] #######################################
mainloop()
The use of place can be tricky that's why you should use it only if other geometrymanager fail to achieve what you want. The benefit of the other two geometrymanagers by tkinter is that they calculate cells or parcels for you that you can use and easily recognize by just look at your layout.
I took the time to change your script and placed comments next to changed lines, that should explain what and why I think those changes are necessary.
#import only what you need and avoid wildcard imports due naming conflicts
import tkinter as tk #as tk as short for tkinter
from tkinter import ttk
class TestingGui():
def __init__(self):
print("testing")
def registerUser(self):
userName = "tim"
userAge = "36"
userGender = "male"
userPosition = "softeware engineer"
userInfo = [userName.upper(),userAge,userGender,userPosition]
tree.column(0,anchor='center')
tree.column(1,anchor='center')
tree.column(2,anchor='center')
tree.column(3,anchor='center')
tree.insert('',0,values=userInfo)
if __name__ == '__main__':
window = tk.Tk()
## bonus: leading tk. symbols you are using tk
window.title('Dashboard')
window.geometry('925x500+300+200')
window.configure(bg="#fff")
window.resizable(False,False)
#Window Content
topframe = tk.Frame(window,width=860,height=60,bg='white')
centerframe = tk.Frame(window,width=860,height=315,bg='#f0f0f1')
bottomframe = tk.Frame(window,width=860,height=60,bg='white')
topframe.pack(side=tk.TOP, padx=(40,0),pady=(40,0),fill=tk.X)
centerframe.pack(side = tk.TOP, fill= tk.BOTH, padx=(40,0))
bottomframe.pack(side=tk.BOTTOM, padx=(40,0), fill= tk.X)
## fill = stretch in master
## padx/y are offsets like x/y in place but using their parcels
## keeping content together helps for an overview of content
#frameTop Content
input_field = tk.Entry(
topframe, width=58, fg='black', border=1, bg='white',
font=('Microsoft YaHei UI Light',15,'bold'))
input_field.pack(side=tk.LEFT)
upload_button = tk.Button(
topframe, width=19, pady=7, text='Upload Excel',
bg='#787c82',fg='white',cursor='hand2',border=0)
upload_button.pack(side=tk.TOP)
## seperate the constructor from the geometry method to keep a reference
## split lines for readability compare PEP-8 Style Guide
## dont use camelcase variable names compare PEP-8 Style Guide
## the order of packing matters in this geometry manager
#centerframe Content
treeScroll = ttk.Scrollbar(centerframe,orient="vertical")
treeScroll.pack(side=tk.RIGHT,fill="y")
#tk.RIGHT = tkinter constant
columns = ('name','age','gender','position')
tree = ttk.Treeview(
centerframe, height=13, columns=columns,
show="headings",selectmode='browse',yscrollcommand=treeScroll.set)
tree.heading('name',text='Name')
tree.heading('age',text='Age')
tree.heading('gender',text='Gender')
tree.heading('position',text='Position')
tree.pack(side=tk.TOP, padx=(30,0),pady=10)
treeScroll.config(command=tree.yview)
#bottomframe Content
add_user_button = tk.Button(
bottomframe, width=19, pady=7,text='Add User',
bg='#57a1f8',fg='white',cursor='hand2', border=0)
#command= lambda : TestingGui().registerUser())#DONT DO THIS!
## Only use lambda if needed
## It makes little to no sense to initiate a class in a lambda expression
add_user_button.pack(padx=(30,0),side=tk.LEFT)
#start mainloop
tk.mainloop()#indention correcture

How can i open a .py file using if and open

import tkinter
from tkinter import ttk
from tkinter import *
window = tkinter.Tk()
window.title("wasans")
window.geometry('640x400')
window.resizable(False, False)
textbook = ['국어','영어','social']
textbookselecter = ttk.Combobox(window, text="교과서 선택", values=textbook)
textbookselecter.grid(column=0, row=0)
textbookselecter.place(x=140, y=200)
textbookselecter.set("목록 선택")
textbooksuntack = ttk.Label(window, width=11, borderwidth=2, background="#8182b8")
textbooksuntack.grid(column=0, row=0)
textbooksuntack.place(x=170, y=170)
textbooksuntack.anchor = CENTER
naeyong = textbookselecter.get()
if naeyong == "social":
open("../social.py", "w")
window.mainloop()
How can I open a py file using if statement and open?
Also, please give your overall review of the code.
I am not good at English, so there may be awkward sentences using a translator. Please understand.
You basically need to check every time the ttk.Combobox is changed to check if 'social' is generated.
ttk.Combobox raises a "<<ComboboxSelected>>" virtual event when selected.
import tkinter
from tkinter import ttk
from tkinter import *
window = tkinter.Tk()
window.title("wasans")
window.geometry('640x400')
window.resizable(False, False)
def callback(eventObject):
if textbookselecter.get() == "social":
print("Opening File...")
#file=open("...../social.py","r+")
textbook = ['국어','영어','social']
textbookselecter = ttk.Combobox(window, text="교과서 선택", values=textbook)
textbookselecter.grid(column=0, row=0)
textbookselecter.place(x=140, y=200)
textbookselecter.set("목록 선택")
textbooksuntack = ttk.Label(window, width=11, borderwidth=2, background="#8182b8")
textbooksuntack.grid(column=0, row=0)
textbooksuntack.place(x=170, y=170)
textbooksuntack.anchor = CENTER
textbookselecter.bind("<<ComboboxSelected>>",callback)
window.mainloop()

How to fix to the left a button in tkinter with columnspan

Description
What I'm trying to do is an app with a navbar on top that depending on which one is shows different things on the body of the app (below the navbar). I'm using the grid so I'm iterating through a list and adding a button to the body of the app and they have columnspan but they position in the middle of the columnspan
This is how it looks right now.
Desired Layout
This is a little sketch of the layout (the right bar below the navbar is a scrollbar which isn't implemented yet because I don't know yet how to do it)
Code
import modules.configManager as configManager
import tkinter as tk
from tkinter import messagebox
import tkinter.font as font
from os.path import dirname, abspath
from PIL import Image, ImageTk
imgDirectory = dirname(dirname(abspath(__file__))) + '\img'
logo = imgDirectory + '\logo2.jpg'
root = tk.Tk()
def linkMenu():
links = configManager.readConfig()['linksList']
i = 0
for link in links:
i = i+1
linkB = tk.Button(root,text=link['link'],font=font.Font(font='Helvetica',size=8),width=30,relief='flat')
linkB.grid(column=0,row=i,columnspan=4)
def navbar():
buttonWidth = 18
buttonHeight = 1
myfont = font.Font(font='Helvetica',size=10,weight="bold")
homeButton = tk.Button(root, text="Home",height=buttonHeight,width=buttonWidth,font=myfont)
homeButton.grid(column=0,row=0)
linkButton = tk.Button(root, text="Links",width=buttonWidth,font=myfont,command=linkMenu)
linkButton.grid(column=1,row=0)
groupsButton = tk.Button(root, text="Groups",width=buttonWidth,font=myfont)
groupsButton.grid(column=2,row=0)
resetButton = tk.Button(root, text="Reset",width=buttonWidth,font=myfont)
resetButton.grid(column=3,row=0)
exitButton = tk.Button(root,text="Exit",width=buttonWidth,font=myfont,command=exit)
exitButton.grid(column=4,row=0)
def interface():
navbar()
root.title("LinkManager")
root.geometry("1040x500")
root.mainloop()
Thanks in advance and if it isn't clear tell me please :D

How to set up a top level element to show the download progress?

So I want to send multiple get requests and let a tkinter label to show the progress, but I noticed the toplevel only shows up after all the requests have been done.
How can I fix this?
import tkinter as tk
import requests
window = tk.Tk()
def download():
global window
top = tk.Toplevel(window)
progress_text = tk.StringVar()
tk.Label(top, textvariable=progress_text, font=('Arial', 12))
url_list = [' http://www.yahoo.com', ' http://www.google.com', ' http://www.amazon.com']
[requests.get(c) for c in url_list]
for i in range(len(url_list)):
progress_text.set('Done: {}'.format(i/len(url_list)))
requests.get(url_list[i])
print('done')
tk.Button(window, text='download', command=download).pack()
window.mainloop()

Multiple windows open at once in python

I've searched and found a few things on parent windows in python but that is not what I was looking for. I am trying make a simple program that opens a window and another window after that when the previous one is closed. I was also trying to implement some kind of loop or sleep time to destroy the window by default if the user does not. This is what I have (I'm new please don't laugh)
from tkinter import *
import time
root = Tk()
i = 0
if i < 1:
root.title("title")
logo = PhotoImage(file="burger.gif")
w1 = Label(root, image=logo).pack()
time.sleep(3)
root.destroy()
i = i + 1
if i == 1:
root.title("title")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(root, image=photoTwo).pack()
time.sleep(3)
root.destroy()
i = i + 1
mainloop.()
Perhaps you're looking for something like this:
from tkinter import *
import time
def openNewWindow():
firstWindow.destroy()
secondWindow = Tk()
secondWindow.title("Second Window")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(secondWindow, image=photoTwo).pack()
secondWindow.mainloop()
firstWindow = Tk()
firstWindow.title("First Window")
logo = PhotoImage(file="burger.gif")
w1 = Label(firstWindow, image=logo).pack()
closeBttn = Button(firstWindow, text="Close!", command=openNewWindow)
closeBttn.pack()
firstWindow.mainloop()
This creates a button in the first window, which the user clicks. This then calls the openNewWindow function, which destroys that window, and opens the second window. I'm not sure there's a way to do this using the window exit button.
To get create a more sustainable window creation, use this:
from tkinter import *
import time
def openThirdWindow(previouswindow):
previouswindow.destroy()
thirdWindow = Tk()
thirdWindow.title("Third Window")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(thirdWindow, image=photoTwo).pack()
thirdWindow.mainloop()
def openSecondWindow(previouswindow):
previouswindow.destroy()
secondWindow = Tk()
secondWindow.title("Second Window")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(secondWindow, image=photoTwo).pack()
closeBttn = Button(secondWindow, text="Close!", command= lambda: openThirdWindow(secondWindow))
closeBttn.pack()
secondWindow.mainloop()
def openFirstWindow():
firstWindow = Tk()
firstWindow.title("First Window")
logo = PhotoImage(file="burger.gif")
w1 = Label(firstWindow, image=logo).pack()
closeBttn = Button(firstWindow, text="Close!", command= lambda: openSecondWindow(firstWindow))
closeBttn.pack()
firstWindow.mainloop()
openFirstWindow()
This places the opening of each window in a seperate function, and passes the name of the window through the button presses into the next function. Another method would be setting the window names as global, but this is messy.
The function "lambda:" calls the function, in tkinter you must type this if you want to pass something through a command.
We initiate the whole process first first called "openFirstWindow()"

Categories