[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