from tkinter import *
class wigdet:
def __init__(self):
window = Tk()
window.title("Buttons and Radio Buttons")
frame1 = Frame(window)
frame1.pack()
self.v1 = IntVar()
rb_red = Radiobutton(frame1, text="Red", fg="black", variable= self.v1, value = 1, command=self.process_radio_button)
rb_yellow = Radiobutton(frame1, text="Yellow", fg="black", variable= self.v1, value = 2, command=self.process_radio_button)
rb_white = Radiobutton(frame1, text="White", fg="black", variable= self.v1, value = 3, command=self.process_radio_button)
rb_gray = Radiobutton(frame1, text="Gray", fg="black", variable= self.v1, value = 4, command=self.process_radio_button)
rb_green = Radiobutton(frame1, text="Green", fg="black", variable= self.v1, value = 5, command=self.process_radio_button)
rb_red.grid(row=0, column=0)
rb_yellow.grid(row=0, column=1)
rb_white.grid(row=0, column=2)
rb_gray.grid(row=0, column=3)
rb_green.grid(row=0, column=4)
frame2 = Frame(window)
frame2.pack()
self.canvas = Canvas(frame2, width=400, height=100, bg="white")
self.x1, self.y1 = (200, 50)
self.canvas.create_text(self.x1,self.y1, fill="black",text="Welcome",font=("Arial"),tags="text")
self.canvas.pack()
frame3 = Frame(window)
frame3.pack()
bt_left = Button(frame3, text = "<=", fg = "black", command = self.process_left)
bt_right = Button(frame3, text = "=>", fg = "black", command = self.process_right)
bt_left.grid(row=2, column=0)
bt_right.grid(row=2, column=1)
window.mainloop()
def process_radio_button(self):
if (self.v1.get() == 1):
self.canvas.create_rectangle(0,0,400, 100, fill="red")
self.canvas.create_text(self.x1,self.y1,fill="black",text="Welcome",font=("Arial"),tags="text")
elif (self.v1.get() == 2):
self.canvas.create_rectangle(0,0,400, 100, fill="yellow")
self.canvas.create_text(self.x1,self.y1,fill="black",text="Welcome",font=("Arial"),tags="text")
elif (self.v1.get() == 3):
self.canvas.create_rectangle(0,0,400, 100, fill="white")
self.canvas.create_text(self.x1,self.y1,fill="black",text="Welcome",font=("Arial"),tags="text")
elif (self.v1.get() == 4):
self.canvas.create_rectangle(0,0,400, 100, fill="gray")
self.canvas.create_text(self.x1,self.y1,fill="black",text="Welcome",font=("Arial"),tags="text")
else:
self.canvas.create_rectangle(0,0,400, 100, fill="green")
self.canvas.create_text(self.x1,self.y1,fill="black",text="Welcome",font=("Arial"),tags="text")
def process_left(self):
self.canvas.delete("text")
if self.x1>10:
self.x1-=10
if self.x1>60:
self.x1-=10
self.canvas.create_text(self.x1, self.y1, fill="black", tags="text")
def process_right(self):
self.canvas.delete("text")
if self.x1 < 350:
self.x1 =10
if self.x1 < 400:
self.x1 =10
self.canvas.create_text(self.x1, self.y1, fill="black", tags="text")
wigdet()
I have two buttons where I am to move the text left and right. I also have 5 Radiobutton
s that decide the background color. when i chose for example red, and then move the text left, the text disappears, but reappears slightly to the left when i hit the Radiobutton
for red.
any simple solution?
CodePudding user response:
Here is an improved version of the code (explanation in code comments):
import tkinter as tk
from tkinter import font
# inherit from frame for easier use
class MyWidget(tk.Frame):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
# create the frame for radio buttons
self.rb_frame = tk.Frame(self)
# variable for radio buttons and set value to something already
self.rb_var = tk.StringVar(value='white')
# iterate over colors and place the radio buttons with the color
# text and set `value=color`, that way `self.rb_var.get()`
# will return the color
for color in ('red', 'yellow', 'white', 'gray', 'green'):
tk.Radiobutton(
self.rb_frame, text=color.title(), value=color,
variable=self.rb_var, command=self.color_select
).pack(side='left')
# configure canvas stuff, set width and height
self.c_w, self.c_h = 600, 500
# get initial x position for text
self.x = self.c_w // 2
self.canvas = tk.Canvas(self, width=self.c_w, height=self.c_h)
# create rectangle on canvas and save its id
self.rect = self.canvas.create_rectangle(
0, 0, self.c_w, self.c_h, fill=self.rb_var.get(),
outline=self.rb_var.get())
# define the text to display
self.text = 'Welcome!'
# use a `font` so that later can measure the text width
self.font = font.Font(family='Arial')
# measure text width to allow for better collision detection with sides
self.text_width = self.font.measure(self.text)
# create the text and save the id
self.canvas_text = self.canvas.create_text(
self.x, self.c_h // 2, text=self.text, font=self.font)
# create the frame where the left/right buttons will be
self.btn_frame = tk.Frame(self)
# create the buttons
tk.Button(
self.btn_frame, text='>>>', command=lambda: self.move('right')
).pack(side='right', fill='x', expand=True)
tk.Button(
self.btn_frame, text='<<<', command=lambda: self.move('left')
).pack(side='left', fill='x', expand=True)
# place all the created frames
self.rb_frame.grid(row=0, column=0)
self.canvas.grid(row=1, column=0)
self.btn_frame.grid(row=2, column=0, sticky='we')
# the color selector method which is called from radio buttons
def color_select(self):
value = self.rb_var.get()
# as you can see then using `value=color` earlier now this is possible
# to easily set the color
self.canvas.itemconfig(self.rect, fill=value, outline=value)
# method for moving
def move(self, side):
# get half width of font because the center of the created text is middle
half_width = self.text_width // 2
if side == 'left' and self.x - 10 - half_width > 0:
self.x -= 10
elif side == 'right' and self.x 10 half_width < self.c_w:
self.x = 10
# move the created text
self.canvas.coords(self.canvas_text, self.x, self.c_h // 2)
# in general good practice to use this if statement
if __name__ == '__main__':
# create the root
root = tk.Tk()
# put the widget on the window
frame = MyWidget(root)
frame.pack()
root.mainloop()
As you see, there is no need to delete the created text or rectangles, just change their coordinates and options (which can be done with tags too, I just used IDs)
Also:
I strongly advise against using wildcard (*
) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2
and so on or import the whole module: import module
then You can also use an alias: import module as md
or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.
I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case
, class names in CapitalCase
. Don't have space around =
if it is used as a part of keyword argument (func(arg='value')
) but have space around =
if it is used for assigning a value (variable = 'some value'
). Have space around operators ( -/
etc.: value = x y
(except here value = x y
)). Have two blank lines around function and class declarations. Object method definitions have one blank line around them.
CodePudding user response:
It is because you delete existing text and create a new text object without assigning text
to it. So you just create a empty text object.
Also it is better to create those canvas items once and using coords()
to move them and itemconfig()
to change their attributes.
class widget:
def __init__(self):
...
# create the background rectangle first
self.canvas.create_rectangle(0,0,400, 100, fill="white", tags="rect")
self.canvas.create_text(self.x1,self.y1, fill="black",text="Welcome",font=("Arial"),tags="text")
...
def process_radio_button(self):
if (self.v1.get() == 1):
fill="red"
elif (self.v1.get() == 2):
fill="yellow"
elif (self.v1.get() == 3):
fill="white"
elif (self.v1.get() == 4):
fill="gray"
else:
fill="green"
# change the fill color
self.canvas.itemconfig("rect", fill=fill)
def process_left(self):
# why two if ???
if self.x1>10:
self.x1-=10
if self.x1>60:
self.x1-=10
# move the text
self.canvas.coords("text", self.x1, self.y1)
def process_right(self):
# why two if ???
if self.x1 < 350:
self.x1 =10
if self.x1 < 400:
self.x1 =10
# move the text
self.canvas.coords("text", self.x1, self.y1)