Toplevel() and Label out put from For loop - Python 2 - python

I want to create a gui sub window that could look like this, which lists a live feedback for the top teams and also giving them a numbering.
So I have done for loop function to number them and Label them out, which works fine when run with nothing but the code but I'm having trouble making it run on the new window that is opened from main window.
import io
import base64
import Tkinter as tk
from Tkinter import *
from re import findall
from urllib2 import urlopen
def epl_Window():
epl = tk.Toplevel()
epl.title('Top Ten EPL Team 2016')
url = "http://i.imgur.com/3znCRqH.gif"
image_byte1 = urlopen(url).read()
data_stream1 = io.BytesIO(image_byte1)
pil_image1 = Image.open(data_stream1)
w, h = pil_image.size
tk_image1 = ImageTk.PhotoImage(pil_image1)
label1 = tk.Label(epl, image=tk_image1, bg='black')
label1.pack(padx=5, pady=5)
epl.geometry("500x700")
for index, value in enumerate(EPL_10, start=1):
Label(epl, text=str(index)).grid(row=index, column=1, sticky='W')
Label(epl, text=value).grid(row=index, column=2, sticky='W')
epl.mainloop()
root = tk.Tk()
root.title("Top Ten Lists")
url = "http://i.imgur.com/H1sURuR.gif"
image_bytes = urlopen(url).read()
# internal data file
data_stream = io.BytesIO(image_bytes)
# open as a PIL image object
pil_image = Image.open(data_stream)
# optionally show image info
# get the size of the image
w, h = pil_image.size
### convert PIL image object to Tkinter PhotoImage object
tk_image = ImageTk.PhotoImage(pil_image)
# put the image on a typical widget
label = tk.Label(root, image=tk_image, bg='brown')
label.pack(padx=5, pady=5)
#BUTTON
EPL_B = Button(root, text='EPL Teams', width=10, command=epl_Window)
EPL_B.pack(anchor = "w", side = LEFT)
#EPL RANK
url = 'http://www.bbc.com/sport/football/premier-league/table'
EPL_contents = urlopen(url).read()
EPL_Ranking = findall("'>(\w* ?\w*)</a>", EPL_contents)
EPL_10= EPL_Ranking[:10]
root.mainloop()
I think there is problem with def new window toplevel() but not sure how to change it to load. Running it make program crash

So it crashes when you click on the button which opens the TopLevel?
Without a traceback this is very difficult to answer, but my guess is that the line
epl.mainloop()
causes the crash. Even if it doesn't, you don't need to call it. There is usually only one mainloop at a time on your root widget.

Related

Frame in Tkinter Popup Putting Content into Main Window instead of Popup

