Running into problems with class inheritance an tkinter listBox insert - python

I am currently trying to make a simple Jukebox/Music Player in Python and ran into some concerns with class inheritance and tkinter's listBox method.
I have to two classes JukeboxGUI and JukeboxContent (the content one is incomplete). The JukeboxContent class inherits the JukeboxGUI:
import os
import pygame
#from PIL import Image
from tkinter.filedialog import askdirectory
from tkinter import *
import eyed3
class JukeboxGUI:
def __init__(self, window):
self.photo = PhotoImage(file = "//Users//nukhbahmajid//Desktop//Jukebox//background2.gif")
self.canvas = Canvas(width = 1000, height = 1000, bg = "black")
self.label = Label(self.canvas, text = "Jukebox")
self.listBox = Listbox(self.canvas)
self.playPauseButton = Button(self.canvas, text = "Play / Pause")
self.nextButton = Button(self.canvas, text = "Next Song")
self.previousButton = Button(self.canvas, text = "Previous Song")
self.stopButton = Button(self.canvas, text = "Stop")
self.labelVar = StringVar()
self.songLabel = Label(self.canvas, textvariable = self.labelVar, width = 20)
def constructButtons(self):
self.canvas.pack()
self.canvas.create_image(0,0, image = self.photo, anchor = NW)
self.label = self.canvas.create_window(325, 40, anchor = NW, window = self.label)
self.listBox = self.canvas.create_window(270, 80, anchor = NW, window = self.listBox)
self.playPauseButton = self.canvas.create_window(110, 120, anchor = NW, window = self.playPauseButton)
self.nextButton = self.canvas.create_window(500, 120, anchor = NW, window = self.nextButton)
self.previousButton = self.canvas.create_window(500, 180, anchor = NW, window = self.previousButton)
self.stopButton = self.canvas.create_window(130, 183, anchor = NW, window = self.stopButton)
self.songLabel = self.canvas.create_window(268, 268, anchor = NW, window = self.songLabel)
class JukeboxContent(JukeboxGUI):
def __init__(self, window):
#JukeboxGUI.__init__(self, window)
super(JukeboxContent, self).__init__(window)
listOfSongs = []
songTitles = []
num_songs = len(songTitles)
self.index = 1
self.listOfSongs = listOfSongs
self.songTitles = songTitles
self.directoryAsk = askdirectory()
self.num_songs = num_songs
self.Error_NoMP3s = "No \".mp3\" files found."
def directoryChooser(self):
self.directoryAsk
os.chdir(self.directoryAsk)
for files in os.listdir(self.directoryAsk):
if files.endswith(".mp3"):
realdir = os.path.realpath(files)
audioTag = eyed3.load(realdir)
self.songTitles.append(audioTag.tag.title)
self.listOfSongs.append(files)
print(files) ## comment out or remove later
print("These are the Song titles:", self.songTitles) #check if the list gets appended
for items in self.songTitles:
self.listBox.insert(END, items) ## the list doesn't get inserted into the listbox
pygame.mixer.init()
pygame.mixer.music.load(self.listOfSongs[0])
self.labelVar.set(self.songTitles[0])
print("The label variable:", self.labelVar) ## the variable isn't set either
print("The label is accessible:", self.songLabel) ## songLabel doesn't get updated
pygame.mixer.music.play() # the song doesn't play
if __name__ == "__main__":
window = Tk()
window.geometry("700x500+450+200")
window.title("Jukebox")
constructGUI = JukeboxGUI(window)
constructGUI.constructButtons()
initiateJukebox = JukeboxContent(window)
initiateJukebox.directoryChooser()
window.mainloop()
When I try to access the attributes of the parent class, like inserting the songs into the list box, there isn't an error here specifically, but the list isn't into the box either
Secondly, when I update the label variable and songLabel, and try to print out later to see if it was implemented, the following gets printed to the terminal:
The label variable: PY_VAR1
The label is accessible: .!canvas2.!label2
The song doesn't play either. What could be the problem? Please help me out! Here's a picture of the interface if it helps:
JukeboxInterface

Related

Linked data from database to a button tkinter

