Tkinter grid method - python

I'm using Tkinter to create a GUI for my computer science coursework based on steganography. I'm using the .grid() function on the widgets in my window to lay them out, however I can't get this particular part to look how I want it to.
Here's what my GUI currently looks like: http://imgur.com/LNEZtEL
(or just the part with the error).
I want the remaining characters label to sit directly underneath the text entry box, but for some reason row 4 starts a large way down underneath the box. If I label the GUI with columns and rows anchored north west it looks like this: http://imgur.com/a/V7dTW.
If I shrink the image box on the left, it looks how I want, however I don't want the image this small: http://imgur.com/a/0Dudu.
The image box has a rowspan of 2, so what is causing the 4th row to start so low down from the text entry box? Here's roughly what I want the GUI to look like: http://imgur.com/a/ck04A.
Full code:
imageButton = Button(root, text="Add Image", command = add_image)
imageButton.grid(row = 2, columnspan = 2, sticky = W, padx = 30, pady = 20)
steg_widgets.append(imageButton)
image = Image.open("square.jpg")
image = image.resize((250,250))
photo = ImageTk.PhotoImage(image)
pictureLabel = Label(root, image = photo)
pictureLabel.image = photo
pictureLabel.grid(column = 0, row = 3, columnspan = 2, rowspan = 2, padx = 20, pady = (0, 20), sticky = NW)
steg_widgets.append(pictureLabel)
nameLabel = Label(root, text = "Brandon Edwards - OCR Computer Science Coursework 2016/2017")
nameLabel.grid(row = 0, column = 2, columnspan = 2, padx = (0, 20), pady = 10)
steg_widgets.append(nameLabel)
inputTextLabel = Label(root, text = "Enter text:")
inputTextLabel.grid(row = 2, column = 2, sticky = W)
steg_widgets.append(inputTextLabel)
startButton = Button(root, text="Go!", command = start_stega)
startButton.grid(row = 2, column = 2, sticky = E)
steg_widgets.append(startButton)
inputTextBox = Text(root, height = 10, width = 30)
inputTextBox.grid(row = 3, column = 2, sticky = NW)
steg_widgets.append(inputTextBox)
maxCharLabel = Label(root, text = "Remaining characters:")
maxCharLabel.grid(row = 4, column = 2, sticky = NW)
steg_widgets.append(maxCharLabel)
saveButton = Button(root, text="Save Image", command = save_image)
saveButton.grid(row = 2, column = 3, sticky = W)
steg_widgets.append(saveButton)

I recommend breaking your UI down into logical sections, and laying out each section separately.
For example, you clearly have two distinct sections: the image and button on the left, and the other widgets on the right. Start by creating containers for those two groups:
import Tkinter as tk
...
left_side = tk.Frame(root)
right_side = tk.Frame(root)
Since they are side-by-side, pack is the simplest way to lay them out:
left_side.pack(side="left", fill="y", expand=False)
right_side.pack(side="right", fill="both", expand=True)
Next, you can focus on just one side. You can use pack or grid. This uses grid for illustrative purposes:
image = tk.Canvas(left_side, ...)
button = tk.Button(left_side, ...)
left_side.grid_rowconfigure(0, weight=1)
left_side.grid_columnconfigure(0, weight=1)
image.grid(row=0, column=0, sticky="nw")
button.grid(row=1, column=0, sticky="n")
Finally, work on the right side. Since widgets are stacked top-to-bottom, pack is the natural choice:
l1 = tk.Label(right_side, text="Enter text:")
l2 = tk.Label(right_side, text="Remaining characters")
text = tk.Text(right_side)
l1.pack(side="top", fill="x")
text.pack(side="top", fill="both", expand=True)
l2.pack(side="top", fill="x")

Related

How can I pull a row through with grid_columnconfigure tkinter (Error)?

