4

I'm working on a Python application using tkinter. What I want to do is to draw on canvas coordinates, and the points will be recorded to a list so I can do calculation later. If it's not possible, would you recommend any other tools or GUI platform that can do this?

Edit: What I have so far is an application that can take points from a list and draw on the canvas. I would like the opposite way to work too.

from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showerror
from tkinter import ttk
import tkinter
import threading

another_points = []

class Waveform(Frame):
   def __init__(self, master):
      ttk.Frame.__init__(self, master)
      self.master = master

      self.points = [10, 20, 30]
      self.create_widget()

   def create_widget(self):

      self.LoadFrame = ttk.LabelFrame(self.master, text = "Load")
      self.LoadFrame.pack(side = "left", padx = 10, pady = 10)
      self.PlotFrame()

      self.anotherFrame = ttk.LabelFrame(self.LoadFrame, text = "Browse")
      self.anotherFrame.pack(fill = "both", padx = 10, pady = 10)
      self.OpenFileButton = ttk.Button(self.anotherFrame, text = "Browse", command = self.load_file)
      self.OpenFileButton.grid(row = 0, column = 0)

   def load_file(self):
      fname = askopenfilename(filetypes = (("Text files", "*.txt"), ("All files", "*.*")))
      another_points[:] = []
      self.points[:] = []
      if fname:
         try:
            print (fname)
            with open(fname) as f:
               for line in f:
                  another_points.append(float(line.rstrip()))

            self.points = another_points

         except:
            print ("Error")
         return


   def PlotFrame(self):
      self.PlotFrame = ttk.LabelFrame(self.master, text = "X/Y Coordinates")
      self.PlotFrame.pack(side = LEFT, padx = 10, pady = 10)

      self.width = 400
      self.height = 350
      self.pressure = 75
      self.x_increment = 1
      self.x_factor = 0.04
      self.y_amplitude = 80


      def draw():
         self.GraphFrame.delete(self.sin_line)
         self.xy1 = []
         self.xy2 = self.points
         for x in range(len(self.xy2)):
            self.xy1.append(x + 25)
            self.xy1.append(self.height - self.xy2[x])

         self.sin_line = self.GraphFrame.create_line(self.xy1, fill = "yellow")

      self.UpdateButton = ttk.Button(self.PlotFrame, text = "Update", command = draw)
      self.UpdateButton.pack()

      self.GraphFrame = Canvas(self.PlotFrame, width = self.width, height = self.height, bg = "black")

      self.GraphFrame.pack()
      self.original = []

      self.mock = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      for x in range(len(self.mock)):
         self.original.append((x + 5)*10)
         self.original.append((self.height - self.mock[x])/100)

      self.sin_line = self.GraphFrame.create_line(self.original, fill = "yellow")


if __name__ == "__main__":
    master = Tk()
    Waveform(master).pack(side = "top", fill ="both", expand = True)
    master.mainloop()

-Thanks

4
  • 1
    What have you tried so far? Right now, this question is just, "write code for me". Commented Nov 15, 2016 at 7:27
  • this code won't run. AttributeError: 'Waveform' object has no attribute 'CustomizedWaveformes' Commented Nov 15, 2016 at 16:56
  • You can add bindings for when the mouse moves, and when you click the mouse. You can use information given to the bound functions to draw lines. Commented Nov 15, 2016 at 16:57
  • @BryanOakley: Code fixed. Thank you for pointing it out. Can you give a brief example of that? I'll definitely give it a try too. Thanks! Commented Nov 15, 2016 at 17:37

2 Answers 2

6

Start with

import tkinter as tk
root = tk.Tk()
def mmove(event):
    print(event.x, event.y)
root.bind('<Motion>', mmove)
root.mainloop()

Then elaborate as you wish. Bind motion to a canvas, draw points on the canvas, append pairs to a list, bind clicks instead or in addition, filter the stream of points, etc.

Sign up to request clarification or add additional context in comments.

Comments

3

Thank you Terry for providing a very useful hint. I managed to get it working. Note that this is not the optimal solution because of the redundant points recorded. That's why I have to pop it out a lot. But it works, at least.

import tkinter as tk

class ExampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.previous_x = self.previous_y = 0
        self.x = self.y = 0
        self.points_recorded = []
        self.canvas = tk.Canvas(self, width=400, height=400, bg = "black", cursor="cross")
        self.canvas.pack(side="top", fill="both", expand=True)
        self.button_print = tk.Button(self, text = "Display points", command = self.print_points)
        self.button_print.pack(side="top", fill="both", expand=True)
        self.button_clear = tk.Button(self, text = "Clear", command = self.clear_all)
        self.button_clear.pack(side="top", fill="both", expand=True)
        self.canvas.bind("<Motion>", self.tell_me_where_you_are)
        self.canvas.bind("<B1-Motion>", self.draw_from_where_you_are)

    def clear_all(self):
        self.canvas.delete("all")

    def print_points(self):
        if self.points_recorded:
            self.points_recorded.pop()
            self.points_recorded.pop()
        self.canvas.create_line(self.points_recorded, fill = "yellow")
        self.points_recorded[:] = []

    def tell_me_where_you_are(self, event):
        self.previous_x = event.x
        self.previous_y = event.y

    def draw_from_where_you_are(self, event):
        if self.points_recorded:
            self.points_recorded.pop()
            self.points_recorded.pop()

        self.x = event.x
        self.y = event.y
        self.canvas.create_line(self.previous_x, self.previous_y, 
                                self.x, self.y,fill="yellow")
        self.points_recorded.append(self.previous_x)
        self.points_recorded.append(self.previous_y)
        self.points_recorded.append(self.x)     
        self.points_recorded.append(self.x)        
        self.previous_x = self.x
        self.previous_y = self.y

if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()

2 Comments

can you please show how can I export it to an image? btw, this is better than other answer, thanks....
I've never done it before. So, I found this on another SO post. Hope it helps!!! stackoverflow.com/questions/9886274/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.