I am working on a project on tkinter python.
This is how my graphic interface looks like:
And I have this database.txt:
ChickenCurry,Rice,Curry,Chicken,0.ppm
ChocolateCake,Chocolate,Flour,Sugar,Eggs,1.ppm
BolognesePasta,Pasta,Beef,TomatoeSauce,Cheese,2.ppm
Really simple. 0.ppm, 1.ppm and 2.ppm are the name of 3 images, the first one is the image of chicken curry the second one of chocolate and the last one of bolognese pasta.
My project: I would like to display the image of the chicken dish when I am clicking on the button ChickenCurry, the image of the chocolate cake when I am clicking on the chocolate cake, etc...
Here is my code:
import sys
from tkinter import *
import tkinter as tk
from PIL import Image
class Application(tk.Frame):
x = 2
def __init__(self, param = None, i = None, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
if (self.x == 2):
param = "coucou"
self.hi_there = tk.Label(self)
self.hi_there["text"] = param
#self.hi_there["command"] = self.say_hi
self.hi_there.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red",
command=self.master.destroy)
self.quit.pack(side="bottom")
# Opening file in read format
File = open('data.txt',"r")
if(File == None):
print("File Not Found..")
else:
while(True):
# extracting data from records
record = File.readline()
if (record == ''): break
data = record.split(',')
print('Name of the dish:', data[0])
self.hi_there = tk.Button(self)
self.hi_there["text"] = data[0]
self.hi_there["command"] = self.photoOfTheDish
self.hi_there.pack(side="top")
# printing each record's data in organised form
for i in range(1, len(data)-1):
print('Ingredients:',data[i])
self.hi_there = tk.Label(self)
self.hi_there["text"] = data[i]
self.hi_there.pack(side="top")
File.close()
def photoOfTheDish(self):
novi = Toplevel()
self.canvas = Canvas(novi, width = 1500, height = 1000)
self.canvas.pack(expand = YES, fill = BOTH)
File = open('data.txt',"r")
with open('data.txt') as f:
record = File.readline()
data = record.split(',')
gif1 = PhotoImage(file = data[-1].rstrip('\n'))
#image not visual
self.canvas.create_image(50, 10, image = gif1, anchor = NW)
#assigned the gif1 to the canvas object
self.canvas.gif1 = gif1
root = tk.Tk()
root.geometry("5000x2000")
app = Application(master=root)
app.mainloop()
My issue is whatever the button I am clicking on, it's always the image corresponding to "0.ppm" which is displaying. I don't know how to link the button to his set of value from the database.
Inside photoOfTheDish(), you open data.txt and read only the first line to get the image filename. Therefore you always get the 0.ppm.
You can use lambda to pass the image filename to photoOfTheDish() when creating the buttons:
def create_widgets(self):
...
else:
while True:
...
# extracting data from records
record = File.readline().rstrip() # strip out the trailing newline
...
# pass image filename to callback
self.hi_there["command"] = lambda image=data[-1]: self.photoOfTheDish(image)
...
...
def photoOfTheDish(self, image):
novi = Toplevel()
self.canvas = Canvas(novi, width = 1500, height = 1000)
self.canvas.pack(expand = YES, fill = BOTH)
self.canvas.gif1 = PhotoImage(file=image)
self.canvas.create_image(50, 10, image=self.canvas.gif1, anchor=NW)

Tkinter need a Button to change background color when pointer on and pointer off

