Python Forum
How to place global tk text widget in class or on canvas
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to place global tk text widget in class or on canvas
#1
I´m making a GUI with an analysis page, where you can drag lines on different plots and get the differences in x position of the lines. I want to somehow display the difference on "PageOne" in a textbox or something similar. In the code below I´ve created global text widgets(at the very end of the code). The problem is that the text widget are also visible on the "StartPage". If I make the text widgets local variables to the PageOne Class I´m no longer able to insert data from the "DraggableLines" classes. So I´m a bit stuck at the moment. Can someone explain a good solution?

# -*- coding: utf-8 -*-
import matplotlib
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)

from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib.widgets import TextBox
import matplotlib.lines as lines
import numpy as np

import tkinter as tk   
from tkinter import ttk
from tkinter.filedialog import askopenfile 

LARGE_FONT= ("Verdana", 12)

a=[0]
b=[0]
c=[0]
difference=[0]
difference1=[0]
    
class AnalysisProgram(tk.Tk):

    def __init__(self, *args, **kwargs):
        
        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.wm_title(self, "Analysisprogram")
        
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        
        self.state('zoomed')

        self.frames = {}

        for F in (StartPage, PageOne):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()
        
class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Front page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        button = ttk.Button(self, text="Under construction",
                            command=lambda: Patient())
        button.pack()

        button2 = ttk.Button(self, text="Analysis", 
                             command=lambda: controller.show_frame(PageOne))
        button2.pack()
        
        button3 = ttk.Button(self, text="Exit",
                             command=lambda: endProgram())
        button3.pack()
        
def Patient():
        file = askopenfile(mode ='r', filetypes =[('Tekstdokumenter', '*.txt')]) 
        if file is not None: 
            content = file.read() 
        # print(content) 
            
def endProgram():
    root.destroy()        
        
class PageOne(tk.Frame):
    """Illustrate how to drag items on a Tkinter canvas"""

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        fig = Figure(figsize=(15, 6), dpi=100)
    
        t = np.arange(0, 3, .01)
        ax = fig.add_subplot(311)
        ax2 = fig.add_subplot(312)
        ax3 = fig.add_subplot(313)
        ax.plot(t, 2 * np.sin(4 * np.pi * t))
        ax2.plot(t, 2 * np.cos(2 * np.pi * t))
        ax3.plot(t, 2 * np.sin(7 * np.pi * t))
                
        # create the canvas
        canvas = FigureCanvasTkAgg(fig, self)  # A tk.DrawingArea.
        canvas.draw()
        canvas.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH, expand=1)    
                
        self.line1 = DraggableLine1(ax, canvas, 0.1)
        self.lin2 = DraggableLine2(ax2, canvas, 0.1)
        self.line3 = DraggableLine3(ax3, canvas, 0.1)
        
        button1 = ttk.Button(self, text="Back to Home",
                            command=lambda: controller.show_frame(StartPage))
        button1.pack()
            
class DraggableLine1():
    def __init__(self, ax1, canvas, XorY1):
        self.ax1 = ax1
        self.c1 = canvas

        self.XorY1 = XorY1

        x1 = [XorY1, XorY1]
        y1 = [-2, 2]
        self.line1 = lines.Line2D(x1, y1, color='red', picker=5)
        self.ax1.add_line(self.line1)
        self.c1.draw_idle()
        self.sid1 = self.c1.mpl_connect('pick_event', self.clickonline1)

    def clickonline1(self, event1):
        if event1.artist == self.line1:
            self.follower1 = self.c1.mpl_connect("motion_notify_event", self.followmouse1)
            self.releaser1 = self.c1.mpl_connect("button_press_event", self.releaseonclick1)

    def followmouse1(self, event1):
        self.line1.set_xdata([event1.xdata, event1.xdata])
        self.c1.draw_idle()

    def releaseonclick1(self, event1):
        self.XorY1 = self.line1.get_xdata()[0]
        del b[:]
        b.insert(1, self.XorY1)
        print(b)
        
        self.tex1.get(0, "end")
        
        del difference[:]
        zip_object = zip(a, b)
        for a_i, b_i in zip_object:
            difference.append(a_i-b_i)
        print(difference)
        tex1.insert('1.0', difference, 'recent') 

        self.c1.mpl_disconnect(self.releaser1)
        self.c1.mpl_disconnect(self.follower1)
        
class DraggableLine2:
  
    def __init__(self, ax, canvas, XorY):
        self.ax = ax
        self.c = canvas

        self.XorY = XorY

        x = [XorY, XorY]
        y = [-2, 2]
        self.line2 = lines.Line2D(x, y, color='red', picker=5)
        self.ax.add_line(self.line2)
        self.c.draw_idle()
        self.sid = self.c.mpl_connect('pick_event', self.clickonline)

    def clickonline(self, event):
        if event.artist == self.line2:
            self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse)
            self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick)

    def followmouse(self, event):
        self.line2.set_xdata([event.xdata, event.xdata])
        self.c.draw_idle()

    def releaseonclick(self, event):
        self.XorY = self.line2.get_xdata()[0]
        del a[:]
        a.insert(1, self.XorY)
        print(a)
        
        del difference[:]
        zip_object = zip(a, b)
        for a_i, b_i in zip_object:
            difference.append(a_i-b_i)
        print(difference)
        tex1.insert('1.0', difference, 'recent') 
        
        del difference1[:]
        zip_object = zip(c, a)
        for c_i, a_i in zip_object:
            difference1.append(c_i-a_i)
        print(difference1)
        tex2.insert('1.0', difference1, 'recent') 
        
        self.c.mpl_disconnect(self.releaser)
        self.c.mpl_disconnect(self.follower)
        