I have a little problem with tkinter Display:
The Black and white bar aren't pulled trough. Why not?
I declared the white bar in White Info Bar, and the Black Info Bar in Black Bar.
But they stop at the second Side Bar (Frame f4).
I want both upper bars to go trough the whole Window, but don't know how to do it.
Please give me some help.
A left a few unimportant things, like the fonts away.
Please forgive the mess.
My code:
And an Image (Display)
from tkinter import *
import tkinter.font as tkFont
import tkinter as tk
root = Tk()
root.geometry("200x100")
# White Info Bar
f2 = tk.Frame(root, background = "white", width = 1, height = 30)
f2.grid(row = 1, column = 0, sticky = "ew")
# Side Bars
f3 = tk.Frame(root, bg = "black", width = 1, height = 1)
f3.grid(row = 3, column = 0, sticky = "nsw")
root.grid_rowconfigure(3, weight = 1)
f4 = tk.Frame(root, bg = "black", width = 1, height = 1)
f4.grid(row = 3, column = 1, sticky = "nse")
root.grid_rowconfigure(3, weight = 1)
# Window
root.title("THE FRIDGER")
root.geometry("500x500")
# Black Bar
f1 = tk.Frame(root, background="black", width=1, height=45)
f1.grid(row=0, column=0, sticky="ew")
root.grid_columnconfigure(0, weight=1)
# Black Bar Content
fridge = Label(f1, text = "Fridge", fg = "white", bg = "black")
fridge.grid(column = 0, row = 0, pady = 4, padx = 4)
recipes = Label(f1, text = "Recipes", fg = "white", bg = "black")
recipes.grid(column = 1, row = 0, pady = 4, padx = 4)
# Entry
content = Label(f3, text = "Content:", fg = "white", bg = "black")
content.grid(column = 0, row = 2, sticky = W)
quest = Entry(f3, width = 36, bg = "white", fg = "black", relief = FLAT)
quest.grid(column = 0, row = 3, sticky = W)
content1 = Label(f4, text = "Content:", fg = "white", bg = "black")
content1.grid(column = 0, row = 2, sticky = W)
quest1 = Entry(f4, width = 36, bg = "white", fg = "black", relief = FLAT)
quest1.grid(column = 0, row = 3, sticky = W)
root.bind("<Return>", analyse)
root.mainloop()
You have lots of issues/misunderstandings.
assigning width and height to a Frame does nothing unless you also call propagate(0) on the Frame. You don't need to worry about doing that though cause, your app is based on weight and content.
using a Frame as a separator bar is noobish. Use a ttk.Separator instead. Make it thicker by adding ipady (if necessary ... or ipadx if vertical)
all of your stuff has terrible names that don't mean or reveal anything. To illustrate this, try to describe your code and take note of how much sense it does not make ~ "First I put the fridge and recipes in the f1, and separate it from the content with f2...". Now explain my refactor ~ "First I put 2 anonymous labels in a header Frame and follow it with a separator..". Names matter!
your sticky values are confused. You are attempting to consider the entire app with your sticky, but tkinter is just considering the cell each widget is in. For instance: sticky='nse' does not make the cell stick to the right side. It makes the widget IN THE CELL stick to the right side of the cell.
your header frame and separator are intended to span both of the columns below them, but you never told either to do that
you store references to every Label even though you will likely never change or remove any of those Labels
you double import tkinter AND use both syntax possibilities in your code. For instance: some of your stuff is tk.Label and some of it is just Label, but both of these return the same kind of Label. It's very sloppy.
rows and columns are not global. In other words, if you use row=2 IN a Frame, you don't have to start with row=3 FOR the next Frame. Similarly, if you put a Frame on row 3, you don't have to start it's children on row 4. Every Frame you create has it's own grid and it will always start with 0,0 indexes for it's children.
arguments for tkinter classes/methods can already become ridiculous in length. Doing this: var = val, var2 = val2, var3 = val3 is not helping. Also, writing the exact same arguments across multiple widgets is not efficient. Prepare your common arguments for use as kwargs.
you start your app by configuring the root, but then you configure it a little more later on, and then a little more even later on. Doing this is a recipe for problems/errors/useless code. This is evidenced by the fact that you configured the same row twice, and assigned geometry twice. If you are working on a widget (including root), finish it (as much as possible) before going on to the next widget. Sometimes this is not entirely possible (like when attaching scrollbars to things), but it is generally mostly possible.
You can glean the rest from this refactor of your code.
import tkinter as tk, tkinter.ttk as ttk
root = tk.Tk()
root.title("THE FRIDGER")
root.geometry("500x500")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(2, weight=1)
#prepared data
dflt = dict(fg="white", bg="black")
pads = dict(pady=4, padx=4)
#header frame
header = tk.Frame(root, bg="black")
header.grid(row=0, column=0, columnspan=2, sticky="nsew")
for i in range(2):
header.grid_columnconfigure(i, weight=1)
#header labels
tk.Label(header, text="Fridge", **dflt).grid(column=0, row=0, **pads)
tk.Label(header, text="Recipes", **dflt).grid(column=1, row=0, **pads)
#separator
s = ttk.Style()
s.configure('custom.TSeparator', background='white')
ttk.Separator(root, style='custom.TSeparator').grid(row=1, column=0, columnspan=2, sticky="ew")
#left side content
l_content = tk.Frame(root, bg="black")
l_content.grid(row=2, column=0, sticky="nsew")
tk.Label(l_content, text="Content:", **dflt).grid(column=0, row=0, sticky=tk.W)
l_query = tk.Entry(l_content, width=36, relief=tk.FLAT, **dflt)
l_query.grid(column=0, row=1, sticky=tk.W)
#right side content
r_content = tk.Frame(root, bg="black")
r_content.grid(row=2, column=1, sticky="nsew")
tk.Label(r_content, text="Content:", **dflt).grid(column=0, row=0, sticky=tk.W)
r_query = tk.Entry(r_content, width=36, relief=tk.FLAT, **dflt)
r_query.grid(column=0, row=1, sticky=tk.W)
#root.bind("<Return>", analyse)
root.mainloop()

