AttributeError: '' object has no attribute '' - python

I have a problem, I was working on a code with python 3. the code is about getting news of a website onto my canvas. however I keep getting this error which says:
AttributeError: 'NewsFeed' object has no attribute 'canvas'.
this is my code:
from tkinter import *
import feedparser
root=Tk()
class Achtergrond() :
m_Width = 0
m_Height = 0
m_BgColor = 0
def CreateCanvas(self, master, width, height) :
m_Width = width
m_Height = height
m_BgColor='#14B4E1'
self.canvas = Canvas(master, width=m_Width, height=m_Height)
self.canvas.configure(bg=m_BgColor)
self.canvas.pack()
return(self.canvas)
def create_rectangle(x0, y0 ,x1,y1, color) :
self.canvas.create_rectangle(x0, y0, x1, y1, fill=color)
return
def create_title (self, x, y, title, opmaak):
self.canvas.create_text(x,y,text=title, font= opmaak)
return
def create_newsbox(master,x0,y0,x1,y1,color):
canvas.create_rectangle(x0,y0,x1,y1, fill=color)
return
def SetBackgroundColor(self, kleurcode) :
m_BgColor = kleurcode
self.canvas.configure(bg=m_BgCode)
self.canvas.pack()
return
class NewsFeed ():
Hitem = 0
Nitem = 0
feed = 0
th = 0
rssURL = ""
def UpdateNews(self,path):
self.rssURL = path
self.feed = feedparser.parse(self.rssURL)
self.Nitem = len(self.feed["items"])
return
def ToonEerste(self):
str=""
self.Hitem = 0
for i in range(self.Hitem,self.Hitem+2,1):
if i < self.Nitem:
entry = self.feed["entries"][i]
str += entry.title + "\n\n" + entry.summary + "\n__________________________________________________\n\n"
self.canvas.delete(th)
th = self.canvas.create_text(200,300, width=300, text = str)
return
def ToonVolgende(self):
str=""
self.Hitem += 3
if self.Hitem >= self.Nitem:
Hitem = 0
for i in range(self.Hitem,self.Hitem+2,1):
if i < self.Nitem:
entry = feed["entries"][i]
str += entry.title + "\n\n" + entry.summary + "\n__________________________________________________\n\n"
self.canvas.delete(th)
th = self.canvas.create_text(200,300, width=300, text = str)
return
hoofdscherm = Achtergrond()
a = hoofdscherm.CreateCanvas(root, 1024,600)
b = hoofdscherm.canvas.create_rectangle(30, 120, 360, 500, fill= '#ffffff')
a.create_rectangle(10,10, 1014,80, fill='#ffffff')
a.create_rectangle(30, 120, 360, 500, fill= '#ffffff')
a.create_text(250, 50, text="Harens Lyceum" , font=('Calibri' , 40))
a.configure(bg='#14B4E1')
a.pack()
n = NewsFeed()
n.UpdateNews('http://www.nu.nl/rss/Algemeen')
n.ToonEerste(root)
n.ToonVolgende(root)
root.mainloop()
We would like to have some help with our problem, we don't have much experience. We need to make a screen with raspberry which displays news etc. for school. If you know how we can fix our code we would very much appreciate your guys' help.

Your NewsFeed class instance n doesn't have a Canvas attribute. If you want to pass the Canvas defined in your Achtergrond class instance hoofdscherm to n, you can define it under the class definition for NewsFeed using __init__():
class NewsFeed ():
def __init__(self, canvas):
self.canvas = canvas
...
Then when you initialize your NewsFeed object as n, you can pass the Canvas instance from your Achtergrond class instance hoofdscherm:
n = NewsFeed(hoofdscherm.canvas)
This is a solution to your current issue, but there are other errors in your code that you can see once you modify it.

Related

How to create a brightness toggle on Python Tkinter

