Python-Tkinter Place button on left of frame - python

How do I place the QUIT button in below code to the extreme right of the Frame?
I tried several things like:
padx
and
self.pack(side="top", anchor="e")
but after trying some 15 times both buttons are coming close to each other. Maybe Some help from anyone would be really appreciated. I need one button on extreme right and other on extreme left
import tkinter as tk
from tkinter.ttk import *
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
self.master.title("Log Parser")
def createWidgets(self):
self.Run_Main = tk.Button(self)
self.Run_Main["text"] = "Browse.."
# self.Run_Main["fg"] = "blue"
self.Run_Main["command"] = self.Sayhello
self.Run_Main.pack(side='left')
self.Label = tk.Label(self)
self.Label["text"] = 'Processing...'
self.progressbar = Progressbar(mode="indeterminate", maximum=20)
self.QUIT = tk.Button(self)
self.QUIT["text"] = "Quit!"
self.QUIT["command"] = self.quit
self.QUIT.pack(anchor='e')
self.pack(side="top", anchor="w")
def Sayhello(self):
print("Hello")
# scroll text inside application frame
class scrollTxtArea:
def __init__(self, root):
frame = tk.Frame(root)
frame.pack()
self.textPad(frame)
return
def textPad(self, frame):
# add a frame and put a text area into it
textPad = tk.Frame(frame)
self.text = tk.Text(textPad, height=18, width=60)
self.text.config()
# add a vertical scroll bar to the text area
scroll = tk.Scrollbar(textPad)
self.text.configure(yscrollcommand=scroll.set,background="black", foreground="green")
# pack everything
self.text.pack(side=tk.LEFT, pady=2)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
textPad.pack(side=tk.TOP)
return
root = tk.Tk()
root.resizable(width=False, height=False)
root.option_add('*font', ('verdana', 9, 'bold'))
app = Application(master=root)
scrollFrame = scrollTxtArea(root)
app.mainloop()

You have several problems here.
First, you're using the wrong geometry manager. The pack geometry manager, as the name implies, packs the widgets as close together as possible. That's not what you want. The grid geometry manager lets you put the widgets into a table-like layout with rows and columns. If you put the Browse button into the first column and the Quit button into the last column, you'll be a step closer.
Second, your Application window contains three child widgets and you're only putting two of them into a geometry manager. How that is going to mess you up I don't even want to think about. So I put the label into column 1, the Quit button into column 2, and the Browse button into column 0. The Quit button I gave a "sticky" value of "e" so it will be attached to the east (right) side of its allocated space.
Third, all the geometry managers try to compact the widgets as much as possible unless you specifically tell it to do otherwise. I told the grid manager to expand column 2 so that the extra space gets assigned to the cell that holds the Quit button.
Fourth, you need to tell the pack manager to expand the top widget so that it spans the entire window. The directive for that is fill="x".
Fifth, you have a redundant call to the pack manager at the end of your createWidgets function.
import tkinter as tk
from tkinter.ttk import *
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack(fill="x")
self.createWidgets()
self.master.title("Log Parser")
def createWidgets(self):
self.Run_Main = tk.Button(self)
self.Run_Main["text"] = "Browse.."
# self.Run_Main["fg"] = "blue"
self.Run_Main["command"] = self.Sayhello
self.Label = tk.Label(self)
self.Label["text"] = 'Processing...'
self.progressbar = Progressbar(mode="indeterminate", maximum=20)
self.QUIT = tk.Button(self)
self.QUIT["text"] = "Quit!"
self.QUIT["command"] = self.quit
self.Label.grid(row=0, column=1)
self.Run_Main.grid(row=0, column=0, sticky="w")
self.QUIT.grid(row=0, column=2, sticky="e")
self.columnconfigure(2, weight=1)
def Sayhello(self):
print("Hello")
# scroll text inside application frame
class scrollTxtArea:
def __init__(self, root):
frame = tk.Frame(root)
frame.pack()
self.textPad(frame)
return
def textPad(self, frame):
# add a frame and put a text area into it
textPad = tk.Frame(frame)
self.text = tk.Text(textPad, height=18, width=60)
self.text.config()
# add a vertical scroll bar to the text area
scroll = tk.Scrollbar(textPad)
self.text.configure(yscrollcommand=scroll.set,background="black", foreground="green")
# pack everything
self.text.pack(side=tk.LEFT, pady=2)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
textPad.pack(side=tk.TOP)
return
root = tk.Tk()
root.resizable(width=False, height=False)
root.option_add('*font', ('verdana', 9, 'bold'))
app = Application(master=root)
scrollFrame = scrollTxtArea(root)
app.mainloop()