class DraggableLine3:
    def __init__(self, ax3, canvas, XorY3):
        self.ax3 = ax3
        self.c3 = canvas

        self.XorY3 = XorY3

        x3 = [XorY3, XorY3]
        y3 = [-2, 2]
        self.line3 = lines.Line2D(x3, y3, color='red', picker=5)
        self.ax3.add_line(self.line3)
        self.c3.draw_idle()
        self.sid3= self.c3.mpl_connect('pick_event', self.clickonline3)

    def clickonline3(self, event3):
        if event3.artist == self.line3:
            self.follower3 = self.c3.mpl_connect("motion_notify_event", self.followmouse3)
            self.releaser3 = self.c3.mpl_connect("button_press_event", self.releaseonclick3)

    def followmouse3(self, event3):
        self.line3.set_xdata([event3.xdata, event3.xdata])
        self.c3.draw_idle()

    def releaseonclick3(self, event3):
        self.XorY3 = self.line3.get_xdata()[0]
        del c[:]
        c.insert(1, self.XorY3)
        print(c)

        del difference1[:]
        zip_object = zip(c, a)
        for c_i, a_i in zip_object:
            difference1.append(c_i-a_i)
        print(difference1)
        tex2.insert('1.0', difference1, 'recent') 

        self.c3.mpl_disconnect(self.releaser3)
        self.c3.mpl_disconnect(self.follower3)        
        
root = AnalysisProgram()
tex1 = tk.Text(height=1, width=5, font=("Helvetica", 20))
tex2 = tk.Text(height=1, width=5, font=("Helvetica", 20)) 
tex1.place(x=1680, y=490)
tex2.place(x=1680, y=740)
root.mainloop()
Reply
#2
Your DraggableLine class should not know how it is to be used by the application. It should not know that there are multiple instances of draggable line and it should not be putting information in a global variable and it should definitely not know about calculating differences and writing the result in labels. The DraggableLine class should let you drag the line, provide a way to get the location of the line, and have a way to specify a function to be called when the line is moved.

Use Canvas as an example. Canvas does not know anything about DraggableLine, but it provides a way to call DraggableLine.clickonline when the canvas is picked. Your DraggableLine class should have a connect and disconnect for the line moved event. Your application would use this to call a function in the application that knows about all three plots and how to get the cursor/line position from a plot and know about the labels and all the calculations and stuff. If you want to use the DraggableLine information in multiple places you just connect multiple functions to the event.

Since DraggableLine only has one interesting event, you can simplify the connect/disconnect to maintain a list of functions.
class DraggableLine():
    def __init__(self, plot, canvas):
        self.canvas = canvas
        self.callbacks = []
        self.x = 0
        self.cursor = lines.Line2D((self.x, self.x), (-2, 2), color='red', picker=5)
        plot.add_line(self.cursor)
        self.canvas.draw_idle()
        self.canvas.mpl_connect('pick_event', self.pick_callback)

    def connect(self, func):
        self.callbacks.append[func]
        return func # App will use as handle for disconnect

    def disconnect(self, handle):
        self.callbacks.remove(handle)

    def pick_callback(self, event):
        if event.artist == self.cursor:
            self.move = self.canvas.mpl_connect("motion_notify_event", self.move_callback)
            self.release = self.canvas.mpl_connect("button_press_event", self.button_callback)
 
    def move_callback(self, event):
        self.x = event.xdata
        self.cursor.set_xdata([self.x, self.x])
        self.canvas.draw_idle()
 
    def button_callback(self, event):
        self.canvas.mpl_disconnect(self.move)
        self.canvas.mpl_disconnect(self.release)
        for cb in self.callbacks():
            cb()
Somewhere in you application you would write a function to calculate differences and update the results.
def update_cusor_displays():
    a = pageOne.line1.x
    b = pageOne.line2.x
    c = pageOne.line3.x
    tex1Value = str(b-a)
    tex2Value = str(c-a)

pageOne.line1.connect(update_cursor_displays)
pageOne.line2.connect(update_cursor_displays)
pageOne.line3.connect(update_cursor_displays)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Text widget inert mode on and off rfresh737 5 576 Apr-19-2021, 02:18 PM
Last Post: joe_momma
  Line numbers in Text widget rfresh737 3 387 Apr-15-2021, 12:30 PM
Last Post: rfresh737
  [Tkinter] canvas widget scroll issue chrisdb 2 391 Apr-07-2021, 05:48 AM
Last Post: chrisdb
  tkinter text widget word wrap position chrisdb 6 1,215 Mar-18-2021, 03:55 PM
Last Post: chrisdb
  Label.Place did not work? ATARI_LIVE 15 1,160 Sep-18-2020, 04:22 PM
Last Post: ATARI_LIVE
  [PyQt] remove widget from other class issac_n 2 695 Aug-05-2020, 01:55 PM
Last Post: deanhystad
  [Tkinter] Get the last entry in my text widget Pedroski55 3 1,304 Jul-13-2020, 10:34 PM
Last Post: Pedroski55
  [Tkinter] How to place scroll bar correctly scratchmyhead 1 1,131 May-18-2020, 04:17 PM
Last Post: scratchmyhead
  How to use place holders in tkinter sqlite scratchmyhead 1 607 May-12-2020, 06:13 PM
Last Post: Larz60+
  [Tkinter] manipulation of string in Text widget Stauricus 2 1,086 Feb-17-2020, 09:23 PM
Last Post: Stauricus

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020