I am creating a brightness toggle on Python. I am using the Tkinter module to create a sider function. I have successfully created a slider to increase/decrease the volume. However, I want to translate this into one where I can increase/decrease the screen's brightness. Here is my volume code and output.
I am currently using macOS Monterey Version 12.2.1.
#The GUI player
import pygame
from pygame import mixer
from tkinter import *
# Makes a new window and stores it inside the root variable.
root = Tk()
mixer.init() # initialising the mixer
# Coding the background music
def play_music():
pygame.mixer.music.load("ArcadeMusic copy.mp3")
pygame.mixer.music.play(-1)
def set_vol(val):
volume = int(val) / 100
mixer.music.set_volume(volume)
root.geometry('300x70')
root.title("Volume")
text = Label(root, text = "Drag the slider to adjust volume")
text.pack()
scale = Scale(root,from_=0,to=100 , orient=HORIZONTAL, command=set_vol)
scale.pack()
play_music()
root.mainloop()
Are you trying to achieve something like this? Or do you want to control desktop brightness?
import tkinter
def find( obj ):
name = f"{type(obj).__name__}:n "
try:
return name + "n ".join( [ f"{x} = '{obj.cget(x)}'" for x in obj.keys() ] )
except:
return f"'{obj}' has no keys attribute"
class brightness:
def __init__( self ):
self.master = tkinter.Tk()
self.master.update_idletasks()
self.color = 15790320 # #f0f0f0 = SystemButtonFace
self.var = tkinter.IntVar( self.master, value = self.color )
self.flexx( self.master )
self.label = tkinter.LabelFrame(
self.master, labelanchor = 'n', text = self.master['background'] )
self.label.grid( row=0, column=0, columnspan=2, sticky='nsew' )
self.flexx( self.label, r=None )
self.flexx( self.label, r=None , c=1 )
self.scroll = tkinter.Scale(
self.label, orient = 'horizontal',
resolution = 65793, label = 'Brightness Control',
from_ = 0, to = 16777215, variable = self.var,
command = self.control )
self.scroll.grid( row = 1, column=0, columnspan=2, sticky='ew' )
self.master.geometry( '200x200' )
self.master.minsize( 334, 113 )
def flexx( self, o, r = 0, c = 0, rw = 1, cw = 1 ):
if r != None:
o.rowconfigure( r, weight = rw )
if c != None:
o.columnconfigure( c, weight = cw )
def convert( self ):
col = '#' + ( '000000' + hex( self.color )[2:])[~5:]
self.var.set( self.color )
self.label['text'] = col
self.master.tk_setPalette( col )
def control_up( self ):
self.color += 65793
if self.color > 16777215:
self.color = 15790320
col = self.convert( )
def control_down( self ):
self.color -= 65793
if self.color < 0: # 15790320:
self.color = 16777215
col = self.convert( )
def control( self, n ):
self.color = int( n )
col = self.convert( )
if __name__ == '__main__':
bright = brightness( )
tkinter.mainloop()

How to set a value in the tkinter slider.set method?

I am trying to simulate a stellar system. I aim to manipulate the parameters via slider widgets, see the (reduced) code below. The slider widget in my code accepts a new value for the sun mass, which was set via a StellarSys instance. However the slider.set method fails with TypeError: 'NoneType' object is not subscriptable. Does somebody have a solution or can explain what I'm doing wrong? Many thanks.
import tkinter as tk
import math
class Space(tk.Frame):
def __init__(self, master, size, bg=None):
super().__init__(master)
frame = tk.Frame(self, border=5)
frame.pack()
self.width, self.height = size
self.canvas = tk.Canvas(frame, width=self.width,height=self.height,
borderwidth=0, highlightthickness=0, bg=bg)
self.canvas.pack()
self.bodies = None
def place_bodies(self):
for body in self.bodies:
x1, y1 = int(body.loc[0]-body.size/2.0),int(body.loc[1]-body.size/2.0)
x2, y2 = x1 + body.size, y1 + body.size
body.tk_id = self.canvas.create_oval(x1, y1, x2, y2, fill=body.color)
class SpaceBody:
def __init__(self, **kwargs):
self.name = kwargs['name']
self.size = kwargs['size']
self.mass = kwargs['mass']
self.loc = kwargs['loc']
self.speed = kwargs['speed']
self.color = kwargs['color']
self.dxdy = (0,0)
self.tk_id = None
def __repr__(self):
return f"\n{self.name} is {self.color}"
class Dashboard(tk.Frame):
def __init__(self, master, bg=None):
super().__init__(master)
frame = tk.Frame(self, border=5, bg=bg)
frame.pack()
sun_frame=tk.Frame(frame)
sun_frame.grid(row=1)
w, h = 15, 3
tk.Label(sun_frame, text = '').grid(row=0)
tk.Label(sun_frame, text = 'SUN MASS').grid(row=1)
self.sun_mass = tk.Scale(sun_frame, from_=0, to=1000, orient='horizontal')
self.sun_mass.bind("<ButtonRelease-1>", self.update)
# self.sun_mass.set(500) # this works
self.sun_mass.set(space.bodies[0].mass) # This doesn't work
self.sun_mass.grid(row=2)
def update(self, event):
space.bodies[0].mass = self.sun_mass.get()
print(space.bodies[0].mass)
class StellarSys:
def __init__(self):
sun = SpaceBody(name='Sun', size=30, mass=500, loc=(500,400),speed=(0, 0), color='yellow')
earth = SpaceBody(name='Earth',size=15, mass=1, loc=(500,200),speed=(15,0), color='green')
space.bodies = [sun, earth]
space.place_bodies()
# MAIN
root = tk.Tk()
root.title('UNIVERSE')
size = (1000, 800)
space = Space(root, size, bg='black')
space.grid(row=0, column = 0,sticky="nsew")
dashboard = Dashboard(root)
dashboard.grid(row=0, column = 1,sticky="nsew")
stellarsys = StellarSys()
root.mainloop()
You initialize self.bodies to None, and then try to subscript that value. As the error says, you can't use subscripts on a value of None.
You need to rework your logic so that self.bodies is a non-empty list before trying to reference an item in the list.