I have a Python Tkinter Windows program with many buttons. I need a button to change its background color forth and back when the pointer is on it and off it. This issue has been dicussed here before, and I tried to use the code snippets given to solve my problem but did not succeed. The best solution for me would be such that the method would be on such a level that it is needed only once. In my program the user can define the background color for the buttons, however similar to all, and the pointer-on color should be able to be affected by the choice.
Below a minimal code where I have tried to use bind. randint simulates user choice. But, as said, it does not work. What changes do I require? I am new with Python and Tkinter, so please give your answer as clear changes to the code below.
import tkinter as tk
from random import randint
class PointerOnOff:
def __init__ (self, root):
root.geometry ("200x140+100+100")
color = randint (0, 2)
if color == 0:
off_color = "#aaffaa"
on_color = "#99ff99"
elif color == 1:
off_color = "#ffffaa"
on_color = "#ffff99"
else:
off_color = "#ffaaaa"
on_color = "#ff9999"
self.OK = tk.Button (root, text = "OK", bg = off_color, command = self.OKPush)
self.OK.place (x = 50, y = 20, width = 100, height = 30)
self.Cancel = tk.Button (root, text = "Cancel", bg = off_color, command = self.CancelPush)
self.Cancel.place (x = 50, y = 60, width = 100, height = 30)
self.PushedButton = tk.Label (root, text = "")
self.PushedButton.place (x = 20, y = 100, width = 160, height = 30)
def on_enter (anybutton):
anybutton.widget.config (bg = on_color)
def on_leave (anybutton):
anybutton.widget.config (bg = off_color)
self.OK.bind("<Enter>", on_enter)
self.OK.bind("<Leave>", on_leave)
self.Cancel.bind("<Enter>", on_enter)
self.Cancel.bind("<Leave>", on_leave)
def OKPush (self):
self.PushedButton.config (text = "You pushed OK button")
def CancelPush (self):
self.PushedButton.config (text = "You pushed Cancel button")
root = tk.Tk ()
master = PointerOnOff (root)
root.mainloop ()
I'm python beginner and I'm not sure of my answer but the code for changing the background color is this in my opinion:
from tkinter import *
from random import randint
t = Tk()
t.geometry('200x200')
def change_bg():
color = ("#" + str(randint(100000, 999999)))
f = Frame(t, bg=color)
f.place(x=0, y=0, width=200, height=200)
The issue is due to incorrect indentation of the two functions: on_enter() and on_leave(). They need to be inner functions inside __init__():
class PointerOnOff:
def __init__ (self, root):
...
self.PushedButton = tk.Label (root, text = "")
self.PushedButton.place (x = 20, y = 100, width = 160, height = 30)
def on_enter (anybutton):
anybutton.widget.config (bg = on_color)
def on_leave (anybutton):
anybutton.widget.config (bg = off_color)
self.OK.bind("<Enter>", on_enter)
self.OK.bind("<Leave>", on_leave)
self.Cancel.bind("<Enter>", on_enter)
self.Cancel.bind("<Leave>", on_leave)
If you don't want to call the two bindings for every button, you better create a custom button class to embed the hover feature:
class HoverButton(tk.Button):
_colors = [
# off # on
('#aaffaa', '#99ff99'),
('#ffffaa', '#ffff99'),
('#ffaaaa', '#ff9999'),
]
def __init__(self, master=None, *args, **kw):
# if "colors" option not provided, use random choice from internal colors
self._off_color, self._on_color = kw.pop("colors", self._colors[randint(0, 2)])
super().__init__(master, *args, **kw)
self["bg"] = self._off_color
self.bind("<Enter>", lambda e: self.config(bg=self._on_color))
self.bind("<Leave>", lambda e: self.config(bg=self._off_color))
Then use this custom button class for those buttons you want to have hover effect:
def class PointOnOff:
def __init___(self, root):
...
self.OK = HoverButton(root, text="OK", colors=("orange", "gold"), command=self.OKPush)
self.OK.place(x=50, y=20, width=100, height=30)
self.Cancel = HoverButton(root, text="Cancel", command=self.CancelPush)
self.Cancel.place(x=50, y=60, width=100, height=30)
...

is there a way to grid an extra button while running your program in tkinter correctly?

