I am trying to make a Tkinter GUI that takes Excel documents, reads them, and exports them to the window. The issue is when I changed the code to below to incorporate class structure, I cannot make the GUI load properly anymore.
import tkinter as tk
from tkinter.filedialog import askopenfilename
def NewFile():
print("New File!")
def OpenFile():
name = askopenfilename()
print(name)
def About():
print("About works")
def deletelist():
listbox.delete(0, END)
class MainApplication(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.frame = tk.Frame(self.master)
self.load = tk.Button(self.frame, text = "Load XLSX File", command = OpenFile)
self.load.grid(row = 0, column = 0, padx = 5, pady = 5, sticky = 'w')
self.ckframe = tk.LabelFrame(self.frame, text="Currency Selections")
self.ckframe.grid(row = 1, column = 0, padx = 5, pady = 5, stick = 'nesw')
self.prochk = tk.Checkbutton(self.ckframe, text = '1 Currency').grid(row = 1, column = 0, columnspan = 2, sticky = 'w')
self.msnchk = tk.Checkbutton(self.ckframe, text = '2 Currency').grid(row = 1, column = 2, columnspan = 2, sticky = 'w')
self.nightschk = tk.Checkbutton(self.ckframe, text = '3 Currency').grid(row = 1, column = 4, columnspan = 2, sticky = 'w')
self.semichk = tk.Checkbutton(self.ckframe, text = '4 Currency').grid(row = 2, column = 0, columnspan = 2, sticky = 'w')
self.instqualCRchk = tk.Checkbutton(self.ckframe, text = '5 Currency').grid(row = 2, column = 2, columnspan = 2, sticky = 'w')
self.msnCRchk = tk.Checkbutton(self.ckframe, text = '6 Currency').grid(row = 2, column = 4, columnspan = 2, sticky = 'w')
self.listbox = tk.Listbox(self.frame, width = 83)
self.listbox.grid(row = 3, column = 0, columnspan = 1, sticky = 'w') # Fix width size function
self.listbox.insert(1, 'Test1')
self.listbox.insert(0, 'Test2')
self.save = tk.Button(self.frame, text = "Save").grid(row = 8, column = 0, padx = 5, pady = 5, stick = 'e')
self.delete = tk.Button(self.frame, text = "Delete", command = deletelist).grid(row = 8, column = 0, padx = 45, pady = 5, stick = 'e')
if __name__ == '__main__':
root = tk.Tk()
MainApplication(root)
root.mainloop()
I searched a lot trying to find a solution to using classes with tkinter GUI and the grid system but I mostly found ways to make GUIs with pack() solution.
The instance of MainApplication is a frame. You never call pack or place or grid on that instance so that frame and all of its children will be invisible.
This frame creates another frame that contains all of the other widgets, self.frame. You never call pack, place, or grid on it either, so it and all of its children will be invisible.
Since the widgets are in a frame that is invisible, and that frame itself is invisible, none of the other widgets will be visible.
The first thing to do is to get rid of self.frame. Remove the line that creates it, and everywhere you reference self.frame, replace it with self. Since self in this context is already a frame it makes no sense to create another frame inside.
Next, you need to add the instance of MainApplication to the window. Since it's the only widget directly in the root window, pack is the simplest choice.
root = tk.Tk()
app = = MainApplication(root)
app.pack(fill="both", expand=True)
Related
Trying to split my parent window in several functional parts, one of which will be dealing with weather
data and etc and another one will be located in the right side and contain the map image, preferably extending at full height. The image doesn't want to come up though.. Please help
import pyowm
from tkinter import *
import tkinter.messagebox
from PIL import Image, ImageTk
owm = pyowm.OWM('....') # You MUST provide a valid API key
class MyWindow(tkinter.Frame):
def __init__(self, win):
super(MyWindow, self).__init__()
self.lbl=Label(win, text="Weather info", fg='black', font=("Helvetica", 11))
self.lbl1=Label(win, text='Wind speed')
self.lbl2=Label(win, text='Wind direction')
self.lbl.grid(row = 0, column = 0, sticky = W, pady = 2)
self.lbl1.grid(row = 1, column = 0, sticky = W, pady = 2)
self.lbl2.grid(row = 2, column = 0, sticky = W, pady = 2)
# widgets for destination and weather output
self.e1=Entry()
self.e2=Entry()
self.e3=Entry(bd=3)
# this will arrange entry widgets
self.e1.grid(row = 0, column = 1, pady = 2)
self.e2.grid(row = 1, column = 1, pady = 2)
self.e3.grid(row = 2, column = 1, pady = 2)
self.btn1 = Button(win, text='Get weather', command=self.getWeather)
self.btn1.grid(row = 3, column = 1, pady = 2)
self.btn1.bind('<Button-1>', self.getWeather)
img = Image.open(r"/User/.../pic.png")
photo = ImageTk.PhotoImage(img)
# setting image with the help of label
self.imgLBL = Label(self, image = photo)
self.imgLBL.grid(row = 0, column = 2, columnspan = 2, rowspan = 2, padx = 5, pady = 5)
self.imgLBL.image = photo
#### Get weather function, etc...###
window=Tk()
mywin=MyWindow(window)
window.title('name')
window.geometry("2732x2048")
window.configure(bg='grey')
window.mainloop()
Replace last few lines with this:
self.photo = ImageTk.PhotoImage(Image.open(r"/User/.../pic.png"))
# setting image with the help of label
self.imgLBL = Label(window, image=self.photo)
self.imgLBL.grid(row = 0, column = 2, columnspan = 2, rowspan = 2, padx = 5, pady = 5)
self.imgLBL.image = self.photo
I have this code I coded using tkinter.
def create_widgets(self):
self.submit_button = Button(self, text ="Submit", command = self.popupmsg)
self.submit_button.grid(row = 6, column = 0, sticky = W)
def popupmsg(self):
popupmsg = Tk()
popupmsg.wm_title("Test")
self.grid()
self.text = Text(popupmsg,text="test", width = 30, height = 10, wrap = WORD)
self.text.grid(row = 8, column = 0, columnspan = 2, sticky = W)
I was wondering if there is any way to open popupmsg and close create_widgets. I know about ____.destroy() but using that i can only get it to close it not close it and open a new window
I'm new to Python and just started venturing into doing GUIs. I created a Tkinter window that is pretty basic: it has 3 Entry bars and 3 File Dialog buttons. When you chose the 3rd directory, the GUI file automatically makes a call to a separate file and receives a large text block which is then displayed in a Text box.
The whole thing works correctly, but my problem is that after receiving and inserting the text response, Tkinter stops working and doesn't allow the user to scroll down.
I read that one reason this happens is because people use both .pack( ) and .grid( ), but I'm not mixing those two functions.
Thanks in advance for any help!
Here's my GUI file
from tkinter import *
from tkinter import filedialog
from gui_GPSExtractor import *
import os
class Application(Frame):
def __init__(self, master):
""" Initialize Frame """
Frame.__init__(self, master)
self.grid( )
self.startGUI( )
""" Create Labels, Text Boxes, File Dialogs, and Buttons """
def startGUI(self):
# Label for Scan Path
self.dLabel = Label(self, text = "Scan Path")
self.dLabel.grid(row = 0, column = 0, columnspan = 2, sticky = W)
# Entry for Scan Path
self.dEntry = Entry(self, width = 60)
self.dEntry.grid(row = 1, column = 0, sticky = W)
# Button for Scan Path Directory Browse
self.dButton = Button(self, text = "Browse", command = lambda: self.browseFiles("d"))
self.dButton.grid(row = 1, column = 1, sticky = W)
# Label for CSV Path
self.cLabel = Label(self, text = "CSV Path")
self.cLabel.grid(row = 3, column = 0, columnspan = 2, sticky = W)
# Entry for CSV Path
self.cEntry = Entry(self, width = 60)
self.cEntry.grid(row = 4, column = 0, sticky = W)
# Button for CSV Path Directory Browse
self.cButton = Button(self, text = "Browse", command = lambda: self.browseFiles("c"))
self.cButton.grid(row = 4, column = 1, sticky = W)
# Label for Log Path
self.lLabel = Label(self, text = "Log Path")
self.lLabel.grid(row = 6, column = 0, columnspan = 2, sticky = W)
# Entry for Log Path
self.lEntry = Entry(self, width = 60)
self.lEntry.grid(row = 7, column = 0, sticky = W)
# Button for Log Path Directory Browse
self.lButton = Button(self, text = "Browse", command = lambda: self.browseFiles("l"))
self.lButton.grid(row = 7, column = 1, sticky = W)
# Text Box for Results
self.resultText = Text(self, width = 60, height = 30, wrap = WORD, borderwidth = 3, relief = SUNKEN)
self.resultText.grid(row = 9, column = 0, columnspan = 2, sticky = "nsew")
# Scrollbar for Text Box
self.scrollBar = Scrollbar(self, command = self.resultText.yview)
self.scrollBar.grid(row = 9, column = 2, sticky = "nsew")
self.resultText["yscrollcommand"] = self.scrollBar.set
def browseFiles(self, btnCalling):
if(btnCalling == "d"):
self.dName = filedialog.askdirectory(initialdir = "/python3-CH05")
self.dEntry.delete(0, END)
self.dEntry.insert(0, self.dName)
elif(btnCalling == "c"):
self.cName = filedialog.askdirectory(initialdir = "/python3-CH05")
self.cEntry.delete(0, END)
self.cEntry.insert(0, self.cName)
elif(btnCalling == "l"):
self.lName = filedialog.askdirectory(initialdir = "/python3-CH05")
self.lEntry.delete(0, END)
self.lEntry.insert(0, self.lName)
output = extractGPS(self.dName, self.cName, self.lName)
self.resultText.delete(0.0, END)
self.resultText.insert(0.0, output)
# Start the GUI
root = Tk( )
root.title("Python gpsExtractor")
root.geometry("650x650")
app = Application(root)
root.mainloop( )
I'm trying to add items to the listbox, but every time I try it, it's saying that the global name "title_input" is not defined. I don't understand why this doesn't work, because the last one that I did with this exact same structure didn't give me that error. I'm new to this, and the other tutorials and questions I read about global name errors didn't make sense to me. Thanks for the help!
from Tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
self.list = Listbox(self, selectmode=BROWSE)
self.list.grid(row = 1, column = 4, rowspan = 10, columnspan = 3, sticky = W, padx = 5, pady = 5)
def create_widgets(self):
#setlist box - may not stay text box?
self.setlist = Text(self, height = 14, width = 25)
self.setlist.grid(row = 1, column = 0, rowspan = 10, columnspan = 3, sticky = W, padx = 5, pady = 5)
self.setlistLabel = Label(self, text = "SetList")
self.setlistLabel.grid(row = 0, column = 1, sticky = W, padx = 5, pady = 5)
#Library label
self.libraryLabel = Label(self, text = "Library")
self.libraryLabel.grid(row = 0, column = 5, sticky = W, padx = 5, pady y = 5)
#Library button/input
self.add_title = Button(self, text = "Add Title", command = self.add_item)
self.add_title.grid(row = 16, column = 5, sticky = W, padx = 5, pady = 5)
self.title_input = Entry(self)
self.title_input.grid(row = 16, column = 4, sticky = W, padx = 5, pady = 5)
def add_item(self):
list.insert(END, title_input.get())
def get_list(event):
index = list.curselection()[0]
seltext = list.get(index)
setlist.insert(0, seltext)
root = Tk()
root.title("SetList Creator")
root.geometry("500x500")
app = Application (root)
root.mainloop()
title_input is defined in your instance namespace but it is not defined in your global namespace. When you reference an unqualified title_input in your class method add_item, Python looks for title_input in the global namespace. When it doesn't find it there it gives you that error. Adding the self qualifier, self.title_input, to indicate that you wish to reference title_input in the instance namespace, will resolve the error.
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.