I'm making a simple drawing pad program with pygame and I'm making it so you can define your own color. I'm using a tk window to do this but I cant figure out how to get them to work together. Please help, I've been trying to get this to work for hours
Here is my Tk code:
from Tkinter import *
r = 0
g = 0
b = 0
class Custom():
def get_color(self):
self.root = Tk()
self.root.configure(background='black')
self.root.wm_title("Custom")
label1 = Label(self.root, text='Red Value:',bg="black", fg="white")
label1.grid(row=2, column=0,columnspan=2)
self.enter1 = Entry(self.root, bg='white')
self.enter1.grid(row=3, column=0,columnspan=2)
label2 = Label(self.root, text='Green Value:',bg="black", fg="white")
label2.grid(row=4, column=0,columnspan=2)
self.enter2 = Entry(self.root, bg='white')
self.enter2.grid(row=5, column=0, columnspan=2)
label3 = Label(self.root, text='Blue Value:',bg="black", fg="white")
label3.grid(row=6, column=0,columnspan=2)
self.enter3 = Entry(self.root, bg='white')
self.enter3.grid(row=7, column=0, columnspan=2)
btn1 = Button(self.root, text='OK', command=self.close, bg="black",activebackground="green", fg="white")
btn1.grid(row=14, column=0, columnspan=2)
label7 = Label(self.root, bg="black", fg = "white")
label7.grid(row=15, column=0, columnspan=2)
self.enter1.focus()
self.root.mainloop()
def close(self):
self.root.destroy()
def return_color(self):
r = int(self.enter1.get())
g = int(self.enter2.get())
b = int(self.enter3.get())
return (r,g,b)
It works fine, but I can't get it to return the three values to my pygame program.
Here is the pygame snippet:
if key[pygame.K_c]:
import CustomColor
c = CustomColor.Custom()
c.get_color()
self.color = c.return_color()
Current Error:
Traceback (most recent call last):
File "C:/Python27/Drawpad.py", line 75, in <module>
draw.main()
File "C:/Python27/Drawpad.py", line 69, in main
self.update(screen)
File "C:/Python27/Drawpad.py", line 45, in update
self.color = c.return_color()
File "C:/Python27\CustomColor.py", line 41, in return_color
r = int(self.enter1.get())
File "C:\Python27\lib\lib-tk\Tkinter.py", line 2391, in get
return self.tk.call(self._w, 'get')
TclError: invalid command name ".19783112"
I've been tweaking it, but just getting different error messages. If anyone can help, I would appreciate it.
Your immediate problem is that you're trying to access Entry objects after they've been destroyed.
You can fix that very simply:
def close(self):
self.r = int(self.enter1.get())
self.g = int(self.enter2.get())
self.b = int(self.enter3.get())
self.root.destroy()
def return_color(self):
return (self.r,self.g,self.b)
The reason this is happening is that, when you call get_color, that calls self.root.mainloop, which means it can't possibly return until the Tk event loop has exited, which means calling your close method, which means self.root.destroy is guaranteed to have happened before you can call return_color.
Calling a function that blocks on the Tk event loop is going to have other problems as well. Your pygame event loop is stuck waiting for Tk. So, your pygame window can't redraw itself, minimize, or respond to any other events.
Related
I am new to Tkinter and was following a course when I ran into a problem. I believe the problem is at line 31 when I use my_label.grid_forget(). If I comment it out I do not get the error. I am not sure what the issue is or why it's giving an error.
I am not fully done with the program but it is an image viewer. So it will display an image, then you can click >> to see the next image, exit, or << to go back to other image. When you click the for the next image, I want to clear the current image so they do not overlap, but when I use my_label.grid_forget() something goes wrong.
The Error I get is:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\david\AppData\Local\Programs\Python\Python311\Lib\tkinter\__init__.py", line 1948, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "C:/Users/david/OneDrive/Documents/TKinter Python/Image Viewer.py", line 44, in <lambda>
button_forward = Button(root, text=">>", command=lambda: forward(2))
^^^^^^^^^^
File "C:/Users/david/OneDrive/Documents/TKinter Python/Image Viewer.py", line 32, in forward
my_label.grid_forget()
^^^^^^^^
NameError: name 'my_label' is not defined
from tkinter import *
# Allows for images such as JPEG and PNG
from PIL import ImageTk,Image
def main():
root = Tk()
root.title("Simple Calculator")
root.iconbitmap('c:\\Users\\david\\OneDrive\\Documents\\TKinter Python\\favicon.ico') #favicon
#Img's
my_img1 = ImageTk.PhotoImage(Image.open(r"C:\Users\david\OneDrive\Documents\TKinter Python\Images\apple.png"))
my_img2 = ImageTk.PhotoImage(Image.open(r"C:\Users\david\OneDrive\Documents\TKinter Python\Images\Kiwi.png"))
my_img3 = ImageTk.PhotoImage(Image.open(r"C:\Users\david\OneDrive\Documents\TKinter Python\Images\Lime.png"))
my_img4 = ImageTk.PhotoImage(Image.open(r"C:\Users\david\OneDrive\Documents\TKinter Python\Images\Red Apple.png"))
my_img5 = ImageTk.PhotoImage(Image.open(r"C:\Users\david\OneDrive\Documents\TKinter Python\Images\Grape Fruit.png"))
#Img list
image_list = [my_img1,my_img2,my_img3,my_img4,my_img5]
# Creating a label which will hold an img and then display it
my_label = Label(image=my_img1)
my_label.grid(row=0, column=0, columnspan=3)
# Function for the forward button to display next image in list
def forward(image_number):
global my_label
global button_forward
global button_back
my_label.grid_forget()
my_label = Label(image=image_list[image_number-1])
def back():
global my_label
global button_forward
global button_back
button_back = Button(root, text="<<", command=back)
button_exit = Button(root, text="Exit Program", command=quit)
button_forward = Button(root, text=">>", command=lambda: forward(2))
button_back.grid(row=1, column=0)
button_exit.grid(row=1, column=1)
button_forward.grid(row=1, column=2)
#Program loop for it to run
root.mainloop()
main()
I did try commenting it out which gets rid of the error, but I want to make it work.
I am trying to create a pop up window with Tkinter where I can enter values with an entry window to use them in the main code.
Currently I am trying to simply output the input. I can't get it to work, does anyone have an idea how I can solve this problem?
Here is a small snippet of my code. I have not used the variables from the functions anywhere else in the code.
root = Tk() # set up GUI
menuleiste = Menu(root) #menu bar
def take_over_Temp():
#Tempstring = str(eKnopf.get())
print(eKnopf.get())
print("got it")
def open_popup():
#global eKnopf
top= Toplevel(root)
top.geometry("750x250")
top.title("Child Window")
#Label(top, text= "Hello World!", font=('Mistral 18 bold')).place(x=150,y=80)
eKnopf = Entry(top, bd = 5).place(x=10,y=100, width=100)
button_take_Temp = Button(top, text='Set Temperature', fg="red", command=take_over_Temp)
button_take_Temp.place(x=10, y=150, width=100)
return(eKnopf)
optionen_menu.add_command(label="Offset", command = open_popup)
When I try it like this I get this Error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "/home/user/FAC.py", line 724, in take_over_Temp
print(eKnopf.get())
NameError: name 'eKnopf' is not defined
You need to pass in eKnopf as a parameter to take_over_Temp()
eKnopf = Entry(top, bd = 5)
eKnopf.place(x=10, y=100, width=100)
button_take_Temp = Button(
top,
text='Set Temperature',
fg="red",
# use a lambda to pass `eKnopf` as an argument
command=lambda ent=eKnopf: take_over_Temp(ent)
)
Then modify take_over_Temp to accept and use that value:
def take_over_Temp(ent):
print(ent.get())
FYI, the error you're seeing is essentially saying that the function take_over_Temp doesn't know what eKnopf is because it doesn't exist within the scope of the function.
What I am trying to do:
I want the button Confirmar to disappear once it is clicked, for that I redirected it to the function dConfirm which is supposed to trigger the destroy process.
What is happening:
The button is defined in a different function from the destroy process, so it is returning a not defined error.
My code:
def dSim():
btn3=Button(janela, text= "Hipertensao arterial", command = add1)
btn3.place(x = 80, y = 219)
btn4=Button(janela, text= "Pedras nos rins", command = add2)
btn4.place(x = 200, y = 219)
btn5=Button(janela, text= "Osteoporose", command = add3)
btn5.place(x = 295, y = 219)
btn6=Button(janela, text= "Colesterol elevado", command = add4)
btn6.place(x = 378, y = 219)
btn7=Button(janela, text= "Esclerose multipla", command = add5)
btn7.place(x = 492, y = 219)
btn.destroy()
btn2.destroy()
lb7=Label(janela, text= "Selecione as suas doencas:", font = ("Verdana", "14"))
lb7.place(x = 185, y = 190)
btn8=Button(janela, text= "Confirmar", command = dConfirm)
btn8.place(x = 80, y = 240)
def dNao():
lb5=Label(janela, text=Gperf, font = ("Verdana", "14"))
lb5.place(x = 80, y = 165)
btn.destroy()
btn2.destroy()
lb6=Label(janela, text="E perfeitamente saudavel, otimo!", font = ("Verdana", "14"))
lb6.place(x = 185, y = 190)
def dConfirm():
btn8.destroy()
You have three options:
btn8 is a local variable, so you cannot refer to it outside its scope. You can make it global.
Instead of directly calling dConfirm(), pass to it the button instance using a lambda like this:
btn8 = Button(janela, text="Confirmar", command=lambda: dConfirm(btn8)) and change the function definition to def dConfirm(btn8):(I would prefer this if you don't want to move to option 3 and modify your code)
If you are using classes, make it an instance of the class by using self.btn8 and then destroy it by using self.btn8.destroy().
#1 You can try this:
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root)
frame.grid(row=0, column=0, padx=4, pady=4)
# destroy the button on dConfirm function call
def dConfirm():
btn8.destroy()
# Declare btn8 outside of the two function
btn8 = tk.Button(frame, text="Confirmar", command=dConfirm)
# Place btn8 inside the function you want
def dSim():
btn8.grid(row=0, column=0, padx=4, pady=4)
dSim()
root.mainloop()
#2 You can also try this (In my opinion this is better):
import tkinter as tk
class MainWindow:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
self.frame.grid(row=0, column=0, padx=4, pady=4)
self.dSim()
def dConfirm(self):
self.btn8.destroy()
def dSim(self):
self.btn8 = tk.Button(self.frame, text="Confirmar", command=self.dConfirm)
self.btn8.grid(row=0, column=0, padx=4, pady=4)
def main():
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
I am making this small program, where the user can input the x and y axis of the screen where they wish to move the mouse to, and how many time they would like to click on that pixel.
My problem is when I try to put the variables into this function, the arguments apparently cannot be converted? The SetCurPos() is the problem, it will take SetCurPos(x,y), but I receive the error:
File "C:\Python27\Scripts\ManipulationTools.py", line 13, in click
SetCursorPos(x,y)
ArgumentError: argument 1: : Don't know how to convert parameter 1
My Code:
from Tkinter import *
import time
import ctypes
#from MoveCursor import click
class ManipulationTools():
##############FUNCTIONS###################################
def click(x,y, numclicks):
SetCursorPos = ctypes.windll.user32.SetCursorPos
mouse_event = ctypes.windll.user32.mouse_event
SetCursorPos(x,y)
E1.DELETE(0, END)
E2.DELETE(0, END)
E3.DELETE(0, END)
for i in xrange(numclicks):
mouse_event(2,0,0,0,0)
mouse_event(4,0,0,0,0)
#############END FUNCTIONS################################
root = Tk()
root.maxsize(width=400, height=400)
root.minsize(width=400, height=400)
root.config(bg="black")
L1 = Label(root,text="Enter the x and y value here:", fg="white", bg="black")
L1.place(x=20, y=20)
Lx = Label(root, text="X:",fg="white",bg="black")
Lx.place(x=170,y=20)
Ly = Label(root, text="Y:",fg="white",bg="black")
Ly.place(x=240,y=20)
Lnum = Label(root, text="Number of Times:",fg="white",bg="black")
Lnum.place(x=150, y=100)
E1 = Entry(root, width=5, bg="grey", )
E1.place(x=190,y=20)
E2 = Entry(root, width=5, bg="grey",)
E2.place(x=260,y=20)
E3 = Entry(root, width=5, bg="grey",)
E3.place(x=260,y=100)
a=IntVar(E1.get())
b=IntVar(E2.get())
c=IntVar(E3.get())
con = Button(root, command=click(a,b,c), text="Confirm", bg="white")
con.place(x=300,y=300)
root.mainloop()
My Traceback error when I click the button to confirm the numbers in the fields entered:
Traceback (most recent call last):
File "C:\Python27\Scripts\ManipulationTools.py", line 6, in
class ManipulationTools():
File "C:\Python27\Scripts\ManipulationTools.py", line 53, in ManipulationTools
con = Button(root, command=click(a,b,c), text="Confirm", bg="white")
File "C:\Python27\Scripts\ManipulationTools.py", line 13, in click
SetCursorPos(x,y)
ArgumentError: argument 1: : Don't know how to convert parameter 1
What you call ####functions#### are actually methods, and hence, the first argument they get is always the reference to the instance of their containing class, which commonly is named self. You can, however, name that parameter like you want to, which is what happened here:
class ManipulationTools():
def click(x,y, numclicks):
x is what elsewhere would be called self, not the first argument that you give when doing something like
tools = ManipulationTools()
tools.click(100,200,1) ## this should actually give you an error -- ManipulationTools.click gets called with 4 arguments (self, 100, 200, 1), but is only defined for 3 (self, y, numclicks)
The right thing to do is:
class ManipulationTools():
def click(self, x,y, numclicks):
I am attempting to create a GUI using Python classes. Because I'm new to Python, I'm still learning to troubleshoot my errors. Below, I wish to create a class called Plot_Seismo, and create a GUI that has a listbox, a quit button, and a "Plot" button. I am having trouble with the "Plot_button" within the class. What I want this button to do is read in the seismogram and then plot the selected seismogram from the listbox. I have a feeling my syntax is incorrect (due to my naivete). I can get this to work when this function isn't in a class, but when I put it in a class as a method, I get slightly confused. The error message is shown below:
#!/usr/bin/env python
from Tkinter import *
from obspy.core import read
import math
class Plot_Seismo:
def __init__(self, parent):
self.master = parent
top = Frame(parent, width=500, height=300)
top.pack(side='top')
# create frame to hold the first widget row:
hwframe = Frame(top)
# this frame (row) is packed from top to bottom (in the top frame):
hwframe.pack(side='top')
# create label in the frame:
font = 'times 18 bold'
hwtext = Label(hwframe, text='Seismogram Reader GUI', font=('Arial',18,'bold'), fg="red")
hwtext.pack(side='top')
### ListBox
List1 = Listbox(root, width=50, height= 10)
List1.insert(1,"trace1.BHZ")
List1.insert(2,"trace2.BHZ")
List1.pack(padx=20, pady=20)
plot_button = Button(top, text='Plot Seismogram', command=self.plot_seis)
plot_button.pack(side='top', anchor='w', padx=45, pady=20)
self.event = read(List1.get(List1.curselection()[0]))
# finally, make a quit button and a binding of q to quit:
quit_button = Button(top, text='Quit Seismo-Reader GUI', command=self.quit)
quick_button.pack(side='top', anchor='w', padx=20, pady=20)
self.master.bind('<q>', self.quit)
def quit(self, event=None):
self.master.quit()
def plot_seis(self, event=None):
self.event.plot()
root = Tk()
Plot_Seismo = Plot_Seismo(root)
root.mainloop()
Error Message:
Traceback (most recent call last):
File "plot_seismogram.py", line 46, in <module>
Plot_Seismo = Plot_Seismo(root)
File "plot_seismogram.py", line 31, in __init__
self.event = read(List1.get(List1.curselection()[0]))
IndexError: tuple index out of range
Since I do not have obspy module installed, I had to shrink down your code a bit, but you should get the point.
Since I only have Python3 running on my machine, I rewrote your code to Python3 which is not a big deal. The only differences should be (tkinter instead of Tkinter and print() instead of print).
I changed some parts of your code: The listbox is no populated using a list, which make this a bit easier and it became a class attribute to access it in plot_seis.
Since .curselection() returns a tuple with the listboxes entry index, we have to get the according text entry as described in the docs and in this answer.
Buttons and maybe the listbox provide some event handling features which are making the listbox an class attribute by using self. kind of ugly somehow, but it does the job:
#!/usr/bin/env python3
# coding: utf-8
from tkinter import *
# from obspy.core import read
import math
class Plot_Seismo:
def __init__(self, parent):
self.master = parent
top = Frame(parent, width=500, height=300)
top.pack(side='top')
# create frame to hold the first widget row:
hwframe = Frame(top)
# this frame (row) is packed from top to bottom (in the top frame):
hwframe.pack(side='top')
# create label in the frame:
font = 'times 18 bold'
hwtext = Label(hwframe, text='Seismogram Reader GUI', font=('Arial',18,'bold'), fg="red")
hwtext.pack(side='top')
### ListBox
self.List1 = Listbox(root, width=50, height= 10)
# populate listbox using a list with desired entries
self.list_entries = ["trace1.BHZ", "trace2.BHZ"]
for i, element in enumerate(self.list_entries):
self.List1.insert(i, element)
self.List1.pack(padx=20, pady=20)
plot_button = Button(top, text='Plot Seismogram', command=self.plot_seis)
plot_button.pack(side='top', anchor='w', padx=45, pady=20)
# finally, make a quit button and a binding of q to quit:
quit_button = Button(top, text='Quit Seismo-Reader GUI', command=self.quit)
quit_button.pack(side='top', anchor='w', padx=20, pady=20)
self.master.bind('<q>', self.quit)
def quit(self, event=None):
self.master.quit()
def plot_seis(self, event=None):
selection_index = self.List1.curselection()[0]
selection_text = self.List1.get(selection_index)
print(selection_text)
# do something with `read` from the `obspy.core` module
# read(selection_text)
root = Tk()
Plot_Seismo = Plot_Seismo(root)
root.mainloop()