[Tutor] Tkinter and after() method
Phil
phillor9 at gmail.com
Tue Jan 31 00:46:54 EST 2023
On 31/1/23 11:49, Cameron Simpson wrote:
> On 31Jan2023 11:39, Phil <phillor9 at gmail.com> wrote:
>> The Tkinter project is 128 lines in length plus a class file of 15
>> lines.
>>
>> Would anyone be interested is reviewing the code? There won't be any
>> hard feelings and I understand completely if the answer is no.
>
> Feel free to post it. Can you also describe the design issue and the
> enhancement it blocks?
Thank you Cameron. The most glaring flaw is that I cannot display
multiple dials. I can see why but I'm not sure how to fix the flaw. Even
though it runs without error, It's starting to get overly complex.
This is the analogue dial class as it is at the moment:
class Dial:
def __init__(self, x=60, y=60, size=60):
self.x = x # centre of dial
self.y = y
self.size = size # the diameter of the dial
self.xn = self.x + 1 # the end points of the ticks and pointer
self.yn = self.y + 1
self.value = 0 # the pointer's value
This shows an example of how I might use the dial class:
import tkinter as tk
import math
import dial
my_frame = None # these variables allow use where the original is out of
scope
my_dial = None # I cannot see an alternative to their use at the moment
my_canvas = None
class Root(tk.Tk):
def __init__(self):
super().__init__()
self.title("Canvas Template")
self.frame = tk.Frame(self, background='cornflowerblue')
self.frame.pack(side='top', fill='both', expand=True)
global my_frame, my_dial, my_canvas
my_frame = self.frame
self.canvas = tk.Canvas(
self.frame, relief='flat', background='lightgrey')
self.canvas.pack(side='top', anchor='center', fill='both',
expand=True, padx=10, pady=10)
my_canvas = self.canvas
self.quit_button = tk.Button(self, text="Quit", command=self.quit)
self.quit_button.pack(side=tk.BOTTOM, anchor='se', padx=10,
pady=10)
self.dial = dial.Dial(180, 160, 120)
my_dial = self.dial
draw_dial(self.dial, self.canvas)
move_pointer(self.dial, self.canvas)
loop()
def draw_dial(the_dial, canvasName):
x = the_dial.x # the centre of the circle
y = the_dial.y
r = the_dial.size / 2 # the radius of the circle
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
canvasName.create_oval(x0, y0, x1, y1)
# draw the ticks around the circle's edge
tick_length = the_dial.size / 2
for tick in range(0, 101, 10):
theta = tick * 2.7 - 45
theta_rad = math.radians(theta)
yn = -int(tick_length * math.sin(theta_rad))
xn = -int(tick_length * math.cos(theta_rad))
canvasName.create_line(the_dial.x, the_dial.y,
xn + the_dial.x, the_dial.y + yn)
# shorten ticks
x = the_dial.x
y = the_dial.y
r = the_dial.size / 2.7
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
canvasName.create_oval(
x0, y0, x1, y1, fill='lightgrey', outline='lightgrey')
def move_pointer(the_dial, canvasName):
# this is just a test. In real use the_dial.value woule be supplied
with
# a value from a serial device
pointer_length = the_dial.size * .3
# erase the pointer
drawPointer(the_dial.x, the_dial.y, the_dial.xn + the_dial.x,
the_dial.y + the_dial.yn, 1, canvasName)
theta = the_dial.value * 2.7 - 45
theta_rad = math.radians(theta)
the_dial.yn = -int(pointer_length * math.sin(theta_rad))
the_dial.xn = -int(pointer_length * math.cos(theta_rad))
# draw the pointer in its new position
drawPointer(the_dial.x, the_dial.y, the_dial.xn + the_dial.x,
the_dial.y + the_dial.yn, 0, canvasName)
# draw dial centre
x = the_dial.x
y = the_dial.y
r = 4
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
canvasName.create_oval(x0, y0, x1, y1, fill='black')
def drawPointer(x_centre, y_centre, x_end, y_end, fill, canvasName):
if fill == 1:
colour = 'lightgrey'
else:
colour = 'black'
canvasName.create_line(
x_centre, y_centre, x_end, y_end, fill=colour)
def loop():
# again, this only for testing
global my_dial, my_canvas
my_dial.value += 10 # change the pointer position by 10%
if my_dial.value > 100:
my_dial.value = 0
move_pointer(my_dial, my_canvas)
my_frame.after(1000, loop)
if __name__ == "__main__":
root = Root()
root.mainloop()
--
Regards,
Phil
More information about the Tutor
mailing list