How to create multiple tabs in tkinter with grid , or how to combine grid and pack

I am trying to create a GUI and so far i have organised the window as it is presented in the following figure, produced by the following python script. My question is, is it possible to create multiple tabs with the grid pack, or is it possible to combine grid and pack?
from tkinter import*
import tkinter as tk
master = tk.Tk()
#Title of GUI
master.wm_title('Title')
#Seperate GUI in sections
stepOne = tk.LabelFrame(master, text=" 1. General Heatmaps: ")
stepOne.grid(row=0, columnspan=7, sticky='WE', \
padx=10, pady=10, ipadx=10, ipady=10)
# First tab
l1 = Label(stepOne, text = "Input tilt:")
l2 = Label(stepOne, text = "Input wind speed:")
l3= Label(stepOne, text = "Input path:")
# grid method to arrange labels in respective
# rows and columns as specified
l1.grid(row = 1, column = 0, sticky = E, pady = 2)
l2.grid(row = 2, column = 0, sticky = E, pady = 2)
l3.grid(row = 3, column = 0, sticky = E, pady = 2)
entryTilt = Entry(stepOne)
entryWind = Entry(stepOne)
entryFolder_path=Entry(stepOne)
# this will arrange entry widgets
entryTilt .grid(row = 1, column = 1, pady = 2)
entryWind .grid(row = 2, column = 1, pady = 2)
entryFolder_path .grid(row = 3, column = 1, pady = 2)
b1 = Button(stepOne, text = "Run script")
b1.grid(row = 2, column = 2, sticky = E)
master.mainloop()
You can not use grid and pack inside the same Tk, TopLevel or Frame, however you can use grid and pack in different frames or top levels.
In your case if you wanted to make another frame inside master, like stepOne , you would have to use grid, however inside that new frame you would be able to use grid or pack.

tkinter gui fine tune widget layout

