I'm not quite sure the best way to ask this (I've tried searching and can't find what I'm looking for). I have a GUI that uploads an excel sheet that has base information, cleans it up, adds in relevant information, and exports out a new excel.
What I'm looking to do is to be able to copy/paste the relevant data directly into the GUI rather than uploading an excel sheet. The data is on a different application that currently has to be pasted into an into an excel sheet to be able to be uploaded.
For reference the data would be 3 columns and up to 100 rows in length.
Let me know if more information is needed or if I can explain something better! I'm very new to programming so I'm not always sure what verbiage to use.
Update: This is my script currently. I was looking to replace def getExcel1 () with being able to paste the information over rather than having to paste into an excel then upload the excel.
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
import pandas as pd
import xlwt
window = tk.Tk()
canvas1 = tk.Canvas(window, width = 400, height = 250, bg = 'lightsteelblue2', relief = 'raised')
canvas1.pack()
label1 = tk.Label(window, text = 'Store Name', width = 20)
entry1 = tk.Entry()
canvas1.create_window(250, 100, window = entry1)
canvas1.create_window(100, 100, window = label1)
def getExcel1 ():
global df1
import_file_path = filedialog.askopenfilename()
df1 = pd.read_excel (import_file_path)
browseButton_CSV1 = tk.Button(text=" Import TC56 Information ", command=getExcel1, bg='green', fg='white', font=('bookman old style', 12, 'bold'))
canvas1.create_window(200, 50, window=browseButton_CSV1)
def getInput1 ():
global df2
df2 = entry1.get()
submit_button1 = tk.Button(text = 'Submit Store Name', command = getInput1, bg = 'green', fg = 'white', font= ('bookman old style', 12, 'bold'))
canvas1.create_window(200, 150, window = submit_button1)
def CreateExcel ():
Serial = df1['DSN'].str.split('S').str[1]
Asset = df1['Asset']
DevNum = df1['Device #']
Friendly = df2 + ' ' + '#' + DevNum.astype(str) + ' ' + Serial.astype(str)
df = pd.DataFrame({'Serial': Serial, 'FriendlyName': Friendly, 'Asset': Asset, 'ProdOG': df2 + 'AD'})
export_file_path = filedialog.asksaveasfilename(defaultextension='.xls')
df.to_excel (export_file_path, index = None, header=True)
browseButton_CSV1 = tk.Button(text=" Create Input File ", command=CreateExcel, bg='green', fg='white', font=('bookman old style', 12, 'bold'))
canvas1.create_window(200, 200, window=browseButton_CSV1)
window.mainloop()
The in_() function reads and stores text from the clipboard. It also assumes there's no tk.Tk() object so it's not really needed here. It's the from_grid function that arranges the text into nested lists. You may prefer to arrange for it to return a dataframe rather than a list of lists.
I've trimmed your code to just show the reading part. I've no real pandas experience. I think there may be ways to read into a pandas dataframe from the clipboard but I've never done it.
To use: copy a region in an excel spreadsheet before clicking "Import TC56 Information" The resulting dataframe will print in the console. It can then processed as required.
import tkinter as tk
import pandas as pd
import numpy as np
window = tk.Tk()
def from_grid(parent, delimit_row="\n", delimit_cell="\t"):
"""
Returns a list of lists copied from the clipboard.
Usage: grid=from_grid(delimit_row="\t", delimit_cell="\n")
grid is a list of lists
[ [ r00, r01, r02, ... ],
[ r10, r11, r12, ... ],
....
]
by defaut: the row delimiter is a newline, "\n"
the cell delimiter is a tab character, "\t"
This will paste a copied region of a spreadsheet into a list of lists.
"""
txt = parent.selection_get(selection="CLIPBOARD") # Replaces the in_() function.
rows=txt.split(delimit_row)
ret=[]
for row in rows:
temp=row.split(delimit_cell)
ret.append(temp)
return ret[:-1] # A final empty last row is appended.
# This loses it.
canvas1 = tk.Canvas(window, width = 400, height = 250, bg = 'lightsteelblue2', relief = 'raised')
canvas1.pack()
df1 = 0 # Result store
def do_paste():
global df1
temp=from_grid( window )
df1 = pd.DataFrame( np.array( temp[1:] ), columns= temp[0] ) # Assumed column headers from Excel
print(df1) # To see what's happening remove once it's working
browseButton_CSV1 = tk.Button(text=" Import TC56 Information ", command=do_paste )
canvas1.create_window(200, 50, window=browseButton_CSV1)
window.mainloop()
Related
In this code, I'm trying to open PDFs as a separate window using tkinter and tkPDFViewer. The way this is done is a simple UI opens up with 2 buttons for 2 articles that are accessed from my computer in this case (but I just labeled it "filepath" for the file path to avoid revealing personal info). However, while the buttons work and open up a PDF window and a download window below that (as expected), when you close the PDF window (and the download window closes along with it) and then re-click on a button (the same one or a different one), it shows the previous pdf and the current one that appeared when you re-click combined. As you repeat this process, the PDFs just append to each other. However, what should happen is that the corresponding PDF to the article that is described in the button is shown and no other PDFs. How do I fix this? I've already tried to move the PDF initialization outside the event function then re-initialize it, but that results in a "local variable used before being defined" error, so that doesn't work, and I currently do not know of any other way to do this.
pdfArray = [
["skweak: Weak Supervision Made Easy for NLP",
r"filepath",
"Pierre Lison, Jeremy Barnes, and Aliaksandr Hubin",
"skweak, NLP, Natural Language Processing"],
["Information Theoretic-Based Quality Measures for Clustering",
r"filepath",
"Barry Drake, and Tiffany Huang",
"Quality Measures, Clustering, Data"
]
]
#Import tkinter library
import os
from tkinter import *
import tkinter as tk
from tkinter import ttk
from tkPDFViewer import tkPDFViewer as pdfViewer
from functools import partial
import shutil
#Create an instance of tkinter frame or window
mainWin= Tk()
#Set the geometry of tkinter frame
mainWin.geometry("1000x600+20+20")
download_icon = tk.PhotoImage(file=r'filepath')
paw_icon = tk.PhotoImage(file=r'filepath')
def download_pdf(original_file):
#this if-else statment detects if the original file exists.
if os.path.isfile(original_file):
newFileStem = os.path.expanduser('~') + r"\Downloads\ChatBox_download"
num = 0
while os.path.isfile(newFileStem + "(%d).pdf"%num):
num = num + 1;
newFile = newFileStem + "(%d).pdf"%num
f = open(newFile, "x")
shutil.copyfile(original_file, newFile)
completeWin = Toplevel(mainWin)
completeWin.geometry("400x75+660+480")
completeWin.title("Download Complete")
Label(completeWin, text = "Download Complete!", font = ('Gabriola', 14, 'bold')).pack()
Label(completeWin, text = str(newFile), font = ('Gabriola', 10)).pack(pady=2)
else:
notFoundWin = Toplevel(mainWin)
notFoundWin.geometry("200x75+660+480")
notFoundWin.title("File Not Found")
Label(notFoundWin, text = "File Not Found", font = ('Gabriola', 14, 'bold')).pack(pady=20)
#Define a new function to open the window
def open_win(pdf_ID):
pdf_title = pdfArray[pdf_ID][0] #title of pdf
file_location = pdfArray[pdf_ID][1] #location of pdf
authors = pdfArray[pdf_ID][2] #authors
keywords = pdfArray[pdf_ID][3] #keywords
pdfWin = Toplevel(mainWin)
pdfWin.geometry("600x350+640+20")
pdfWin.title(pdf_title)
# Adding pdf location and width and height.
pdfViewer.ShowPdf().pdf_view(pdfWin, pdf_location=file_location, width=70, height=100).pack(ipadx = 10, ipady = 10)
infoWin = Toplevel(pdfWin)
infoWin.geometry("600x200+640+420")
infoWin.title("PDF Information")
Label(infoWin, text = "Information: ", font = ('Gabriola', 15, 'bold')).pack(pady=2)
Label(infoWin, text = "Title: " + pdf_title, font = ('Gabriola', 12)).pack(pady=1)
Label(infoWin, text = "Author(s): " + authors, font = ('Gabriola', 12)).pack(pady=1)
Label(infoWin, text = "Keyword(s): " + keywords, font = ('Gabriola', 12)).pack(pady=1)
tk.Button(infoWin, image=download_icon, borderwidth = 0, command=partial(download_pdf, file_location)).pack(pady=1)
#Create a label
Label(mainWin, text= "Click any button below to open a PDF", font= ('Gabriola', 25, 'bold')).pack(pady=30, padx = 10)
#Create a button to open a New Window
for ID in range(0, len(pdfArray)):
tk.Button(mainWin, image=paw_icon, compound=LEFT, text=" Open \" " + pdfArray[ID][0]+" \"", font= ('Gabriola', 12), command=partial(open_win, ID)).pack(pady=2)
mainWin.mainloop()
I ran into this issue as well when using tkPDFViewer.
To fix I had to go into the tkPDFViewer module and add a line:
self.img_object_li.clear()
immediately after the line:
def add_img():
I'm just a beginner myself so this was my fix to get around the issue.
From what I understand the line:
self.img_object_li.append(timg)
adds images indefinitely, I was trying to destroy the frame and widgets containing the objects from my main program but couldn't get it to work at all. Issue just kept persisting. This is probably not the best way to do it and someone else will ahve a better fix.
I'm struggling again to figure out a way to update my tkinter listbox from a combobox selection.
What I want to happen is the user imports an excel file, the file is then read and all the sheets available on that workbook is displayed for the user to select (this part works - Combobox), once its selected it suppose to display all the headers in that excel sheet in a listbox so the user can select multiple headers. The headers changes depending on the sheet selected, so the listbox would have to update and display the new headers.
I figured out how to display it as a ComboBox and it'll update as different sheets are selected, but I need the ability to select multiple headers - hence why I'm trying to use a listbox.
I've pasted what I've got right now.
import pandas as pd
import os
import xlrd
from tkinter import *
from tkinter.filedialog import askopenfilename, asksaveasfilename
from tkinter.ttk import Combobox
import tkinter as tk
import re
import numpy as np
class myApp:
importedSheets = []
headers = []
reports = ['A','B','C','D']
# rb_select = IntVar()
def UploadAction(self):
self.filename = askopenfilename()
def SaveAction(self):
self.savelocation = asksaveasfilename()
def sheetnames(self):
self.xlssheets = xlrd.open_workbook(self.filename,on_demand=True)
importedSheets = self.xlssheets.sheet_names()
self.cbox_sheets.config(value=importedSheets) #updating the value of the combobox
return importedSheets
def headernames(self):
if self.reporttype.get(self.reporttype.curselection()) == self.reports[0]:
self.df = pd.read_excel(self.filename,sheet_name = self.cbox_sheets.get(),header = 1, index_col=0)
headers = list(self.df.columns)
self.headerselectors.config(values=headers)
def __init__(self,master):
self.filename = None
self.master = master
#---------------------------------------------------------------------#
# Creating Basic Frame Structure
#---------------------------------------------------------------------#
self.frame1 = Frame(master=master,relief=RAISED,borderwidth=1)
self.frame1.pack(padx=10,pady=10)
self.frame2 = Frame(master=master,relief=RAISED,borderwidth=1)
self.frame2.pack(padx=10,pady=10)
self.frame3 = Frame(master=master,relief=RAISED,borderwidth=1)
self.frame3.pack(padx=10,pady=10)
#---------------------------------------------------------------------#
# Frame 2 - Selecting Sheet and Header To Work with
#---------------------------------------------------------------------#
self.frame2a = Frame(master = self.frame2)
self.frame2b = Frame(master = self.frame2)
self.frame2r = Frame(master = self.frame2)
self.frame2a.pack(side=TOP)
self.frame2b.pack(side=LEFT)
self.frame2r.pack(side=RIGHT)
self.uploadLabel = Label(master = self.frame2a,text = '1) Select the file you want to import',font=(None,12,)).pack()
self.uploadButton = Button(master = self.frame2a,text = 'Import', command =lambda:self.UploadAction()).pack(padx=5,pady=5)
self.reporttype = Listbox(master=self.frame2a,height=4,selectmode=SINGLE,exportselection = False)
for x,reports in enumerate(self.reports):
self.reporttype.insert(x,reports)
self.reporttype.pack(padx=5,pady=5)
#---------------------------------------------------------------------#
# Selecting Sheets to work with:
#---------------------------------------------------------------------#
self.sheetLabel = Label(master = self.frame2b,text = '2) Select the sheet to extract',font=(None,12)).pack(padx=15)
self.cbox_sheets = Combobox(master = self.frame2b,values = self.importedSheets,postcommand = self.sheetnames)
self.cbox_sheets.pack(padx=5,pady=5)
#---------------------------------------------------------------------#
# Selecting Headers to Work with:
#---------------------------------------------------------------------#
self.headerLabel = Label(master = self.frame2r,text = '3) Select the header with data',font=(None,12)).pack(padx=15)
self.headerselectors = Combobox(master = self.frame2r,values = self.headers,postcommand = self.headernames)
self.headerselectors.pack(padx=5,pady=5)
if __name__ == '__main__':
root = Tk()
my_gui = myApp(root)
root.mainloop()
EDIT: The section that needs to be worked on is in: Selecting Headers to Work with (I don't know how to highlight on stackoverflow)
To create a dynamic listbox I had to bind it to a button:
self.headerLabel = Label(master = self.frame2r,
text = '3) Select the header with data',
font=(None,12)).pack(padx=15)
self.headers_button = Button(master = self.frame2r, text = 'Show Headers',command = self.headernames).pack()
self.headers_select = Listbox (master = self.frame2r,exportselection = False,selectmode=MULTIPLE)
self.headers_select.pack()
Once I created the basic listbox and button I added to my function def headernames(self):
def headernames(self):
if self.reporttype.get(self.reporttype.curselection()) == self.reports[0]:
self.df = pd.read_excel(self.filename,sheet_name = self.cbox_sheets.get(),header = 1, index_col=0)
headers = list(self.df.columns)
self.headers_select.delete(0,'end')
for x,header in enumerate(headers):
self.headers_select.insert(x,header)
Now everytime I click on the button "Show Headers" it'll clear the list and then add the new headers for the selected sheet.
Goal:
I am trying to have the script look through a directory named 'data' that is in the working directory of the script for excel workbooks. The script will then have a options menu of the different workbooks to choose from which will then give a selection of column names to choose from in a combo box above.
Results:
I was able to get it to read the default excel workbook upon start up but when I choose a different workbook the combo box does not update the column names.
I've tried to incorporate some sort of update function but I keep having trouble even running it because one or more things don't really line up. I am still new to python and tkinter so I would like some advice and suggestions to solve this problem.
import tkinter
from tkinter import ttk
from tkinter import *
import pandas as pd
def _quit():
root.quit()
root.destroy()
root = Tk()
root.title('BLURG')
root.geometry("1280x720")
path = os.chdir('Data')
filenames = os.listdir(path)
data_as_list = []
for filename in filenames:
if filename.endswith('.xlsx') or filename.endswith('.xls'):
data_as_list.append(filename)
clicked = StringVar()
options = data_as_list
clicked.set(options[0])
drop = OptionMenu(root, clicked, *options)
drop.pack(side="right")
data = pd.read_excel(clicked.get())
df = pd.DataFrame(data)
col_name = list(df.columns)
labelx = tkinter.Label(root, text="x-axis: ")
combox = ttk.Combobox(root, values=col_name)
labelx.pack(side="top")
combox.pack(side="top")
button = tkinter.Button(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)
root.mainloop()
Using an update function with a postcommand fixed the problem.
...
def update_list():
data = pd.read_excel(clicked.get())
df = pd.DataFrame(data)
col_name = list(df.columns)
combox['values'] = col_name
labelx = tkinter.Label(root, text="x-axis: ")
combox = ttk.Combobox(root, postcommand=update_list)
...
My main goal is to write a python scrypt that outputs the temperature by inputing your current city.
I made one and im getting this y = x["main"] KeyError: 'main' python. This is using a gui. The gui part works.
I blocked out my api key by the way.
Here is the code i have so far:
# import all functions from the tkinter
#from tkinter import *
#from tkinter import messagebox *
import tkinter
from tkinter import messagebox
from tkinter import Label
from tkinter import Entry
from tkinter import Button
from tkinter import END
messagebox.showinfo("Title", "a Tk MessageBox")
# hide main window
root = tkinter.Tk()
root.withdraw()
# message box display
messagebox.showerror("Error", "Error message")
messagebox.showwarning("Warning","Warning message")
messagebox.showinfo("Information","Informative message")
# function to find weather details
# of any city using openweathermap api
def tell_weather() :
# import required modules
import requests
# enter your api key here
api_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
# base_url variable to store url
base_url = 'http://api.openweathermap.org/data/2.5/weather?'
# take a city name from city_field entry box
city_name = city_field.get()
# complete_url variable to store complete url address
complete_url = (base_url + "appid =" + api_key
+ "&q =" + city_name)
# get method of requests module
# return response object
response = requests.get(complete_url)
# json method of response object convert
# json format data into python format data
x = response.json()
print(x)
# now x contains list of nested dictionaries
# we know dictionary contains key value pair
# check the value of "cod" key is equal to "404"
# or not if not that means city is found
# otherwise city is not found
if x["cod"] != "404" :
# store the value of "main" key in variable y
#if __main__ == '__response.json() __':
y = x['main']
# store the value corresponding to the "temp" key of y
current_temperature = y["temp"]
# store the value corresponding to the "pressure" key of y
current_pressure = y["pressure"]
# store the value corresponding to the "humidity" key of y
current_humidiy = y["humidity"]
# store the value of "weather" key in variable z
z = x["weather"]
# store the value corresponding to the "description" key
# at the 0th index of z
weather_description = z[0]["description"]
# insert method inserting the
# value in the text entry box.
temp_field.insert(15, str(current_temperature) + " Kelvin")
atm_field.insert(10, str(current_pressure) + " hPa")
humid_field.insert(15, str(current_humidiy) + " %")
desc_field.insert(10, str(weather_description) )
# if city is not found
else :
# message dialog box appear which
# shows given Error meassgae
messagebox.showerror("Error", "City Not Found \n"
"Please enter valid city name")
# clear the content of city_field entry box
city_field.delete(0, END)
# Function for clearing the
# contents of all text entry boxes
def clear_all() :
city_field.delete(0, END)
temp_field.delete(0, END)
atm_field.delete(0, END)
humid_field.delete(0, END)
desc_field.delete(0, END)
# set focus on the city_field entry box
city_field.focus_set()
# Driver code
if __name__ == "__main__" :
# Create a GUI window
root = tkinter.Tk()
# set the name of tkinter GUI window
root.title("Gui Application")
# Set the background colour of GUI window
root.configure(background = "light green")
# Set the configuration of GUI window
root.geometry("425x175")
# Create a Weather Gui Application label
headlabel = Label(root, text = "Weather Gui Application",
fg = 'black', bg = 'red')
# Create a City name : label
label1 = Label(root, text = "City name : ",
fg = 'black', bg = 'dark green')
# Create a City name : label
label2 = Label(root, text = "Temperature :",
fg = 'black', bg = 'dark green')
# Create a atm pressure : label
label3 = Label(root, text = "atm pressure :",
fg = 'black', bg = 'dark green')
# Create a humidity : label
label4 = Label(root, text = "humidity :",
fg = 'black', bg = 'dark green')
# Create a description :label
label5 = Label(root, text = "description :",
fg = 'black', bg = 'dark green')
# grid method is used for placing
# the widgets at respective positions
# in table like structure .
headlabel.grid(row = 0, column = 1)
label1.grid(row = 1, column = 0, sticky ="E")
label2.grid(row = 3, column = 0, sticky ="E")
label3.grid(row = 4, column = 0, sticky ="E")
label4.grid(row = 5, column = 0, sticky ="E")
label5.grid(row = 6, column = 0, sticky ="E")
# Create a text entry box
# for filling or typing the information.
city_field = Entry(root)
temp_field = Entry(root)
atm_field = Entry(root)
humid_field = Entry(root)
desc_field = Entry(root)
# grid method is used for placing
# the widgets at respective positions
# in table like structure .
# ipadx keyword argument set width of entry space .
city_field.grid(row = 1, column = 1, ipadx ="100")
temp_field.grid(row = 3, column = 1, ipadx ="100")
atm_field.grid(row = 4, column = 1, ipadx ="100")
humid_field.grid(row = 5, column = 1, ipadx ="100")
desc_field.grid(row = 6, column = 1, ipadx ="100")
# Create a Submit Button and attached
# to tell_weather function
button1 = Button(root, text = "Submit", bg = "red",
fg = "black", command = tell_weather)
# Create a Clear Button and attached
# to clear_all function
button2 = Button(root, text = "Clear", bg = "red",
fg = "black", command = clear_all)
# grid method is used for placing
# the widgets at respective positions
# in table like structure .
button1.grid(row = 2, column = 1)
button2.grid(row = 7, column = 1)
# Start the GUI
root.mainloop()
Im also getting this :
{cod 401, message Invalid API key. Please see http://openweathermap.org/ faq #error401 for more info.} Exception in Tki
I Know i am using the correct api key. maybe i am missing something.
Excuse my formatting of the code. This is the first time I use stackoverflow.
This is python language btw.
I faced the same problem earlier on , but then i realised it was just a bone headed mistake
In this line ,
....
complete_url = (base_url + "appid =" + api_key
+ "&q =" + city_name)
....
there should be no spaces between any of the characters , otherwise %20 will be inserted automatically by the browser to fill the gap , thus messing with api key . So change it to:
....
complete_url = (base_url + "appid=" + api_key
+ "&q=" + city_name) ↑
.... ↑
The only changes I've made is removed the extra spaces
(The arrows indicate the changes made .)
Hope it helped !
The error message is fairly clear. It is saying that in this bit of code:
if x["cod"] != "404" :
# store the value of "main" key in variable y
#if __main__ == '__response.json() __':
y = x['main']
You try to look up the key 'main' in the dictionary x but that key is not in the dictionary x.
What I'm trying to do is get the frame with the two buttons (sframe) centered inside of the notebook (master) frame. This works without issue on Python 2.4 but on Python 2.7 the frame is anchored to NW by default. I know if I rowconfigure() / columnconfigure() the master page frame the inner frame will center itself but this solution doesn't seem correct. Disabling propagation and changing row/column weights don't seem to help either. Is there anyway to just get that inner frame centered properly? Here is the test code I'm working with:
import Tkinter as tk, Tkinter
import Pmw
class SimpleApp(object):
def __init__(self, master, **kwargs):
title = kwargs.pop('title')
master.configure(bg='blue')
sframe = tk.Frame(master, relief=tk.RIDGE, bd=5, width=100,bg='green')
sframe.grid()
button = tk.Button(sframe, text = title)
button.grid(sticky = tk.W)
button = tk.Button(sframe, text = 'next')
button.grid(sticky = tk.E)
#sframe.propagate(0)
#master.rowconfigure(0, minsize = 300)
#master.columnconfigure(0, minsize = 300)
class Demo:
def __init__(self, parent):
# Create and pack the NoteBook.
notebook = Pmw.NoteBook(parent)
notebook.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
# Add the "Appearance" page to the notebook.
page = notebook.add('Helpers')
app = SimpleApp(page, title= 'hello, world')
notebook.tab('Helpers').focus_set()
page = notebook.add('Appearance')
# Create the "Toolbar" contents of the page.
group = Pmw.Group(page, tag_text = 'Toolbar')
group.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
b1 = Tkinter.Checkbutton(group.interior(), text = 'Show toolbar')
b1.grid(row = 0, column = 0)
b2 = Tkinter.Checkbutton(group.interior(), text = 'Toolbar tips')
b2.grid(row = 0, column = 1)
# Create the "Startup" contents of the page.
group = Pmw.Group(page, tag_text = 'Startup')
group.pack(fill = 'both', expand = 1, padx = 10, pady = 10)
home = Pmw.EntryField(group.interior(), labelpos = 'w',
label_text = 'Home page location:')
home.pack(fill = 'x', padx = 20, pady = 10)
page = notebook.add('Images')
notebook.setnaturalsize()
def basic():
root = tk.Tk()
#app = SimpleApp(root, title = 'Hello, world')
app = Demo(root)
root.mainloop()
basic()
Let me know if I can provide any additional information.
You need to configure the weight of row 0 and column 0 in the master:
master.grid_columnconfigure(0, weight=1)
master.grid_rowconfigure(0, weight=1)
You are placing that inner sframe in row 0 column 0 of master, and since that cell has no weight it shrinks up to the upper-left corner. Giving the row and column a weight of 1 makes the column and row fill the available space. Since you aren't using any sticky options for the sframe, it will stay centered in its cell rather than filling its cell.