How to fix key bindings in tkinter

I want to make a sprite move around on the canvas and have tried to use key bindings as controls. When I run the program it doesn't move until I try the correct key. I've tested with mouse buttons and it works fine.
adding code:
from tkinter import *
class MainGame:
def __init__(self):
self.grid = [[""]*15 for n in range(15)]
self.grid[14][3] = 1
print(self.grid)
self.canvas = Canvas(root, width = 900, height = 900)
self.canvas.pack()
self.a, self.b = 45, 175
def noreaction(self, event):
print("It clicked")
print(self.a)
self.a += 50
self.b += 50
self.canvas.create_image(self.a, self.b, image = self.pl, tags = "p2Tag")
self.canvas.delete("p1Tag")
self.canvas.tag_bind("p2Tag", "<Key-q>", self.noreaction)
def run(self):
self.pl = PhotoImage(file = "player.png")
self.canvas.create_image(self.a, self.b, image = self.pl, tags = "p1Tag")
self.canvas.tag_bind("p1Tag", "<Key>", self.noreaction)
self.x0, self.y0, self.x1, self.y1 = -30, 150, 20, 200
for self.row in self.grid:
for self.column in self.row:
self.x0 += 50
self.x1 += 50
self.cell = self.canvas.create_rectangle(self.x0, self.y0, self.x1, self.y1)
self.y0 += 50
self.y1 += 50
self.x0 = -30
self.x1 = 20
root = Tk()
root.focus_set()
obj = MainGame()
obj.run()
root.mainloop()
After messing with your code for a bit it would seam that tag_bind only works with mouse clicks. After reviewing all the documentation I could find in tag_bind there is nothing that says you can bind a key to a drawn object. So the solution here would be to bind either the root window to the key or to bind the frame the canvas is placed in.
I have changed up your code a little to make this work but it should help you move in the right direction. Without more information as to what you are trying to accomplish in the long run its hard to provide a good answer but I think this will help. Let me know if you have any more questions.
from tkinter import *
class MainGame:
def __init__(self, parent):
self.parent = parent
self.grid = [[""]*15 for n in range(15)]
self.grid[14][3] = 1
self.canvas = Canvas(self.parent, width = 900, height = 900)
self.canvas.pack()
self.a, self.b = 45, 175
#added an argument here so we can better control the player object.
def noreaction(self, old):
print("It clicked")
print(self.a)
self.a += 50
self.b += 50
self.canvas.delete(old)
# assigned the object to a class attribute
self.player_obj = self.canvas.create_image(self.a, self.b, image = self.pl, tags = "p2Tag")
# you will see <Key-q> and <q> work the same here.
self.parent.bind("<Key-q>", lambda x: self.noreaction(self.player_obj))
def run(self):
self.pl = PhotoImage(file = "./Colors/blk.gif")
# assigned the object to a class attribute
self.player_obj = self.canvas.create_image(self.a, self.b, image = self.pl, tags = "p1Tag")
# you will see <Key-q> and <q> work the same here.
self.parent.bind("<q>", lambda x: self.noreaction(self.player_obj))
self.x0, self.y0, self.x1, self.y1 = -30, 150, 20, 200
for self.row in self.grid:
for self.column in self.row:
self.x0 += 50
self.x1 += 50
self.cell = self.canvas.create_rectangle(self.x0, self.y0, self.x1, self.y1)
self.y0 += 50
self.y1 += 50
self.x0 = -30
self.x1 + 20
root = Tk()
root.focus_set()
obj = MainGame(root)
obj.run()
root.mainloop()
"<Key>" is not a valid keysym to bind an event on. Try a valid one, for a full list you can look here http://www.tcl.tk/man/tcl8.4/TkCmd/keysyms.htm
edit: appears I was mistaken, didn't know it was a valid event. You learn something every day :)