These link, link helped. The other option would be to use tkinter's grid manager, it will be more intuitive and keep you more organized in the future.
import tkinter as tk
from tkinter.ttk import *
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
self.master.title("Log Parser")
def createWidgets(self):
self.Run_Main = tk.Button(self)
self.Run_Main["text"] = "Browse.."
# self.Run_Main["fg"] = "blue"
self.Run_Main["command"] = self.Sayhello
self.Run_Main.pack(side='left')
self.Label = tk.Label(self)
self.Label["text"] = 'Processing...'
self.Label.pack(side='left')
self.progressbar = Progressbar(mode="indeterminate", maximum=20)
self.QUIT = tk.Button(self)
self.QUIT["text"] = "Quit!"
self.QUIT["command"] = self.quit
self.QUIT.pack(side='right')
self.pack(side="top", fill=tk.BOTH) # changes here
def Sayhello(self):
print("Hello")
# scroll text inside application frame
class scrollTxtArea:
def __init__(self, root):
frame = tk.Frame(root)
frame.pack()
self.textPad(frame)
return
def textPad(self, frame):
# add a frame and put a text area into it
textPad = tk.Frame(frame)
self.text = tk.Text(textPad, height=18, width=60)
self.text.config()
# add a vertical scroll bar to the text area
scroll = tk.Scrollbar(textPad)
self.text.configure(yscrollcommand=scroll.set,background="black", foreground="green")
# pack everything
self.text.pack(side=tk.LEFT, pady=2)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
textPad.pack(side=tk.TOP)
return
root = tk.Tk()
root.resizable(width=False, height=False)
root.option_add('*font', ('verdana', 9, 'bold'))
app = Application(master=root)
scrollFrame = scrollTxtArea(root)
app.mainloop()

There are two simple fixes you can make in order to get the behavior you want.
First, you need to pack Application so that it fills the window:
class Application(...):
def __init__(...):
...
self.pack(fill="x")
Next, simply pack the quick button on the right side of the window:
self.QUIT.pack(side="right", anchor='e')
Even though the above is all you need to do in this specific example, there are additional things you can do to make your job much easier.
I would recommend creating a frame specifically for the buttons. You can pack it at the top. Then, put the buttons inside this frame, and pack them either on the left or right. You'll get the same results, but you'll find it easier to add additional buttons later.
I also find that it makes the code much easier to read, write, maintain, and visualize when you separate widget creation from widget layout.
class Application(...):
...
def createWidgets(self):
toolbar = tk.Frame(self)
toolbar.pack(side="top", fill="x")
self.Run_Main = tk.Button(toolbar)
self.Label = tk.Label(toolbar)
self.QUIT = tk.Button(toolbar)
...
self.Run_Main.pack(side="left")
self.Label.pack(side="left", fill="x")
self.QUIT.pack(side="right")
...

Related

Why my tkinter back button does not function?