I am trying to create an app using the Tkinter Python library, and I created a preferences popup. I want to add checkboxes to it, and I want to do it in Frames via pack().
I want something like this:
Expected Result (IK it's Edited but Proof of Concept)
This is what I'm getting:
Actual Result (Look at Bottom of Image)
This is what I wrote:
# Import Libraries
from tkinter import *
from tkinter import ttk
from tkinter import simpledialog, messagebox
from tkinter.filedialog import asksaveasfile
from pygame import mixer as playsound
from datetime import datetime as date
from time import sleep
import pyttsx3
import json
import os
# Set Initial Window
window = Tk()
window.title("TTSApp")
window.geometry('500x580')
window.resizable(width=False,height=False)
playsound.init()
# Settings and Menu
preferences = {}
def preferencesHandler():
if os.path.exists('preferences.pref'):
preferences = {'AutoSave':True,'AutoSavePrompt':True,'AutoSaveAutomaticLoad':False}
with open('preferences.pref', 'w') as pref:
json.dump(preferences, pref)
else:
preferences = json.load(open('preferences.pref', 'r'))
pref.close()
sessionOptions = {'SessionName':'Untitled','VoiceSpeed':100}
def topmenucommands_file_newsession():
messagebox.showerror("New Session", "I haven't done this yet... you shouldn't even be able to see this...")
def topmenucommands_file_preferences():
preferencesWin = Toplevel(window)
preferencesWin.geometry("350x500")
preferencesWin.title("Preferences")
preferences_autosave = BooleanVar()
preferences_autosaveprompt = BooleanVar()
preferences_autosaveautomaticload = BooleanVar()
def topmenucommands_file_preferences_changed(*args):
with open('preferences.pref') as pref:
preferences['AutoSave'] = preferences_autosave.get()
preferences['AutoSavePrompt'] = preferences_autosaveprompt.get()
preferences['AutoSaveAutomaticLoad'] = preferences_autosaveautomaticload.get()
json.dump(preferences, pref)
pref.close()
Label(preferencesWin, text="Preferences", font=('helvetica', 24, 'bold')).pack()
autosave_container = Frame(preferencesWin,width=350).pack()
Label(autosave_container, text="Create Autosaves:", font=('helvetica', 12, 'bold')).pack(side=LEFT)
ttk.Checkbutton(autosave_container,command=topmenucommands_file_preferences_changed,variable=preferences_autosave,onvalue=True,offvalue=False).pack(side=RIGHT)
window.wait_window(preferencesWin)
pref.close()
def topmenucommands_session_renamesession():
topmenucommands_session_renamesession_value = simpledialog.askstring(title="Rename Session",prompt="New Session Name:")
sessionOptions['SessionName'] = topmenucommands_session_renamesession_value
topmenu = Menu(window)
topmenu_file = Menu(topmenu, tearoff=0)
#topmenu_file.add_command(label="New Session")
#topmenu_file.add_command(label="Save Session")
#topmenu_file.add_command(label="Save Session As...")
topmenu_file.add_command(label="Preferences", command=topmenucommands_file_preferences)
topmenu.add_cascade(label="File", menu=topmenu_file)
topmenu_session = Menu(topmenu, tearoff=0)
topmenu_session.add_command(label="Rename Session", command=topmenucommands_session_renamesession)
topmenu.add_cascade(label="Session", menu=topmenu_session)
# Create All of the Widgets and Buttons and Kiknacks and Whatnot
# Input Window
inputText = Text(window,height=20,width=62)
inputText.pack()
# Label for Speed Slider
speedText = Label(window, text='Voice Speed', fg='black', font=('helvetica', 8, 'bold'))
speedText.pack()
# Speed Slider
speed = Scale(window, from_=50, to=200, length=250, tickinterval=25, orient=HORIZONTAL, command=speedslidersavestate)
speed.set(100)
speed.pack()
# Dropdown for Voice Selection
voice = OptionMenu(window, voiceSelection, *voiceNames.keys())
voice.pack()
# Warning/Notice Label
warning = Label(window, text='', fg='red', font=('helvetica', 12, 'bold'))
warning.pack()
# Container for All Preview and Save (and PreviewRaw)
buttons = Frame(window)
buttons.pack()
# PreviewRaw Button; Huh... There's Nothing Here
# Preview Button
preview = Button(buttons,text='Preview',height=5,width=25,command=preview)
preview.pack(side=LEFT)
# Save Button
save = Button(buttons,text='Save to File',height=5,width=25,command=save)
save.pack(side=RIGHT)
window.config(menu=topmenu)
preferencesHandler()
window.mainloop()
Did I do something wrong or is there a better way to go about this or is this question a mess (this is my first time doing this)? Also, I clipped out all of the unnecessary content.
Edit: Added More Code
I figured it out. Apparently, I needed to pack() the Frame separately.
The answer was:
autosave_container = Frame(preferencesWin,width=350)
autosave_container.pack()
Instead of:
autosave_container = Frame(preferencesWin,width=350).pack()

Refreshing a tkinter window

Code:
import tkinter, urllib.request, json, io
from PIL import Image, ImageTk
main = tkinter.Tk()
main.geometry('500x500+800+300')
dogapi = urllib.request.urlopen(f'https://dog.ceo/api/breeds/image/random')
dogjson = dogapi.read()
dogdict = json.loads(dogjson)
url=dogdict['message']
m = urllib.request.urlopen(url)
mp = io.BytesIO(m.read())
mpi = Image.open(mp)
tkimg = ImageTk.PhotoImage(mpi)
l = tkinter.Label(main, image=tkimg)
b = tkinter.Button(main, text='Next Dog', command='do something to refresh the dog photo')
l.pack()
main.mainloop()
I have this code that gets a random dog photo and loads it in to a window, as well as a button.
This works fine but the "Next Dog" button doesn't actually do anything, and the dog photo almost never matches up with the window. How could I add functionality to the button, and make the dog photo size consistent?
You can put the fetching of the dog image in a function and update the image of the label inside the function. Then assign this function to the command option of the button.
import tkinter, urllib.request, json, io
from PIL import Image, ImageTk
main = tkinter.Tk()
main.geometry('500x500+800+300')
# maximum size of image
W, H = 500, 460
# resize image but keeping the aspect ratio
def resize_image(img):
ratio = min(W/img.width, H/img.height)
return img.resize((int(img.width*ratio), int(img.height*ratio)), Image.ANTIALIAS)
def fetch_image():
dogapi = urllib.request.urlopen(f'https://dog.ceo/api/breeds/image/random')
dogjson = dogapi.read()
dogdict = json.loads(dogjson)
url = dogdict['message']
m = urllib.request.urlopen(url)
mpi = resize_image(Image.open(m))
tkimg = ImageTk.PhotoImage(mpi)
l.config(image=tkimg) # show the image
l.image = tkimg # save a reference of the image to avoid garbage collection
# label to show the image
l = tkinter.Label(main, image=tkinter.PhotoImage(), width=W, height=H)
b = tkinter.Button(main, text='Next Dog', command=fetch_image)
l.pack()
b.pack()
fetch_image() # fetch first image
main.mainloop()

How to make a button with the name of a file and also call that file?

So I am trying to make a sort of journal program where you can create an entry that is then saved as a text file. I currently have it set up so you can recall an entry by typing in the file name and clicking load, but I want to make a list of buttons on the right side that has all of the file names and then will load the respective file when clicked, any suggestions?
Here is my code:
from cProfile import label
from cgitb import text
from email.quoprimime import quote
import tkinter as tk
from tkinter import *
from tkinter import ttk
import tkinter
from traceback import print_tb
import os
from pip import main
def open_main():
#instantiate main screen
mainscreen = tk.Tk()
mainscreen.state("zoomed")
mainscreen.title("Welcome")
#file name text box
filename = tk.Entry(mainscreen)
filename.place(relx=.5, rely=.1, anchor=CENTER)
#save entry function
def save_entry():
savefile = open("%s .txt" % filename.get(), "w+")
savefile.write(T.get("1.0","end"))
savefile.close
refresh()
#load entry function
def loadentry():
loadentry = open("%s .txt" % filename.get(), "r")
quote = loadentry.readlines()
T.delete("1.0", END)
T.insert(END, quote)
#create frame to place main text box
mainframe = tkinter.Frame(mainscreen)
mainframe.place(relwidth=.65, relheight=.75, relx=.05, rely=.5, anchor=W)
#label the file name text box
tk.Label(mainscreen, text="Make an Entry:").place(relx=.5, rely=.035, anchor=CENTER)
tk.Label(mainscreen, text="Date: MMDDYYYY").place(relx=.5, rely=.07, anchor=CENTER)
#create main text box within the main frame
S = Scrollbar(mainframe)
T = Text(mainframe)
S.pack(side=RIGHT, fill=Y)
T.pack(side=LEFT, expand=True, fill=BOTH)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
#create second frame next to main frame to hold buttons
sideframe = tkinter.Frame(mainscreen)
sideframe.place(relwidth=.2, relheight=.75, relx=.7, rely=.5, anchor=W)
side_bar = Scrollbar(sideframe)
side_box = Text(sideframe)
side_bar.pack(side=RIGHT, fill=Y)
side_box.pack(side=LEFT, expand=True, fill=BOTH)
#create and load buttons
def loadbutton(item):
bfilename = item
bfileentry = open(bfilename, "r")
bquote = bfileentry.readlines()
T.delete("1.0",END)
T.insert(END,bquote)
#add buttons to box initially
entry_initate = [f for f in os.listdir(os.getcwd()) if f.endswith('.txt')]
for item in entry_initate:
mybutton = Button(side_box, text=item, command = lambda m = item: loadbutton(item))
mybutton.pack(fill=BOTH)
#refresh buttons when a new entry is saved
def refresh():
entry_raw = [f for f in os.listdir(os.getcwd()) if f.endswith('.txt')]
for item in entry_raw:
mybutton = Button(side_box, text=item, command = lambda m = item: loadbutton(item))
mybutton.pack(fill=BOTH)
list = side_box.slaves()
for l in list:
l.destroy()
for item in entry_raw:
mybutton = Button(side_box, text=item, command = lambda m = item: loadbutton(item))
mybutton.pack(fill=BOTH)
#Save and load entry buttons
Button(mainscreen, text="Save Entry", command=save_entry).place(relx=.5, rely=.9, anchor=CENTER)
Button(mainscreen, text="Load Entry", command=loadentry).place(relx=.5, rely=.95, anchor=CENTER)
mainscreen.mainloop()
I currently just have the side box just commented out, it was originally just a text box that had the file names listed in it.
Sorry if its a little messy, im still pretty new to python.
You should use variable loadfileb instead of button_press on .readlines() inside loadbutton(). Also use read() instead of readlines() and you need to insert the read content into text box.
def loadbutton(button_press):
with open(button_press, "r") as loadfileb:
quote = loadfileb.read()
T.delete('1.0', 'end')
T.insert('end', quote)
for item in entry_raw:
tk.Button(sideframe, text=item, command=lambda m=item: loadbutton(m)).pack()
Note that there are different way to initiate widgets, like tk.Entry(...), tkinter.Frame(...) and Button(...) in your code. So I think you have imported tkinter like below:
import tkinter
from tkinter import *
import tkinter as tk
Recommend to use import tkinter as tk only.

Python Tkinter - Error with widgets - TclError: expected integer but got "New"

I'm following a basic Tkinter tutorial and I have followed it pretty much exactly but have used my minimal previous knowledge of Tkinter also. However, every time I have run it, I seem to be getting an error, but only with widgets.
The error message is:
self.tk.call(_tkinter.TclError: expected integer but got "New"
According to the error message, it is when I assign Label(head) to lbl_logo on line 46.
As I am doing this in college, I have to follow the tutorial which is why some of it could be reduced, ie: using .config
# Libraries
from tkinter import *
# generates password
class password_generator:
def __init__(self):
pass
# Window
class window():
def __init__(self):
# initial setup
self.title('Safe G - The Password Generator')
self.geometry('1600x900+100+100') # width (w), height (h), x-start-position (x), y-start-position (y)
self.configure(bg='gray20')
self.iconbitmap('safeg_icon.ico')
# initial defaults
self.option_add('*Font', 'Courier New')
self.option_add('*Background', 'gray20')
self.option_add('*Label.Font', 'Courier New')
# constructs header
head = Frame(self, highlightthickness=5, highlightbackground='tomato2')
head.pack(fill='both', expand=True)
# HEADER - logo
img = PhotoImage(file='file.gif') # isn't actually called file.gif, but is a .gif file
lbl_logo = Label(head)
lbl_logo.config(image = img)
lbl_logo.image = img
lbl_logo.pack(side=LEFT, padx=10, pady=10)
# HEADER - title
lbl_title = Label(head)
lbl_title.config(text='Safe G - The Password Generator', font=('Courier New 20'))
lbl_title.pack(side=LEFT, padx=10, pady=10)
# constructs main body
body = Frame(self, highlightthickness=5, highlightbackground='orange2')
body.pack(fill='both', expand=True)
# constructs footer
foot = Frame(self, highlightthickness=5, highlightbackground='gold')
foot.pack(fill='both', expand=True)
# Initalises program
if __name__ == '__main__':
win = Tk()
window.__init__(win)
win.mainloop()
It seems to work if I comment out any and all references to a label and the image seems to sometimes work if I do it outside the function.

Why isn't an image displaying in tkinter? (Python 2.x)

Alright, I am thoroughly confused.
So I recently started to use the Steam API and I decided to start out something simple, displaying the avatar image of a profile.
Thing is, the program runs with no errors except that it does not display the image.
Here is the code where it shows the image:
def displayImage():
global window
global STEAM_USER
response = urllib2.urlopen('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' + STEAM_API_KEY + '&steamids=' + STEAM_USER + '&format=xml')
htmlSource = response.read()
soup = BeautifulSoup(htmlSource)
avatar = soup.find('avatarfull').getText()
print avatar
image_bytes = urllib2.urlopen(avatar).read()
data_stream = io.BytesIO(image_bytes)
pil_image = Image.open(data_stream)
tk_image = ImageTk.PhotoImage(pil_image)
label = Label(window, image=tk_image)
label.pack(padx=5, pady=5)
And here is the rest of the code:
import urllib2
from Tkinter import *
from PIL import Image, ImageTk
from bs4 import BeautifulSoup
import io
STEAM_API_KEY = 'XXXX'
global window
window = Tk()
window.title('Steam Avatar Viewer')
window.geometry("215x215")
def newUser():
global window
global entry
entry = Entry(window)
button = Button(window, text='Search', width=10, command=getUser)
entry.pack()
button.pack()
def getUser():
global STEAM_USER
global entry
steamUser = entry.get()
steamConverterURL = 'http://www.steamidconverter.com/' + steamUser
steamIDURL = urllib2.urlopen(steamConverterURL)
steamIDSource = steamIDURL.read()
a = BeautifulSoup(steamIDSource)
for hit in a.findAll(attrs={'id':'steamID64'}):
STEAM_USER = hit.contents[0]
print STEAM_USER
displayImage()
def displayImage():
global window
global STEAM_USER
response = urllib2.urlopen('http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' + STEAM_API_KEY + '&steamids=' + STEAM_USER + '&format=xml')
htmlSource = response.read()
soup = BeautifulSoup(htmlSource)
avatar = soup.find('avatarfull').getText()
print avatar
image_bytes = urllib2.urlopen(avatar).read()
data_stream = io.BytesIO(image_bytes)
pil_image = Image.open(data_stream)
tk_image = ImageTk.PhotoImage(pil_image)
label = Label(window, image=tk_image)
label.pack(padx=5, pady=5)
newUser()
window.mainloop()
I believe it is something very simple but I can't figure out what's causing the image not to display.
When you add a PhotoImage or other Image object to a Tkinter widget, you must keep your own reference to the image object. If you don’t, the image won’t always show up.
Here is essentially what I'm trying to say:
photo = PhotoImage(...)
label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()
You can refer to this.
As has already been said, you must ensure you keep a reference to the image around, or else it will be removed by Python's garbage collector. In addition to the above method, the way I first learnt to overcome the issue was to simply append the image to a list, such as:
photo_list=[]
photo = PhotoImage(...)
photo_list.append(photo)
I liked this method at the time because it was obvious what the code was doing ( i.e. storing the picture to prevent it's deletion).
Either way, you must simply ensure your picture is kept around! Good luck :)

Categories