Delete an instance of the object

I'm trying to understand the class notion in Python and having decided to do a little exercise I found myself facing a problem.
What I'm trying to do is to create a circle (on a left-click) and then I expect the program to delete the circle (on a right-click).
Well, here comes the second part of my problem.
My code:
from tkinter import *
class Application:
def __init__(self):
self.fen = Tk()
self.fen.title('Rom-rom-roooooom')
self.butt1 = Button(self.fen, text = ' Quit ', command = self.fen.quit)
self.can1 = Canvas(self.fen, width = 300, height = 300, bg = 'ivory')
self.can1.grid(row = 1)
self.butt1.grid(row = 2)
self.fen.bind("<Button-1>", self.create_obj)
self.fen.bind("<Button-3>", self.delete_obj)
self.fen.mainloop()
def create_obj(self, event):
self.d = Oval()
self.can1.create_oval(self.d.x1, self.d.y1, self.d.x2, self.d.y2, fill='red', width = 2)
def delete_obj(self, event):
self.can1.delete(self.d)
class Oval:
def __init__(self):
self.x1 = 50
self.y1 = 50
self.x2 = 70
self.y2 = 70
appp = Application()
Here, the program understands that 'd' is an instance of class Oval, but it doesn't delete the object on a right click:
def delete_obj(self, event):
self.can1.delete(self.d)
From the tkinter docs, create_oval returns an object id, which is an integer. To remove the circle, use the Canvas.delete method:
from tkinter import *
import time
class Application:
def __init__(self):
self.fen = Tk()
self.fen.title('Rom-rom-roooooom')
self.butt1 = Button(self.fen, text = ' Quit ', command = self.fen.quit)
self.can1 = Canvas(self.fen, width = 300, height = 300, bg = 'ivory')
self.can1.grid(row = 1)
self.butt1.grid(row = 2)
self.fen.bind("<Button-1>", self.create_obj)
self.fen.mainloop()
def create_obj(self, event):
d = self.can1.create_oval(150,150, 170, 170, fill='red', width = 2)
time.sleep(3)
self.can1.delete(d)
appp = Application()

how to update a listbox in one window in one class using a different class python