I made 2 pages in my tkinter. The main page have one button that will bring the user to Classifier_UI page. In the Classifier_UI page, I made a back button that will bring the user back to the main page. The back button works just fine if I run only the Classifier_UI.py. It did bring me back to the main page. However, if I run from the main_page.py, then click on the button that bring me to the Classifier_UI page, and click on the back button, the windows will automatically closed and did not bring me back to the main page. Why is this happening and how can I fix this?
Below is the button code that I made in my main page:
from tkinter import *
class Test:
def __init__(self, tk):
fm = Frame(tk)
self.l1 = Label(tk, text="Welcome", font=("Helvetica", 38, 'bold'), bg='LightGoldenrod2', fg='gray24').place(relx=0.25, rely=0.15)
self.b2 = Button(tk, bg='LightGoldenrod4', text="Classifier 1", font=("Helvetica", '10', 'bold'), foreground="white", width = 24, height = 3, command=self.change).pack(side=LEFT, expand=YES, padx=110, pady=300)
fm.pack(fill=BOTH, expand=YES)
def change(self):
tk.destroy()
import Classifier_UI
img_path = StringVar()
canvas = tk.Canvas(root, height = '700', width= '750', bg='#292828')
canvas.pack(fill=BOTH)
tk = Tk()
tk['bg']='LightGoldenrod2'
tk.toolbar = Frame(tk, bg="white")
width= tk.winfo_screenwidth()
height= tk.winfo_screenheight()
tk.geometry("%dx%d" % (width, height))
tt = Test(tk)
tk.mainloop()
This is code of the button in my second page:
def change():
root.destroy()
import main_page
root = tk.Tk()
root.title("Image Classifier")
browse = tk.Button(text="Back", bg='white', font='courier 10', command=change)
browse.place(relx = 0.75 ,rely = 0.85, relwidth = 0.12, relheight=0.05)
root.mainloop()
The problem is that tk.destroy() and root.destroy() close the window, because you're calling the destroy() method of the window, not the frame one. Try to do self.destroy() when your class is referring to a frame, this will destroy just the frame and not the entire window, but, when the frame is destroyed, you have no other way to make it reapper but to create another instance. Also, you shouldn't import modules inside functions unless you want to make that import optional, put all your imports at the start of the script if it's not the case.
More importantly, in both files you make a root window and destroy it, which is not necessary if you just want to change the displayed frame. I suggest you to put two frame inside the window, one on top of the other, and switch back and forth between the frames when the button is pressed.
Here is a simple example of code were a button switch between two frames (note that I've put the button straight inside the window and not inside a frame to make it indipendent from the change, but you can put one for each frame if you want):
import tkinter as tk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame_on_top = 1
self.switch_frame_button = tk.Button(self, text='switch', command=self.switch_frame)
self.switch_frame_button.grid(row=0, column=0)
self.container = tk.Frame(self) # This is the position where we will put the frames.
self.container.grid(row=1, column=0)
self.frames = {}
counter = 2
# Now let's make our frames.
# Starting from the second, so that the first frame will be put on top (last in first out).
for fr in (SecondFrame, FirstFrame):
frame = fr(parent=self)
self.frames[str(counter)] = frame
frame.grid(row=1, column=0, sticky='nsew') # Put all the frames in the same spot.
counter -= 1
def switch_frame(self):
if self.frame_on_top == 1:
frame = self.frames['2']
frame.tkraise()
self.frame_on_top = 2
elif self.frame_on_top == 2:
frame = self.frames['1']
frame.tkraise()
self.frame_on_top = 1
class FirstFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
tk.Label(self, text='First frame').pack()
class SecondFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
tk.Label(self, text='Second frame').pack()
root = MainWindow()
root.mainloop()
try making a button that it's command goes back to that function
def BackFunction(self):
pass
def __init__(self):
back = Button(root, command=self.BackFunction)

Checking if Tkinter Widget (OptionMenu) is disabled

I feel like I've scoured the web for an eternity, rephrased my question a thousand times for something I feel like should be very simple.
I wonder if there is a way to check if a Tkinter Widget is active (not greyed out / disabled). I have a set of OptionMenus that start out disabled, and are configured to state=ACTIVE when they click a checkbox, so that the user can select which OptionMenus they want to use.
When I try to "submit" the fields in the OptionMenus, I only want the ones that are ACTIVE. I already tried if OptionMenu.state == ACTIVE but then I get an error that OptionMenu has no attribute state, even though I configure that earlier.
Here is a sample of my code:
from tkinter import *
class Application(Frame):
# Initializing the window and the required variables
def __init__(self, master=None):
Frame.__init__(self, master)
self.checkbox_in_use = BooleanVar(self, False)
self.checkbox = Checkbutton(self, text="check",
var=self.checkbox_in_use,
command=self.check_change
self.checkbox.grid(row=0, column=1, sticky='W')
self.menu = OptionMenu(title_setting,
"Menu",
"Menu",
["Menu1", "Menu2"])
self.menu.grid(row=1, column=1)
self.menu.config(state=DISABLED)
submit = Button(self, text="submit",
command=self.submit_function)
submit.grid(row=2, column=0)
self.master = master
self.init_window()
# Initialize the window
def init_window(self):
self.master.title("Example")
self.pack(fill=BOTH, expand=1)
def check_change(self):
if self.checkbox_in_use.get():
self.menu.config(state=ACTIVE)
else:
self.menu.config(state=DISABLED)
def submit_function(self):
# This is the part I want to do something with.
if self.menu.state == ACTIVE:
print("You are good to go! Do the stuff.")
root = Tk()
root.geometry("400x300")
app = Application(root)
root.mainloop()
Thank you for all responses.
All you need is cget() for this. self.menu.cget('state') will do the trick.
That said I want to point out some other things in your code.
You Application class already has an __init__ at the start so why use:
# Initialize the window
def init_window(self):
self.master.title("Example")
self.pack(fill=BOTH, expand=1)
You really should not pack the frame from inside the frame class but rather when calling the class. Also pack wont work here it will throw an error. Do this instead: app = Application(root).grid().
Take a look at the reformatted example below (with cget()).
from tkinter import *
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master.title("Example")
self.checkbox_in_use = BooleanVar(self, False)
self.checkbox = Checkbutton(self, text="check", var=self.checkbox_in_use, command=self.check_change)
self.checkbox.grid(row=0, column=1, sticky='W')
self.menu = OptionMenu(master,"Menu","Menu",["Menu1", "Menu2"])
self.menu.grid(row=1, column=1)
self.menu.config(state=DISABLED)
Button(self, text="submit", command=self.submit_function).grid(row=2, column=0)
def check_change(self):
if self.checkbox_in_use.get():
self.menu.config(state=ACTIVE)
else:
self.menu.config(state=DISABLED)
def submit_function(self):
print(self.menu.cget('state'))
root = Tk()
root.geometry("400x300")
app = Application(root).grid()
root.mainloop()

Tkinter Grid Dynamic Layout

I am wanting to create a grid layout, with a grid that fills the first row until it runs out of space in the window, and will dynamically move items to the row below (like text line-wrapping). As the window width is adjusted, the grid adjusts to fit. The boxes resizing is not desired. I intend to maintain each small box's size, but change where the layout puts each box.
I imagine this functionality is possible by measuring the width of the frame, and if the (number of boxes)*(width of each box) exceeds the width, move to the next row. I was just wondering if there was a better way built in that I'm not understanding.
If the above is the only option, what is the best way to update that? Do I have to set an event on window resize or something? It seems like I shouldn't have to rework a layout manager, which is what that feels like. I just want to check if similar functionality is already built in. Grid seems like a powerful layout manager, but I have not been able to find that option.
The below pics describes the behavior I want using the same set of 6 boxes on a single frame using grid layout.
Window is wide enough to hold all 6 boxes, so they all fit on row 1. They then adjust as window size changes.
If you plan on forcing each box to be a uniform size, the simplest solution is to use the text widget as the container since it has the built-in ability to wrap.
Here is a working example. Click on the "add" button to add additional boxes. Resize the window to see that they automatically wrap as the window grows and shrinks.
import Tkinter as tk
import random
class DynamicGrid(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.text = tk.Text(self, wrap="char", borderwidth=0, highlightthickness=0,
state="disabled")
self.text.pack(fill="both", expand=True)
self.boxes = []
def add_box(self, color=None):
bg = color if color else random.choice(("red", "orange", "green", "blue", "violet"))
box = tk.Frame(self.text, bd=1, relief="sunken", background=bg,
width=100, height=100)
self.boxes.append(box)
self.text.configure(state="normal")
self.text.window_create("end", window=box)
self.text.configure(state="disabled")
class Example(object):
def __init__(self):
self.root = tk.Tk()
self.dg = DynamicGrid(self.root, width=500, height=200)
add_button = tk.Button(self.root, text="Add", command=self.dg.add_box)
add_button.pack()
self.dg.pack(side="top", fill="both", expand=True)
# add a few boxes to start
for i in range(10):
self.dg.add_box()
def start(self):
self.root.mainloop()
Example().start()
Here's a working example:
import Tkinter as tk
class AutoGrid(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.columns = None
self.bind('<Configure>', self.regrid)
def regrid(self, event=None):
width = self.winfo_width()
slaves = self.grid_slaves()
max_width = max(slave.winfo_width() for slave in slaves)
cols = width // max_width
if cols == self.columns: # if the column number has not changed, abort
return
for i, slave in enumerate(slaves):
slave.grid_forget()
slave.grid(row=i//cols, column=i%cols)
self.columns = cols
class TestFrame(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, bd=5, relief=tk.RAISED, **kwargs)
tk.Label(self, text="name").pack(pady=10)
tk.Label(self, text=" info ........ info ").pack(pady=10)
tk.Label(self, text="data\n"*5).pack(pady=10)
def main():
root = tk.Tk()
frame = AutoGrid(root)
frame.pack(fill=tk.BOTH, expand=True)
TestFrame(frame).grid() # use normal grid parameters to set up initial layout
TestFrame(frame).grid(column=1)
TestFrame(frame).grid(column=2)
TestFrame(frame).grid()
TestFrame(frame).grid()
TestFrame(frame).grid()
root.mainloop()
if __name__ == '__main__':
main()
Note this will ruin the rowspan and columnspan features of the grid manager.
Here's a streamlined version of Bryan's answer without classes and a few extra comments for anyone who is confused and is trying to implement this quickly into their own project.
from tkinter import *
import tkinter as tk
#Create main window
root = tk.Tk()
#Create WidgetWrapper
widgetWrapper = tk.Text(root, wrap="char", borderwidth=0,highlightthickness=0,state="disabled", cursor="arrow")
#state = "disabled" is to disable text from being input by user
#cursor = "arrow" is to ensure when user hovers, the "I" beam cursor (text cursor) is not displayed
widgetWrapper.pack(fill="both", expand=True)
def additem():
item = Label(bd = 5, relief="solid", text="O", bg="red") #Create the actual widgets
widgetWrapper.window_create("end", window=item) #Put it inside the widget wrapper (the text)
# add a few boxes to start
for i in range(10):
additem()
#Not needed to implement in other code, just an add button
add_button = tk.Button(root, text="Add", command=additem)
add_button.pack()

How to make Tkinter button to be placed in particular position?

I am new to python so I was trying to make a GUI, in that I have to place a button in a particular position.
I tried using self.nxt_form.place(x=200,y=100) instead of self.nxt_form.pack().
But the button disappeared and only the frame appeared when it ran. Can you tell me how to place the button in a particular position?
Here is the code:
import tkinter as tk
class Main_form:
def __init__(self, root,title="Simulated MTBF"):
self.root = root
self.frame = tk.Frame(self.root)
"""Button nxt_form which moves to next form"""
self.nxt_form = tk.Button(self.frame, text = 'Next Form', width = 25,command = self.new_window)
self.nxt_form.pack()
self.frame.pack()
"""command to open new window by clicking Button """
def new_window(self):
self.newWindow = tk.Toplevel(self.root)
self.app = Demo2(self.newWindow)
class Demo2:
def __init__(self, root):
self.root = root
self.frame = tk.Frame(self.root)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.root.destroy()
def main():
root = tk.Tk()
app = Main_form(root)
root.mainloop()
if __name__ == '__main__':
main()
when i am using tkinter i used column and row to position objects
self.btn = tk.Button(self, text = "button")
self.btn.grid(row = 1, column = 1)
EDIT - expanded on information in response to comment (below)
I would make an label and change its width and height to make the spacing you need (note im a beginer at python as well so this is probly a bad way but it works)
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.create_GUI()
def create_GUI(self):
frame1 = tk.LabelFrame(self, text="frame1", width=300, height=130, bd=5)
frame1.grid(row=0, column=0, columnspan=3, padx=8)
#the frame is not needed but it is a good thing to use as can group
#parts of your interface together
self.text1 = Entry(frame1)
#note if you were not using frames would just put self here
self.text1.grid(row = 1, column = 0)
self.text2 = Label(frame1, text = "",height = 10)
self.text2.grid(row = 2 , column = 0)
self.text3 = Entry(frame1)
self.text3.grid(row = 3, column = 0)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()
Also note that you can not use pack and grid together what you could do is group your objects in different frames then use grid in one frame and pack in a different frame. I personally prefer to use grid to pack as it gives you more control over your object then pack does

python 3.2.5 grid sticky/weight not working

Below is a simple illustration of the problem. It consists of a grid layout where I've placed a button widget in row 0 and a text widget in row 1.
What I want is for the text widget in row 1 to expand with the form while keeping the top of the text widget anchored NW (row 0 not expanding). The problem is that the horizontal(column expands correctly, but the text widget row does not. If I get rid of the button the text widget expands correctly. Also the original form I've put together is more involved and is best served using a grid. So basically using pack isn't a solution. Any help would be appreciated.
################################################
from tkinter import *
class Application(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initGui()
# ##################################################################
# Initialize GUI widgets
def initGui(self):
self.parent.title("Test Grid")
self.parent.resizable(width=TRUE, height=TRUE)
self.grid(sticky=W+E+N+S, padx=20, pady=20)
self.parent.columnconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.parent.rowconfigure(1, weight=1)
self.rowconfigure(1, weight=1)
# Add a button to row 0
self.btn = Button(self, text="Button", width=20)
self.btn.grid(row=0, column=0, padx=(0,10),pady=(0,10), sticky=N+W)
# Add a text box and v-scrollbar to row 1
self.txtOut = Text(self, width=80, height=20)
self.scrOut = Scrollbar(self)
self.txtOut.grid(row=1,column=0,padx=(0,18),sticky=N+E+S+W)
self.scrOut.grid(row=1,column=0,sticky=N+S+E)
self.scrOut.config(command=self.txtOut.yview)
self.txtOut.config(yscrollcommand=self.scrOut.set)
print(self.grid_size())
def main():
root = Tk()
app = Application(parent=root)
app.mainloop()
if __name__ == '__main__':
main()
There's a case where using pack probably is a solution. It won't cause any conflicts if you pack the instance of the Frame (Application) inside the root window, then grid widgets inside that frame. It'll cut down on the headache of all the rowconfigure and columnconfigure methods and just makes more sense to me.
def initGui(self):
self.parent.title("Test Grid")
self.parent.resizable(width=TRUE, height=TRUE)
self.pack(fill=BOTH, expand=1, padx=20, pady=20)
self.columnconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
The core problem is that you are putting the application frame in row 0 (zero), but you are giving row 1 (one) a weight of 1 (one). That is why the text widget doesn't expand when you resize the window.
This is really hard to see because you mix grid commands of a widget in its parent, along with its own children widgets. It makes it hard to quickly scan the code to see what the layout options are, because you can't assume all of the grid, pack or place commands only affect child widgets.
Another minor problem with your code is that you've put the text widget and scrollbar in the same column.
Here's how I would change the code: remove the self.grid and self.parent.*configure commands from initGui. Then, use pack to add the application frame to the root window at the point where it's created. Also, move the scrollbar to column 1.
class Application(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initGui()
# ##################################################################
# Initialize GUI widgets
def initGui(self):
self.parent.title("Test Grid")
self.parent.resizable(width=TRUE, height=TRUE)
self.columnconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
# Add a button to row 0
self.btn = Button(self, text="Button", width=20)
self.btn.grid(row=0, column=0, padx=(0,10),pady=(0,10), sticky=N+W)
# Add a text box and v-scrollbar to row 1
self.txtOut = Text(self, width=80, height=20)
self.scrOut = Scrollbar(self)
self.txtOut.grid(row=1,column=0,padx=(0,18),sticky=N+E+S+W)
self.scrOut.grid(row=1,column=1,sticky=N+S)
self.scrOut.config(command=self.txtOut.yview)
self.txtOut.config(yscrollcommand=self.scrOut.set)
print(self.grid_size())
def main():
root = Tk()
app = Application(parent=root)
app.pack(fill="both", expand=True)
app.mainloop()
if __name__ == '__main__':
main()

Categories