This is a follow-on to an answered post - I assume it's poor form to add to an answered thread even if it's related.
Overall I'm pretty happy with the layout (heavy lifting done by Bryan O. here).
Now I'm trying to fine-tune some widgets, and I can't seem to nudge things. In order to shift widgets I seem to need to layer additional frames to do so. This seems like using a shotgun to kill a fly, but what do I know?
I would like to nudge the button 'Add Edges" over so it has some space between it and the number entry widget to the left.
I would also love to have some space between the ok and cancel buttons on the bottom. Have tried adding padding via padx, and implementing layered frames whacks things up bad layout truncated central region pretty badly.I guess that geometry propagation means using padx isn't the right approach.
I cannot seem to nudge the widgets where I want them. My question specifically: using the code base I have, how do you recommend I make these fine-tune adjustments??
Thx
current gui layout
code:
from Tkinter import *
root2 = Tk()
root2.title('Model Definition')
root2.geometry('{}x{}'.format(460, 350))
# functions/commands
def get_list(event):
global seltext
"""
read the listbox selection and put the result somewhere
"""
# get selected line index
index = data_list.curselection()[0]
# get the line's text
seltext = data_list.get(index)
root2.update_idletasks()
# create all of the main containers
top_frame = Frame(root2, bg='cyan', width = 450, height=50, pady=6)
center = Frame(root2, bg='gray2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root2, bg='plum4', width = 450, height = 45, pady=3)
btm_frame2_outer = Frame(root2, bg='lavender', width = 450, height = 60, pady=3)
btm_frame2 = Frame(btm_frame2_outer, bg='green', width = 350, height = 60, pady=3)
btm_frame2_cntr = Frame(btm_frame2_outer, bg='gray', width = 50, padx=7)
# layout all of the main containers
root2.grid_rowconfigure(1, weight=1)
root2.grid_columnconfigure(0, weight=1)
top_frame.grid(row=0, sticky="ew")
center.grid(row=1, sticky="nsew")
btm_frame.grid(row = 3, sticky="ew")
btm_frame2_outer.grid(row = 4, sticky="ew")
btm_frame2.grid(row = 1, columnspan = 2, sticky="ew")
btm_frame2_cntr.grid(row = 1, column = 4, sticky='ew')
# create the widgets for the top frame
model_label = Label(top_frame, text = 'Model Dimensions')
width_label = Label(top_frame, text = 'Width:')
length_label = Label(top_frame, text = 'Length:')
entry_W = Entry(top_frame, background="pink")
entry_L = Entry(top_frame, background="orange")
# layout the widgets in the top frame
model_label.grid(row = 0, column = 0, pady=5)
width_label.grid(row = 1, column = 0, sticky = 'e')
length_label.grid(row = 1, column = 2)
entry_W.grid(row = 1, column = 1)
entry_L.grid(row = 1, column = 3)
# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)
ctr_left = Frame(center, bg='blue', width=100, height=190)
ctr_mid = Frame(center, bg='yellow', width=250, height=190, padx=3, pady=3)
ctr_right = Frame(center, width=100, height=190, padx=3, pady=3)
ctr_left.grid(row=0, column = 0, sticky="ns")
ctr_mid.grid(row=0, column = 1, sticky="nsew")
ctr_right.grid(row=0, column = 2, sticky="ns")
# decorate the center frame widgets
# left
shift_up_label = Label(ctr_left, text = 'Shift Up')
shift_down_label = Label(ctr_left, text = 'Shift Down')
cut_label = Label(ctr_left, text = 'Cut')
copy_label = Label(ctr_left, text = 'Copy')
paste_label = Label(ctr_left, text = 'Paste')
# center
data_list = Listbox(ctr_mid, bg='snow2', width='55')
yscroll = Scrollbar(ctr_mid, command=data_list.yview, orient=VERTICAL)
# right
status_label = Label(ctr_right, text = 'Status', bg = 'green', height = 11)
#####################################################################
# layout the center widgets
#####################################################################
#left
shift_up_label.grid(row = 0, column = 0, pady = '7', sticky = 'nsew')
shift_down_label.grid(row = 1, column = 0, pady = '7', sticky = 'nsew')
cut_label.grid(row = 2, column = 0, pady = '7', sticky = 'nsew')
copy_label.grid(row = 3, column = 0, pady = '7', sticky = 'nsew')
paste_label.grid(row = 4, column = 0, pady = '7', sticky = 'nsew')
# center
data_list.grid(row=0, column=0, sticky='ns')
yscroll.grid(row=0, column=0, sticky='ens')
# right
status_label.grid(row = 2, column = 0, rowspan = 4, sticky = 'nsew')
# create the bottom widgets
# layout the bottom widgets
#####################################################################
# create bottom widgets
#####################################################################
label_label = Label(btm_frame, text = 'Label:', padx = '4')
entry_label = Entry(btm_frame, background="orange")
entry_number = Entry(btm_frame, background="cyan")
number_label = Label(btm_frame, text = 'Number:', padx = '4')
add_btn = Button(btm_frame, text='Add Edges', padx = '12')
ok_btn = Button(btm_frame2_cntr, text='OK', padx = '5')
cancel_btn = Button(btm_frame2_cntr, text='Cancel', padx = '12')
#####################################################################
# layout the bottom widgets
#####################################################################
label_label.grid(row = 1, column = 1, sticky = 'ew')
entry_label.grid(row = 1, column = 2, sticky = 'w')
number_label.grid(row = 1, column = 3, sticky = 'w')
entry_number.grid(row = 1, column = 4, sticky = 'e')
add_btn.grid(row = 1, column = 6, sticky = 'e')
ok_btn.grid(row = 0, column = 3, sticky = 'ew')
cancel_btn.grid(row = 0, column = 4, sticky = 'e')
# commands/bindings
data_list.configure(yscrollcommand=yscroll.set)
data_list.bind('<ButtonRelease-1>', get_list)
root2.mainloop()
I would like to nudge the button 'Add Edges" over so it has some space
between it and the number entry widget to the left.
When you call grid on a widget, there are two options that control spacing on either side of the widget: padx and pady. You can specify a single value that applies to both sides (eg: padx=20 will add 20 pixels on both the left and right side of the widget), or you can provide a two-tuple (eg: padx=(0,20) will only add 20 pixels on the right).
For example, to "nudge" the "Add Edges" button over, just add some padding:
add_btn.grid(row = 1, column = 6, sticky = 'e', padx=(20, 0))
I would also love to have some space between the ok and cancel buttons
on the bottom.
Again, padx is the solution:
ok_btn.grid(row = 0, column = 3, sticky = 'ew', padx=(0, 8))

Deleting a Label in Python Tkinter?

I am trying to hide everything in this function:
def addHome(self):
Label(self, text = "Would you like to add to your to-do list, or generate a random item?", bg="#efefef").grid(row = 3, columnspan = 2, sticky="W")
self.txtHome = Entry(self)
self.btnAddToIt = Button(self, text = "Add To It!", bg="#efefef")
self.btnAddToIt.grid(row = 4, columnspan = 2)
self.btnAddToIt["command"] = self.addToIt
self.btnRandom = Button(self, text = "Random!", bg="#efefef")
self.btnRandom.grid(row = 5, columnspan = 2)
self.btnRandom["command"] = self.addRandom
So that I can show the things in these functions:
def addToIt(self):
#self.clearMiddle()
Label(self, text = "Add To List").grid(row = 3, columnspan = 2)
self.addInput()
self.btnProcessAdd = Button(self, text = "Add To It!", bg="#efefef")
self.btnProcessAdd.grid(row = 7, column = 0)
self.btnProcessAdd["command"] = self.processAdd
self.btnCancel = Button(self, text = "Cancel", bg="#efefef")
self.btnCancel.grid(row = 7, column = 1)
self.btnCancel["command"] = self.addHome
def addInput(self):
#adds input for add to item page
Label(self, text = "Name of Item:", bg="#efefef", width=50).grid(row=3, column=0)
self.nameOfItem = Entry(self)
self.nameOfItem.grid(row = 3, column = 1)
self.nameOfItem.insert(0, "Be Awesome")
Label(self, text = "Item Category:", bg="#efefef", width=50).grid(row = 4, column = 0, sticky="E")
self.itemCategory = Listbox(self, height = 5)
self.itemCategory.grid(row = 4, column = 1)
self.itemCategory.insert(END, "Fun", "School", "Work", "Exercise", "Other")
Label(self, text = "Other Item Details:", bg="#efefef", width=50).grid(row = 5, column = 0, sticky="E")
self.otherItemDetails = Text(self, width=22, height=3)
self.otherItemDetails.grid(row = 5, column = 1)
Label(self, text = "Due Date (mm/dd/yy):", bg="#efefef", width=50).grid(row = 6, column = 0, sticky="E")
self.dueDate = Entry(self)
self.dueDate.grid(row = 6, column = 1)
self.dueDate.insert(0, "06/19/2013")
Then vice versa when the Cancel button is hit (clearing the things in addToIt and addInput). Is there any way I can do this?
Yes, there is some way. I see you are using grid. So, to hide an object use Object.grid_forget().
Just in case, if you use pack, you can hide an object by Object.pack_forget(). Same thing works with place.
I have some idea, that might come in handy. I recommend you to have all objects you want to hide simultaneously in a single Frame, so you will just use Frame.grid_forget() instead of
Obj1.grid_forget()
Obj2.grid_forget()
Obj3.grid_forget()
.
.
.
Remember that using this will only make any object invisible, but it still exists "within" memory with all its properties.

Tkinter - Text widget shrinks when Scrollbar is added

I'm working on the GUI for a simple quiz app using Tkinter in Python 2.7.
Thus far, I have begun to set up my frame. I've put a scrollbar inside of a Text widget named results_txtbx to scroll up and down a list noting the player's performance on each question. I've been using grid since it's easier for me to manage.
from Tkinter import *
class Q_and_A:
def __init__(self, master):
frame = Frame(master)
Label(master).grid(row = 4)
results_txtbx = Text(master)
results_scrbr = Scrollbar(results_txtbx)
results_scrbr.grid(sticky = NS + E)
results_txtbx.config(width = 20, height = 4, wrap = NONE, yscrollcommand = results_scrbr.set)
results_txtbx.grid(row = 3, column = 1, padx = 12, sticky = W)
root = Tk()
root.wm_title("Question and Answer")
root.resizable(0, 0)
app = Q_and_A(root)
root.mainloop()
What happens is that when it runs, results_txtbx resizes to fit the scrollbar. Is there any way to make it keep its original size using grid?
You don't want to use a text widget as the master for a scrollbar. Like any other widget, if you pack or grid the scrollbar in the text widget, the text widget will shrink or expand to fit the scrollbar. That is the crux of your problem.
Instead, create a separate frame (which you're already doing), and use that frame as the parent for both the text widget and the scrollbars. If you want the appearance that the scrollbars are inside, set the borderwidth of the text widget to zero, and then give the containing frame a small border.
As a final usability hint, I recommend not making the window non-resizable. Your users probably know better what size of window they want than you do. Don't take that control away from your users.
Here's (roughly) how I would implement your code:
I would use import Tkinter as tk rather than from Tkinter import * since global imports are generally a bad idea.
I would make Q_and_A a subclass of tk.Frame so that it can be treated as a widget.
I would make the whole window resizable
I would separate widget creation from widget layout, so all my layout options are in one place. This makes it easier to write and maintain, IMO.
As mentioned in my answer, I would put the text and scrollbar widgets inside a frame
Here's the final result:
import Tkinter as tk
class Q_and_A(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master, borderwidth=1, relief="sunken")
self.label = tk.Label(self)
self.results_txtbx = tk.Text(self, width=20, height=4, wrap="none",
borderwidth=0, highlightthickness=0)
self.results_scrbr = tk.Scrollbar(self, orient="vertical",
command=self.results_txtbx.yview)
self.results_txtbx.configure(yscrollcommand=self.results_scrbr.set)
self.label.grid(row=1, columnspan=2)
self.results_scrbr.grid(row=0, column=1, sticky="ns")
self.results_txtbx.grid(row=0, column=0, sticky="nsew")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
root = tk.Tk()
root.wm_title("Question And Answer")
app = Q_and_A(root)
app.pack(side="top", fill="both", expand=True)
root.mainloop()
Set results_scrbr.grid(row = 3, column = 2) next to results_txtbx.grid(row = 3,column = 1, padx = 4), sticky is not needed because window is not resizable, and i lowered the padx so scrollbar is closer to text.
Also to make the results_txtbx vertically scrollable, add results_scrbr.config(command=results_txtbx.yview)
Here is a working code...
from Tkinter import *
class Q_and_A:
def __init__(self, master):
frame = Frame(master)
Label(master).grid(row = 4)
results_txtbx = Text(master)
results_scrbr = Scrollbar(master)
results_scrbr.grid(row = 3, column = 2)
results_scrbr.config(command=results_txtbx.yview)
results_txtbx.config(width = 20, height = 4,
wrap = NONE, yscrollcommand = results_scrbr.set)
results_txtbx.grid(row = 3, column = 1, padx = 4)
root = Tk()
root.wm_title("Question and Answer")
root.resizable(0, 0)
app = Q_and_A(root)
root.mainloop()
My implemented solution:
I needed to add more widgets to the app, so I bound the Scrollbar and Text widgets to another label and put that in the proper column the code (trimmed for readability) is below:
import Tkinter as tk
class Q_and_A(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.label = tk.Label(self)
#Set up menu strip
self.main_menu = tk.Menu(self)
self.file_menu = tk.Menu(self.main_menu, tearoff = 0)
self.file_menu.add_command(label = "Exit", command = self.quit)
self.main_menu.add_cascade(label = "File", menu = self.file_menu)
self.master.config(menu = self.main_menu)
#Set up labels
self.question_lbl = tk.Label(self, text = "Question #: ", padx = 12, pady = 6)
self.question_lbl.grid(row = 0, sticky = "w")
tk.Label(self, text = "Hint: ").grid(row = 1, sticky = "w", padx = 12, pady = 6)
tk.Label(self, text = "Answer: ").grid(row = 2, sticky = "w", padx = 12, pady = 6)
tk.Label(self, text = "Results: ").grid(row = 3, sticky = "nw", padx = 12, pady = 6)
tk.Label(self).grid(row = 4)
#Set up textboxes
self.question_txtbx = tk.Entry(self)
self.question_txtbx.config(width = 60)
self.question_txtbx.grid(row = 0, column = 1, padx = 12, columnspan = 3, sticky = "w")
self.help_txtbx = tk.Entry(self)
self.help_txtbx.config(width = 40)
self.help_txtbx.grid(row = 1, column = 1, columnspan = 2, padx = 12, sticky = "w")
self.answer_txtbx = tk.Entry(self)
self.answer_txtbx.config(width = 40)
self.answer_txtbx.grid(row = 2, column = 1, columnspan = 2, padx = 12, sticky = "w")
self.results_label = tk.Label(self)
self.results_txtbx = tk.Text(self.results_label, width = 10, height = 4, wrap = "none", borderwidth = 1, highlightthickness = 1)
self.results_scrbr = tk.Scrollbar(self.results_label, orient = "vertical", command = self.results_txtbx.yview)
self.results_txtbx.configure(yscrollcommand = self.results_scrbr.set)
self.label.grid(row = 1)
self.results_label.grid(row = 3, column = 1, padx = 11, sticky = "w")
self.results_scrbr.grid(row = 0, column = 1, sticky = "nse")
self.results_txtbx.grid(row = 0, column = 0, sticky = "w")
root = tk.Tk()
root.wm_title("Question and Answer")
#A note: The window is non-resizable due to project specifications.
root.resizable(0, 0)
app = Q_and_A(root)
app.pack(side = "top", fill = "both")
root.mainloop()
I'll keep storage in nested labels as a reference for myself for when I need to group things close together, unless there's some reason it should be avoided. Worked very well here. Thanks to Bryan for the advice.

Categories

Resources