what i have is a window that opens up and it has a list box. this is created using one class. when i click the search button and results are found using a different class, i want the list box to update without having to open up another window. below is my code so far\n
from Tkinter import *
class addTask:
def __init__(self):
self.addWindow = Tk()
self.addWindow.configure(background = "black")
self.addWindow.geometry("450x450")
self.addWindow.resizable(width = False, height = False)
self.addWindow.title("Add Task")
self.addNameLabel = Label(self.addWindow,text="Add the name of the task",font = ("Helvetica",10,"italic"),bg = "black",fg = "white")
self.addNameLabel.place(relx=0.01, rely=0.05)
self.nameWiget = Text (self.addWindow, width = 63, height = 1)
self.nameWiget.place(relx=0.0, rely=0.1)
self.addDateLabel = Label(self.addWindow,text="Add the date of the task",font = ("Helvetica",10,"italic"),bg = "black",fg = "white")
self.addDateLabel.place(relx=0.01, rely=0.2)
self.dateWiget = Text (self.addWindow, width = 63, height = 1)
self.dateWiget.place(relx=0.0, rely=0.25)
self.addTaskLabel = Label(self.addWindow,text="Add the details of the task",font = ("Helvetica",10,"italic"),bg = "black",fg = "white")
self.addTaskLabel.place(relx=0.01, rely=0.35)
self.taskWiget = Text (self.addWindow, width = 63, height = 1)
self.taskWiget.place(relx=0.0, rely=0.4)
addButton = Button(self.addWindow,height = 5, width = 20, text="Add Task",highlightbackground="black",font=("Helvetica",10,"bold"),command=lambda:self.saveFuntion())
addButton.place(relx=0.25, rely=0.55)
def saveFuntion(self):
nameInfo = (self.nameWiget.get(1.0, END))
dateInfo = self.dateWiget.get(1.0, END)
taskInfo = self.taskWiget.get(1.0, END)
print nameInfo
task1 = Task(nameInfo,dateInfo,taskInfo)
task1.save()
self.nameWiget.delete(1.0,END)
class Task:
def __init__(self,name,date,task):
self.__name = name
self.__date = date
self.__task = task
def save(self):
fileName = open("dataFile.txt","a")
fileName.write(self.__name)
fileName.write(self.__date)
fileName.write(self.__task)
class editTask:
def __init__(self):
self.editWindow = Tk()
self.newWindow = Tk()
self.newWindow.geometry("450x750")
self.editWindow.configure(background = "black")
self.editWindow.geometry("450x750")
self.editWindow.resizable(width = False, height = False)
self.editWindow.title("Edit Task")
self.listBox = Listbox(self.editWindow,heigh = 15, width = 30)
self.listBox.place(relx = 0.2, rely = 0.6)
#drop down menu
self.var = StringVar(self.editWindow)
self.var.set("Select search critria")
self.choices = ["Name","Date"]
self.option = OptionMenu(self.editWindow,self.var,*self.choices)
self.option.configure(bg = "black")
self.option.place(relx = 0.5, rely = 0.2)
#edit label and text box
self.editLabel = Label(self.editWindow,text="Add the name of the task",font = ("Helvetica",10,"italic"),bg = "black",fg = "white")
self.editLabel.place(relx=0.01, rely=0.05)
self.editInfoWiget = Text (self.editWindow, width = 63, height = 1)
self.editInfoWiget.place(relx=0.0, rely=0.1)
# search button
searchButton = Button(self.editWindow,height = 5, width = 20, text="Search for Task",highlightbackground="black",font=("Helvetica",10,"bold"),command=lambda:self.searchFuntion())
searchButton.place(relx=0.3, rely=0.4)
def searchFuntion(self):
critria = self.var.get()
info = self.editInfoWiget.get(1.0,END)
thing = info.split("\n")
thing2 = thing[0]
search = searchCritria(critria,thing2)
search.search()
# def openListBox(self):
class searchCritria():
def __init__(self,critria,info):
self.__critria = critria
self.__info = info
def search(self):
self.file = open("dataFile.txt", "r+")
fileData = self.file.readlines()
self.file.close()
lengthOfFile = len(fileData)
counter = 1
self.name = []
self.date = []
self.details = []
for i in range (lengthOfFile):
split = fileData[i].split("\n")
while counter == 1:
self.name.append(split)
break
while counter == 2:
self.date.append(split)
break
while counter == 3:
self.details.append(split)
break
counter = counter +1
if counter > 3:
counter = 1
if self.__critria == "Name":
for x in range (len(self.name)):
self.taskName = self.name[x]
self.taskName2 = self.taskName[0]
if self.__info == self.taskName2:
openWindow = True
else :
openWindow = False
if openWindow == True:
editTask().listBox.insert(END,self.taskName2)
if self.__critria == "Date":
for x in range (len(self.date)):
self.taskDate = self.date[x]
self.taskDate2 = self.taskDate[0]
if self.__info == self.taskDate2:
print "found"
else :
print"not found"
class editTask2():
def __init__(self):
self.edit2Window = Tk()
self.edit2Window.configure(background = "black")
self.edit2Window.geometry("450x350")
self.edit2Window.resizable(width = False, height = False)
self.edit2Window.title("Edit Task")
any help would be great
thanks
The biggest problem in your code is that you're creating multiple instances of Tk. Tkinter simply isn't designed to work that way. You should only ever create a single instance of Tk. If you need additional windows, create instances of Toplevel.
Also, you need to call the mainloop function of this instance of Tk exactly once. Without it, your GUI will not work.
If you want to update a listbox in another class than where it was created, the concept is pretty simple: if A needs to update B, A needs a reference to B. So, either pass in a reference to the listbox when you create the other class, or give the other class a method you can call where you pass in the reference to the listbox after it was created.

Categories

Resources