I'm making an mp3 player app and I want the user to be able to add playlists (which will be buttons in a grid system.
Like so.
However in this state when I'm trying to add a playlist button this happens:
The top buttons and the button i just added get squeezed off and the scrollbar is stuck (I can't use it)
I've tried refreshing by self.playlist_frame.update_idletasks() after running create_playlists() but it doesn't seem to change anything
this is my code so you can test it:
import os
import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
class MyApp:
def __init__(self):
self.root = tk.Tk()
self.width = self.root.winfo_screenwidth()
self.height = self.root.winfo_screenheight()
self.height = self.root.winfo_screenheight() - int(self.height / 13)
self.root.geometry(f'{self.width}x{self.height}')
self.root.title("Mp3")
self.c = '#14141D'
self.playlists_buttons_list = []
self.playlists = {}
self.helping_d = {}
self.main = ttk.Notebook(self.root)
self.playlists_tab = tk.Frame(self.main)
self.playlist_menu_frame = tk.Frame(self.playlists_tab, bg=self.c)
self.playlists_canvas = tk.Canvas(self.playlists_tab, bg=self.c)
self.playlist_frame = tk.Frame(self.playlists_canvas, bg=self.c)
self.playlists_scrollbar = ttk.Scrollbar(self.playlists_tab, orient='vertical',
command=self.playlists_canvas.yview)
self.add_playlist_win = tk.Toplevel(self.root)
self.add_playlists_button = tk.Button(self.playlist_frame)
self.default_img = Image.open('images/default.png').resize((75, 72))
self.default_img = ImageTk.PhotoImage(self.default_img)
self.add_img = Image.open('images/add.png').resize((50, 50))
self.add_img = ImageTk.PhotoImage(self.add_img)
self.widgets()
self.root.mainloop()
def widgets(self):
self.playlists_tab.place(height=self.height, width=self.width, x=0, y=0)
self.main.add(self.playlists_tab, text="Playlists")
self.main.pack(expand=1, fill="both")
self.playlist_frame = tk.Frame(self.playlists_canvas, bg=self.c)
self.playlists_canvas.create_window((0, 0), window=self.playlist_frame, anchor='center')
self.playlists_canvas.config(bg=self.c)
self.playlists_canvas.place(height=int(self.height / 1.428), width=self.width, x=0, y=int(self.height / 9))
self.add_playlists_button = tk.Button(self.playlists_canvas, image=self.add_img, bg=self.c, bd=0,
command=self.add_playlists)
self.add_playlists_button.place(x=1284, y=75)
self.playlists_scrollbar.pack(side='right', fill='y')
self.playlists_canvas.config(yscrollcommand=self.playlists_scrollbar.set)
self.playlists_canvas.bind('<Configure>', lambda e: self.playlists_canvas.configure(
scrollregion=self.playlists_canvas.bbox('all')))
if os.path.getsize('playlistsnames.txt') != 0:
lines = open('playlistsnames.txt', 'r', encoding='utf-8').read().splitlines()
for i in lines:
self.playlists[i] = []
self.create_playlists()
def create_playlists(self):
self.playlists_buttons_list = []
for i in range(len(self.playlists.keys())):
self.playlists_buttons_list.append(tk.Button(self.playlist_frame, bg=self.c,
text=' ' + list(self.playlists.keys())[i].split('!')[0],
fg='white', image=self.default_img, height=280, width=300))
row = 0
column = 0
for i in self.playlists_buttons_list:
if column > 3:
row += 1
column = 0
if column > 7:
row += 1
column = 0
i.grid(row=row, column=column)
column += 1
def get_name(self):
self.name_of_plst = self.plst_entry.get()
self.playlists[self.name_of_plst] = []
self.create_playlists()
with open('playlistsnames.txt', 'a', encoding='utf-8') as names_file:
names_file.write(self.name_of_plst + '!\n')
def add_playlists(self):
self.add_playlist_win = tk.Toplevel(self.root)
self.name_label = tk.Label(self.add_playlist_win, text='Name:', bg=self.c, fg='pink').pack()
self.plst_entry = tk.Entry(self.add_playlist_win)
self.plst_entry.pack()
self.confirm_btn = tk.Button(self.add_playlist_win, text='Confirm', bg=self.c, fg='pink',
command=self.get_name).pack()
self.add_playlist_win.mainloop()
MyApp()
I should also mention that because I store the playlist names in a file called playlistnames.txt when I rerun the program I can see all the playlist buttons plus the one I created before and things work just fine.
So what I want is making the grid update and work while running the app without having to rerun the app of course
My playlistsnames.txt file has this format:
rock!
metal!
chill!
rap!
jazz!
blues!
hard rock!
trap!
Any suggestions would be helpful!
Thanks in advance!

Python 2: Replace word in string with icon image.

I am trying to create a weather application. I have a section of code that retrieved weather information from DarkSkyAPI for the next 7 days. The String that is print out looks like Sat clear-day 10. What I am trying to do is display the text I'm a label but replace the clear-sky section of the string for the clear-sky icon I have.
Format I am looking for is Sat {icon} 10
from Tkinter import *
from datetime import timedelta, datetime
from PIL import Image, ImageTk
import requests
import json
## Location of Icons used
icon_lookup = {
'clear-day' : "Icons/WeatherIcons/WeatherIcon.png",
}
class Weather(Frame):
def __init__(self, parent, *args, **kwargs):
Frame.__init__(self, parent, bg = 'black')
self.iconLbl = Label(self, bg="black")
self.iconLbl.grid(row = 0, column = 1, sticky = W)
self.icon = ''
self.get_weather()
def get_weather(self):
try:
## Get Week's Weather Values
todayPlusOne = 'Sat clear-day 10'
## Get Icon
icon_id = 'clear-day'
icon2 = None
if icon_id in icon_lookup:
icon2 = icon_lookup[icon_id]
if icon2 is not None:
if self.icon != icon2:
self.icon = icon2
image = Image.open(icon2)
image = image.resize((100, 100), Image.ANTIALIAS)
image = image.convert('RGB')
photo = ImageTk.PhotoImage(image)
self.iconLbl.config(image=photo)
self.iconLbl.image = photo
else:
self.iconLbl.config(image='')
except Exception as e:
print "Error: %s. Cannot get weather." % e
self.after(900000, self.get_weather)
class FullscreenWindow:
def __init__(self):
self.tk = Tk()
self.tk.configure(background='black')
self.topFrame = Frame(self.tk, background = 'black', height = 240)
self.middleFrame = Frame(self.tk, background = 'black', height = 240)
self.bottomFrame = Frame(self.tk, background = 'black', height = 240)
self.topFrame.pack(side = TOP, fill = BOTH)
self.middleFrame.pack(side = TOP, fill = BOTH)
self.bottomFrame.pack(side = TOP, fill = BOTH)
self.state = False
self.tk.bind('<Return>', self.toggle_fullscreen)
#weather
self.weather = Weather(self.topFrame)
self.weather.pack(side = LEFT, anchor = NW, padx = 25, pady = 25)
def toggle_fullscreen(self, event=None):
self.state = not self.state
self.tk.attributes('-fullscreen', self.state)
return 'break'
if __name__ == '__main__':
w = FullscreenWindow()
w.tk.resizable(width=False, height=False)
w.tk.geometry('720x480')
w.tk.mainloop()
Is this possible to do?
You cannot put an image in the middle of text in a label; you can only put an image on one side (top, bottom, left, right) or centered. To have both text and an image you need to use the compound attribute of the label.
To have an image in the middle of text, there are at least three options:
create a frame with a label for the text, a label for the icon, and another label for more text
use a canvas, and create text and image items on the canvas
use a one-line text widget, which supports embedded images.

PIL/tkinter - updating label image with button images

I'm trying to implement my simple image viewer, where I have one main label and menubutton with three choices. Each of them creates different numbers of buttons with pictures inside them. I would like create one main label and then update its image with images on the buttons. So when I click on the first button with image, that image will appear on the label, then click second button and that second image will appear and so on. I've tried to create two functions one for creating label and updating its image and the second for getting current image on the button, but I wasn't able to do the second one correctly. Appreciate your help. Here's the code:
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
from functools import partial
from PIL import Image, ImageTk
class Halabala():
def __init__(self):
self.master = tk.Tk()
self.master.geometry("1100x700")
self.pictures = ["pavuk1.gif", "pavuk2.gif", "pavuk3.gif"]
self.pictures2 = ["cukor1.gif", "cukor2.gif", "cukor3.gif", "cukor4.gif", "cukor5.gif"]
self.lists_images = []
self.lists_images2 = []
self.init_image_list()
self.lists_labels = []
#self.main_label = tk.Label(self.master, image = None).grid(row = 0, column = 0)
#image with original size
self.rbutton = tk.Menubutton(self.master, text = "Choose picture")
self.picks2 = tk.Menu(self.rbutton)
self.rbutton.config(menu=self.picks2)
self.picks2.add_command(label = "Spider", command = partial(self.create_labels,3))
self.picks2.add_command(label = "Sugar", command = partial(self.create_labels,5))
self.rbutton.config(width = 30, bg = "white", bd = 5, relief = tk.RAISED)
self.rbutton.place(x = 900, y = 30)
self.master.mainloop()
def init_image_list(self):
for i in self.pictures:
picture = Image.open(i)
picture.thumbnail((130, 130))
self.lists_images.append(ImageTk.PhotoImage(picture))
for i in self.pictures2:
picture = Image.open(i)
picture.thumbnail((130, 130))
self.lists_images2.append(ImageTk.PhotoImage(picture))
def create_labels(self, num):
for label in self.lists_labels:
label.destroy()
self.lists_labels=[]
for i in range(num):
if num == 3:
but = tk.Button(self.master, image = self.lists_images[i]) #command = self.get_command
but.grid(row = 2, column = i + 1) #label will be in the first row
self.lists_labels.append(but)
else:
but = tk.Button(self.master, image = self.lists_images2[i])
but.grid(row = 2, column = i + 1)
self.lists_labels.append(but)
#def get_command(self):
#self.main_label = tk.Label(self.master, image = self.get_image).grid(row = 0, column = 0)
#def get_image(self):
# don't know how to get current image from button
myapp = Halabala()

Categories