Tkinter OptionMenu widget is not displaying values - python

At the moment I am working on a project using Python 3.6 Tkinter. At the moment, I am trying to make a user access rights OptionMenu for me to put either "User" or "Admin". I have tried various methods, but cannot seem to either fix it myself or to find helpful documentation online.
The problem isn't in making the OptionMenu and displaying it, nor is it that the value of the StringVar variable isn't changing. The problem is that the text inside of the OptionMenu isn't changing when any new option is selected.
class UsersDetailsEditPage(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
self.title("Edit User Details")
self.option_add("*Font", 'TkDefaultFont')
self.noteBook = ttk.Notebook(self)
for i in range(len(users)):
self.noteBook.add(self.getUserViewFrame(users[i]), text=users[i][2])
self.noteBook.pack()
self.resizable(width=False, height=False)
def getUserViewFrame(self, user):
frame = Frame(self)
frame.grid_rowconfigure(1, weight=1)
frame.grid_columnconfigure(1, weight=1)
Label(frame, text="User's name:").grid(row=0, column=0, sticky=W)
nameText = Text(frame, height=1, width=20)
nameText.insert("1.0", user[2])
nameText.edit_reset()
nameText.grid(row=0, column=1, sticky=E)
Label(frame, text="Username:").grid(row=1, column=0, sticky=W)
usernameText = Text(frame, height=1, width=20)
usernameText.insert("1.0", user[0])
usernameText.edit_reset()
usernameText.grid(row=1, column=1, sticky=E)
Label(frame, text="Password:").grid(row=2, column=0, sticky=W)
passwordText = Text(frame, height=1, width=20)
passwordText.insert("1.0", user[1])
passwordText.edit_reset()
passwordText.grid(row=2, column=1, sticky=E)
# the constructor syntax is:
# OptionMenu(master, variable, *values)
Label(frame, text="User Access:").grid(row=3, column=0, sticky=W)
self.options = StringVar()
self.options.set("User")
self.userAccessDrop = ttk.OptionMenu(frame, self.options, "User", *("User", "Admin"))
self.userAccessDrop.config(width=10)
self.userAccessDrop.grid(row=3, column=1, sticky=E)
return frame
This is the output of the code
I have all the library imports that are needed (I think):
from tkinter import *
from tkinter import messagebox
import tkinter.ttk as ttk
import csv
import os
If anyone can work out how to make this work it would be much appreciated.
Thanks

I tried your code and it works for me. I can only guess that this is a garbage collection problem. Try assigning the option menu to frame rather than self, so that it doesn't get overwritten.
frame.options = StringVar()
frame.options.set("User")
frame.userAccessDrop = ttk.OptionMenu(frame, frame.options, "User", *("User", "Admin"))
frame.userAccessDrop.config(width=10)
frame.userAccessDrop.grid(row=3, column=1, sticky=E)
You really should rewrite this so that you subclass a Frame to make the user instances.
Edit: for example:
import tkinter as tk
from tkinter import ttk
class UserFrame(tk.Frame):
def __init__(self, master=None, data=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
data = data[2], data[0], data[1] # rearrange data
labels = ("User's name:", "Username:", "Password:")
for row, (label, value) in enumerate(zip(labels, data)):
lbl = tk.Label(self, text=label)
lbl.grid(row=row, column=0, sticky=tk.W)
ent = tk.Entry(self)
ent.insert(0, value)
ent.grid(row=row, column=1, sticky=tk.E)
lbl = tk.Label(self, text="User Access:")
lbl.grid(row=3, column=0, sticky=tk.W)
self.options = tk.StringVar(self, "User")
self.userAccessDrop = ttk.OptionMenu(self,
self.options,
"User", # starting value
"User", "Admin", # options
)
self.userAccessDrop.config(width=10)
self.userAccessDrop.grid(row=len(labels), column=1, sticky=tk.E)
class UsersDetailsEditPage(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("Edit User Details")
self.option_add("*Font", 'TkDefaultFont')
self.noteBook = ttk.Notebook(self)
for user in users:
self.noteBook.add(UserFrame(self, user), text=user[2])
self.noteBook.pack()
self.resizable(width=False, height=False)
It's really not functionally any different from what you have, just neater code (which actually makes a huge difference in coding time). Note I also got rid of the evil wildcard import and condensed your code a bit. Remember, if you are copying and pasting code blocks you are doing the computer's job. I also moved you to Entry widgets, which are a single line Text widget. Also, try to avoid the "convenience" initializing and laying out a widget on the same line. It's ugly and it leads to bugs.
I used 'self' in for the "self.options" and "self.userAccessDrop", but since we subclassed the Frame, "self" now refers to the Frame instance. In other words it's the same as my above block where I used "frame.options".

Related

Using Tkinter filedialog within a frame and accessing the output globally

I am building my first GUI using tkinter and have come up against some problems. To make the code more modular, I am using an object-oriented approach, as seen in the code below. The basic idea is that I have defined classes for the DataFrame, MetaFrame and SaveFrame, which are all instantiated within the OptionsFrame, which then is instantiated within the MainWindow.
import tkinter as tk
from tkinter import ttk
class DataFrame(ttk.Frame):
def __init__(self, main, *args, **kwargs):
super().__init__(main, *args, **kwargs)
# data frame elements
self.data_label = ttk.Label(self, text="Add Data:")
self.labelled_tweets_label = ttk.Label(self, text="Labelled-Tweets: ")
self.labelled_tweets_button = ttk.Button(self, text="Browse")
self.places_label = ttk.Label(self, text="Places: ")
self.places_button = ttk.Button(self, text="Browse")
self.plots_label = ttk.Label(self, text="Plots Path: ")
self.plots_button = ttk.Button(self, text="Browse")
self.submit_button = ttk.Button(self, text="Submit")
# data frame layout
self.data_label.grid(row=0, column=0, columnspan=2, pady=10)
self.labelled_tweets_label.grid(row=1, column=0)
self.labelled_tweets_button.grid(row=1, column=1)
self.places_label.grid(row=2, column=0)
self.places_button.grid(row=2, column=1)
self.plots_label.grid(row=3, column=0)
self.plots_button.grid(row=3, column=1)
self.submit_button.grid(row=4, column=0, columnspan=2, pady=10)
class MetaFrame(ttk.Frame):
...
class SaveFrame(ttk.Frame):
...
class OptionsFrame(ttk.Frame):
def __init__(self, main, *args, **kwargs):
super().__init__(main, *args, **kwargs)
# options frame components
self.data_frame = DataFrame(self)
self.horiz1 = ttk.Separator(self, orient="horizontal")
self.meta_frame = MetaFrame(self)
self.horiz2 = ttk.Separator(self, orient="horizontal")
self.save_frame = SaveFrame(self)
# options frame layout
self.data_frame.grid(row=0, column=0)
self.horiz1.grid(row=1, column=0, sticky="ew", pady=30)
self.meta_frame.grid(row=2, column=0)
self.horiz2.grid(row=3, column=0, sticky="ew", pady=30)
self.save_frame.grid(row=4, column=0, sticky="s")
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry("800x600")
self.resizable(False, False)
# configuration
self.columnconfigure(index=0, weight=1)
self.columnconfigure(index=1, weight=2)
# main frames
self.options_frame = OptionsFrame(self, width=400, height=600, borderwidth=1)
self.vert = ttk.Separator(self, orient="vertical")
# main layout
self.options_frame.grid(row=0, column=0)
self.vert.grid(row=0, column=1, sticky="ns")
def main():
root = MainWindow()
root.mainloop()
The layout can be seen in the following image.
This is the basic layout I want within the OptionsFrame. My confusion lies with creating filedialog methods for the three file browsing buttons within the DataFrame. I understand how to use the filedialog class to return the path to a given file, but then this value is restricted to be in the scope of the DataFrame.
I have a back-end that is already developed which requires these file paths, so ideally I would like to access them from the main() function. How is this possible?
Thanks

Tkinter DateEntry not allowing selection

I am using a Tkinter DateEntry field to get a "from" and "to" date for a SQL query. I recetnly redid my project, but copied a lot of code over. In my old project, the date entry works fine, however in my new project whenever I try to select a day for any DateEntry fields, it autofills and does not allow me to use the drop-down window.
This link is an example of how it looks in my working project:
https://www.plus2net.com/python/tkinter-DateEntry.php
This is the working code:
date_joined_to = DateEntry(container, selectmode="day", year=datetime.now().year,
month=datetime.now().month, day=datetime.now().day,
date_pattern="yyyy-mm-dd", foreground="black",
headersforeground="black", selectforeground="black",
width=10)
date_joined_to.grid(row=4, column=1, sticky="W")
date_joined_to.delete(0, "end")
date_joined_to._top_cal.overrideredirect(False)
This is my code in my new project where the problem occurs:
test_date_to = DateEntry(self.centersearch, selectmode="day", year=datetime.now().year,
month=datetime.now().month,
day=datetime.now().day, date_pattern="yyyy-mm-dd",
foreground="black", headersforeground="black",
selectforeground="black", width=10)
test_date_to.grid(row=9, column=1, sticky="E")
test_date_to.delete(0, "end")
test_date_to._top_cal.overrideredirect(False)
I tried removing all keyword arguments to see if those caused it, but the issue persisted.
From my searches it does appear that many people have encountered this before.
I can't answer as I've seen the same problem and got here looking for an answer. Here is code that shows it. In my case the version that works looks the same but is not in separate classes but instead in one large script file. But for real world problems that's poor coding practice. When I moved it out into classes It no longer works.
This version works
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkcalendar import DateEntry
from datetime import datetime
current_day = datetime.now().day
current_month = datetime.now().month
current_year = datetime.now().year
root = tk.Tk()
root.title("Date Demo Works")
# root.minsize(750, 400)
root.geometry("1024x768+0+0")
root.grid()
demo_edit_screen = tk.Toplevel(root)
demo_edit_screen.geometry("1024x768+0+0")
demo_edit_screen.title("Demo Working")
demo_edit_screen.iconify()
demo_edit_screen.withdraw()
def DoNothing():
tk.messagebox.showinfo(message='This is an info box that Does Nothing')
print("testing do nothing dialog")
class DemoEdit():
def __init__(self):
leftsidebar = tk.Frame(demo_edit_screen, borderwidth=2, relief="raised", width=40)
leftsidebar.grid(row=0, column=0, rowspan=11, sticky=("NSEW"))
gohome = ttk.Button(leftsidebar, text="Home", command=DoNothing())
gohome.grid(row=0, column=0)
centersearch = tk.Frame(demo_edit_screen, width=850)
centersearch.grid(row=0, column=1, sticky="W")
test_date_label = tk.Label(centersearch, text='Test Date Range', anchor="e")
test_date_label.grid(row=7, column=0, columnspan=2, padx=4)
test_date_from_label = tk.Label(centersearch, text='From', anchor="w")
test_date_from_label.grid(row=8, column=0, padx=4)
test_date_to_label = tk.Label(centersearch, text='To', anchor="w")
test_date_to_label.grid(row=8, column=1, padx=4)
test_date_from = DateEntry(centersearch, selectmode="day"
, year=datetime.now().year, month=datetime.now().month, day=datetime.now().day
, date_pattern="yyyy-mm-dd"
, foreground="black", headersforeground="black", selectforeground="black", width=10)
test_date_from.grid(row=9, column=0, sticky="W")
test_date_from.delete(0, "end")
test_date_from._top_cal.overrideredirect(False)
test_date_to = DateEntry(centersearch, selectmode="day"
, year=datetime.now().year, month=datetime.now().month, day=datetime.now().day
, date_pattern="yyyy-mm-dd"
, foreground="black", headersforeground="black", selectforeground="black", width=10)
test_date_to.grid(row=9, column=1, sticky="E")
test_date_to.delete(0, "end")
test_date_to._top_cal.overrideredirect(False)
def show_demoedit(self):
root.withdraw()
demo_edit_screen.update()
demo_edit_screen.deiconify()
leftsidebar = tk.Frame(root, borderwidth=2, relief="raised", height=768)
leftsidebar.grid(row=0, column=0, rowspan=8, sticky=("NSEW"))
show_screen = ttk.Button(leftsidebar, text="Show Calendar Screen", command=DemoEdit.show_demoedit(root))
show_screen.grid(row=3, column=0)
demo_edit = DemoEdit()
root.mainloop()
This version does not
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkcalendar import DateEntry
from datetime import datetime
def DoNothing():
tk.messagebox.showinfo(message='This is an info box that Does Nothing')
print("testing do nothing dialog")
class TopScreen(tk.Frame):
def __init__(self, parent, controller, label_text="sample", *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.controller = controller
self.parent = parent
# Create the choose action sidebar that will go to specific screens
self.leftsidebar = tk.Frame(self, borderwidth=2, relief="raised", height=768)
self.leftsidebar.grid(row=0, column=0, rowspan=8, sticky=("NSEW"))
self.home_label = tk.Label(self.leftsidebar, text=label_text)
self.home_label.grid(row=0, column=0)
class CSVReportScreen(TopScreen):
def __init__(self, parent, controller):
super().__init__(parent, controller, label_text="CSV Report")
self.controller = controller
self.parent = parent
create_csv_files_button = ttk.Button(self.leftsidebar, text="Create .CSV Files", command=DoNothing())
create_csv_files_button.grid(row=3, column=0, sticky="NSEW")
# Top center search section
self.centersearch = tk.Frame(self, width=850)
self.centersearch.grid(row=0, column=1, sticky="W")
test_date_label = tk.Label(self.centersearch, text='Test Date Range', anchor="e")
test_date_label.grid(row=7, column=0, columnspan=2, padx=4)
test_date_from_label = tk.Label(self.centersearch, text='From', anchor="w")
test_date_from_label.grid(row=8, column=0, padx=4)
test_date_to_label = tk.Label(self.centersearch, text='To', anchor="w")
test_date_to_label.grid(row=8, column=1, padx=4)
test_date_from = DateEntry(self.centersearch, selectmode="day"
, year=datetime.now().year, month=datetime.now().month, day=datetime.now().day
, date_pattern="yyyy-mm-dd"
, foreground="black", headersforeground="black", selectforeground="black", width=10)
test_date_from.grid(row=9, column=0, sticky="W")
test_date_from.delete(0, "end")
test_date_from._top_cal.overrideredirect(False)
test_date_to = DateEntry(self.centersearch, selectmode="day"
, year=datetime.now().year, month=datetime.now().month, day=datetime.now().day
, date_pattern="yyyy-mm-dd"
, foreground="black", headersforeground="black", selectforeground="black", width=10)
test_date_to.grid(row=9, column=1, sticky="E")
test_date_to.delete(0, "end")
test_date_to._top_cal.overrideredirect(False)
class TestApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = dict()
# Add each separate screen here. The name is the class for that screen
trakker_classes = (CSVReportScreen,TopScreen)
for F in trakker_classes:
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("CSVReportScreen")
def show_frame(self, page_name):
# Show a frame for the given page name
frame = self.frames[page_name]
frame.tkraise()
if __name__ == "__main__":
app = TestApp()
app.mainloop()
DateEntry is a part of tkcalendar. So I have the same question.
OK, I've just spent all day trying all sorts of permutations:
I'm running on MacOS Catalina 10.15.7 (19H1824)
I am using PyCharm 2021.03.3 (Professional Edition)
Build #Py-213.7172.26, built on March 15, 2022
I am using virtual environments and have tried the following versions with these results:
Python 3.8.3
tkinter 8.6.8
Cannot get the DateEntry dropdown calendar to appear. Doesn't matter whether the _top_cal.overrideredirect(False) is set or not same behavior.
Python version 3.8.10 (v3.8.10:3d8993a744, May 3 2021, 08:55:58)
tkinter 8.6.8
DateEntry in the documentation demo code works when the _top_cal.overrideredirect(False) is used.
My DateEntry is not working from within a class.
Python 3.9.8 Universal Version
tkinter 8.6.11
DateEntry dropdown requires double clicks to display. Doesn't matter whether the _top_cal.overrideredirect(False) is set or not same behavior. Same in both documentation demo code and my code.
Python 3.9.12 Intel
tkinter 8.6.8
Cannot get the DateEntry dropdown calendar to appear. Doesn't matter whether the _top_cal.overrideredirect(False) is set or not same behavior. Same in both documentation demo code and my code.
Python 3.10.4 Universal Version
tkinter 8.6.121
DateEntry dropdown requires double clicks to display. Doesn't matter whether the _top_cal.overrideredirect(False) is set or not same behavior. Same in both documentation demo code and my code.
A couple of things I learned along the way.
The Intel Python installers all seem to include tkinter 8.6.8
The Universal installers seem to grab whatever was the latest for that version of Python.
I was not able to test all the options because for lots of the intervening ones there are no installers. I was not able to install from the source code.
I don't know where to go from here.

Is it possible to resize an input box (entry) when clicked with tkinter?

Reading through other stackoverflow questions, and other sources I do see that bind can be used to call a function. Currently I'm working on a program that will communicate with a database (most likely mongodb), and so far I've set up a frame that has 2 inputs per row (key-value). I haven't completely decided whether I want one row per document, or one row per field. Right now, if a user has a lot to type then it wouldn't be ideal for them because you can't see everything you write. So what I was thinking is that, if the user clicks on the entry widget, then the box would become bigger and show them everything they have written. My current line of thinking is that maybe I could create another frame for it and somehow pass onto the information to that?
This is what it currently looks like
Then what I'd ideally want it to look like
Here's the code if interested how I made it (Images are from the "CreatePage" section):
from tkinter import *
import tkinter as tk
class Database_Project(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
stack_frame_container = tk.Frame(self)
stack_frame_container.grid_columnconfigure(0, weight=1)
stack_frame_container.grid_rowconfigure(0, weight=1)
stack_frame_container.pack(side="top", fill="both", expand=True)
self.frameslist = {}
for frame in (MainPage, CreatePage):
frame_occurrence = frame.__name__
active_frame = frame(parent=stack_frame_container, controller=self)
self.frameslist[frame_occurrence] = active_frame
active_frame.grid(row=0, column=0, sticky="snew")
self.current_frame("MainPage")
def current_frame(self, frame_occurrence):
active_frame = self.frameslist[frame_occurrence]
active_frame.tkraise()
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label_create = tk.Label(self, text="Create and insert data").grid(row=0, column=0, padx=50, pady=(50,0))
create_button = tk.Button(self, text="CREATE", command=lambda: controller.current_frame("CreatePage")).grid(row=1, column=0)
label_read = tk.Label(self, text="Query over data").grid(row=0, column=1, padx=50, pady=(50,0))
read_button = tk.Button(self, text="READ").grid(row=1, column=1)
label_update = tk.Label(self, text="Modify existing data").grid(row=2, column=0, padx=50, pady=(50,0))
update_button = tk.Button(self, text="UPDATE").grid(row=3, column=0, pady=(0,50))
label_delete = tk.Label(self, text="Remove data").grid(row=2, column=1, padx=50, pady=(50,0))
delete_button = tk.Button(self, text="DELETE").grid(row=3, column=1, pady=(0,50))
class CreatePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.inputlist = []
self.newinputlist = []
labels = [tk.Label(self, text="Enter unique field"), tk.Label(self, text="Enter corresponding the value/s")]
self.inputlist.append(labels[:])
for toplabels in range(1):
self.inputlist[toplabels][0].grid(row=toplabels, column=0, padx=10, pady=5)
self.inputlist[toplabels][1].grid(row=toplabels, column=1, padx=10, pady=5)
for entries in range(2):
for entrynum in range(0, 1):
print("column:", entries)
print("row", entrynum)
self.newinputlist.append(tk.Entry(self, borderwidth=5))
for x in range(len(self.newinputlist)):
self.newinputlist[x].grid(row=1, column=x, padx=10, pady=5)
self.inputlist.append(self.newinputlist[:])
button_input_1 = [tk.Button(self, text="ADD FIELD/VALUE", command=self.add_insert), tk.Button(self, text="BACK", command=lambda: controller.current_frame("MainPage"))]
self.inputlist.append(button_input_1[:])
button_input_2 = [tk.Button(self, text="IMPORT FILE"), tk.Button(self, text="SUBMIT DATA")]
self.inputlist.append(button_input_2[:])
for button in range(len(self.inputlist) - 2, len(self.inputlist)):
self.inputlist[button][0].grid(row=button, column=0, padx=10, pady=5)
self.inputlist[button][1].grid(row=button, column=1, padx=10, pady=5)
def add_insert(self):
add_input = [tk.Entry(self, borderwidth=5), tk.Entry(self, borderwidth=5)]
self.inputlist.insert(-2, add_input)
self.newinputlist.append(add_input)
for widget in self.children.values():
widget.grid_forget()
for index, widgets in enumerate(self.inputlist):
widget_one = widgets[0]
widget_two = widgets[1]
print(str(index), widget_one, widget_two)
widget_one.grid(row=index, column=0, padx=10, pady=5)
widget_two.grid(row=index, column=1, padx=10)
if __name__ == "__main__":
NoSQL_Project = Database_Project()
NoSQL_Project.title("NoSQL Database Project")
NoSQL_Project.mainloop()
It's pointless to resize an Entry widget since they can only ever hold a single line. I'll give an example using the Text widget instead, though the technique works with any widget.
There's really no trick, just bind to <FocusIn> and <FocusOut>. In the following example I've created two Text widgets that have this resize behavior:
import tkinter as tk
def resizer(event):
if event.widget == event.widget.focus_get():
event.widget.configure(height=8)
else:
event.widget.configure(height=1)
root = tk.Tk()
root.geometry("400x200")
text1 = tk.Text(root, height=1, width=20)
text2 = tk.Text(root, height=1, width=20)
text1.pack(side="left")
text2.pack(side="right")
for widget in (text1, text2):
widget.bind("<FocusIn>", resizer)
widget.bind("<FocusOut>", resizer)
root.mainloop()
The actual behavior depends on how you've laid out your widget. This could cause widgets to jump around or the window resize, but every app will be different so it's hard to give a solution that works everywhere.

How to add only a bottom border to input fields in tkinter?

I am making a login software and I want the input fields to have only the bottom border like we have in CSS. Is there any way to do this in tkinter?
There are a few ways to do this. Arguably the simplest is to turn off the border, and then use place to add a separator. You can wrap that up in a class so that you can use it just like a normal entry.
Here's a simple example:
import tkinter as tk
from tkinter import ttk
class CustomEntry(tk.Entry):
def __init__(self, *args, **kwargs):
kwargs["borderwidth"] = 0
super().__init__(*args, **kwargs)
separator = ttk.Separator(orient="horizontal")
separator.place(in_=self, x=0, rely=1.0, height=2, relwidth=1.0)
root = tk.Tk()
style = ttk.Style()
print(style.layout("TEntry"))
print(style.layout("TSeparator"))
for row, field in enumerate(("First", "Last")):
label = tk.Label(root, text=field)
entry = CustomEntry(root, width=20, highlightthickness=0)
label.grid(row=row, column=0, sticky="e", padx=10, pady=4)
entry.grid(row=row, column=1, sticky="ew", padx=10, pady=4)
root.mainloop()

StringVar().set() Not Adjusting StringVar

I'm a beginner learning Python and mucking around with the tkinter GUI stuff. I'm trying to make a very basic beginner project that allows a user to type something into a text box and click a button, whereupon that input is added to a label in another part of the window.
However, I'm running into an issue where the StringVar that I'm using as an output isn't being updated by the .set() command.
def __init__(self):
self.window = Tk()
self.window.title("Terminal Writer 9000!")
self.terminalString = StringVar()
self.terminalString.set("This is an example message.")
self.allcontent = ttk.Frame(self.window)
self.allcontent.grid(row=0, column=0, sticky="nwse")
self.mainframe = ttk.Frame(self.allcontent)
self.mainframe.grid(row=0, column=0, sticky = "nwse", columnspan=4, rowspan=5)
self.terminal = ttk.Label(self.mainframe, textvariable=self.terminalString, padding=10, relief="sunken")
self.terminal.grid(row=0, column=0, rowspan=5, columnspan=2, sticky="nwse")
# GUI setup for Buttons and Entry box omitted...
play = TerminalWriterApp()
play.window.mainloop()
However, the area used by the terminal Label is blank, even though it should display "This is an example message." While troubleshooting, I made this, which is basically a complete copy/paste of the functional elements of my original code:
from tkinter import *
from tkinter import ttk
window = Tk()
strvar = StringVar()
strvar.set("Test 2")
allcontent = ttk.Frame(window)
allcontent.grid(row=0, column=0, sticky="nwse")
mainframe = ttk.Frame(allcontent)
mainframe.grid(row=0, column=0, sticky="nwse", columnspan=4, rowspan=5)
text = Label(mainframe, text="Test 1")
text.grid(row=0, column=0, sticky="nwse")
text2 = Label(mainframe, textvariable=strvar)
text2.grid(row=1, column=0, sticky="nwse")
window.mainloop()
This code functions as intended, displaying a window with "Test 1" and "Test 2" on separate lines.
Does anyone know why the set() method wouldn't work in this context? (Also, feel free to get mad at my horrible code - I need to learn good habits somehow!)
For some reasons, the label appears when the app takes focus (when you click on it); maybe it is because of the stack nested frames, IDK.
You could use focus_force to constrain the OS to give focus to your app immediately.
from tkinter import *
from tkinter import ttk
class TerminalWriterApp:
def __init__(self):
self.window = Tk()
self.window.title("Terminal Writer 9000!")
self.terminalString = StringVar()
self.terminalString.set("This is an example message.")
self.allcontent = ttk.Frame(self.window)
self.allcontent.grid(row=0, column=0, sticky="nwse")
self.mainframe = ttk.Frame(self.allcontent)
self.mainframe.grid(row=0, column=0, sticky = "nwse", columnspan=4, rowspan=5)
self.terminal = ttk.Label(self.mainframe, textvariable=self.terminalString, padding=10, relief="sunken")
self.terminal.grid(row=0, column=0, rowspan=5, columnspan=2, sticky="nwse")
self.terminal.focus_force()
play = TerminalWriterApp()
play.window.mainloop()

Categories