首页 > 解决方案 > 获取类中的鼠标点击坐标 - python

问题描述

我想在一个类中获取鼠标点击坐标。我在使用 tkinter 之前已经这样做了,但是我无法将它集成到更复杂的上下文中(在一个类中)

我当前的代码在两个图表之间切换,效果很好,但是我希望能够在第二个图表上获得鼠标点击坐标。

到目前为止,这是我的代码(试图使其成为最小的工作代码):

import math
import scipy  as sp
from scipy import signal
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.widgets import Cursor
import tkinter as tk
from matplotlib.widgets import Button

matplotlib.use( 'tkagg' )

from tkinter import *
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
# Implement the default Matplotlib key bindings.
from matplotlib.backend_bases import key_press_handler


# make some data:
x_axis = np.arange(0, 10, 0.1)
data = np.sin(x_axis)

zero_crossings = np.where(np.diff(np.sign(data)))[0]
y_axis = [0, 0, 0, 0]


def find_nearest(array, value):
    idx = (np.abs(array-value)).argmin()
    return array[idx]

def config_plot():
    tk, ax = plt.subplots()
    ax.set(title='Count the steps! \n Are there 10 steps??')
    return (tk, ax)


class matplotlibSwitchGraphs:
    def __init__(self, master):
        self.master = master
        self.frame = Frame(self.master)
        self.fig, self.ax = config_plot()
        self.graphIndex = 0
        self.canvas = FigureCanvasTkAgg(self.fig, self.master)  
        self.config_window()
        self.draw_graph_one()
        self.frame.pack(expand=YES, fill=BOTH)

    def config_window(self):
        self.canvas.mpl_connect("key_press_event", self.on_key_press)
        toolbar = NavigationToolbar2Tk(self.canvas, self.master)
        toolbar.update()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        self.button = Button(self.master, text="YES", command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="NO", command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)

    def draw_graph_one(self):
        self.ax.clear() # clear current axes
        self.ax.plot(data)
        self.ax.plot(zero_crossings, y_axis, marker='o', linestyle='none')
        self.ax.set(title='Check the data \n Are the touchdowns and toeoffs in the right spots? \n are there 10 steps?')
        self.canvas.draw()

    def draw_graph_two(self):
        self.ax.clear()
        self.ax.plot(data)
        self.ax.set(title='Instructions: \n 1) click the incorrect step \n 2)Click where it should be')
        self.ax.plot(zero_crossings, y_axis, marker='o', linestyle='none')
        self.canvas.draw()
        #Want to get imput from 2 mouse clicks!!!! 

    def on_key_press(event):
        print("you pressed {}".format(event.key))
        key_press_handler(event, self.canvas, toolbar)

    def _quit(self):
        self.master.quit()  # stops mainloop

    def switch_graphs(self):
        # Need to call the correct draw, whether we're on graph one or two
        self.graphIndex = (self.graphIndex + 1 ) % 2
        if self.graphIndex == 0:
            self.draw_graph_one()
        else:
            self.draw_graph_two()

def main():
    root = Tk()
    matplotlibSwitchGraphs(root)
    root.mainloop()

if __name__ == '__main__':
    main()

理想情况下,最后我希望第一次单击删除一个标记(toeoff_cut 或 touchdown_cut),然后第二次单击将其放置在一个新位置......但现在只需获取点击的坐标会很有帮助!

有任何想法吗?谢谢!

标签: pythontkinter

解决方案


如果你想获得鼠标点击,那么你必须使用它"button_press_event"来代替"key_press_event"键盘键。

self.canvas.mpl_connect("button_press_event", self.on_key_press)

或者您可以同时使用两者 - 您可以分配给不同的方法

self.canvas.mpl_connect("key_press_event", self.on_key_press)
self.canvas.mpl_connect("button_press_event", self.on_button_press)

def on_button_press(self, event):
    print('-----')
    print('button:', event.button)
    print('xdata, ydata:', event.xdata, event.ydata)
    print('x, y:', event.x, event.y)
    print('canvas:', event.canvas)
    print('inaxes:', event.inaxes)

您可以在matplotlib.pyplot.connect事件处理中找到更多类型的事件

(但我似乎没有DoubleClick鼠标)


如果要断开事件,则必须保留 mpl_connect 返回的值

 # connect

 self.button_press_id = self.canvas.mpl_connect("button_press_event", self.on_button_press)

 # disconnect

 self.canvas.mpl_disconnect(self.button_press_id)

这样您就可以对不同的绘图使用不同的功能。


最小的工作代码:

from tkinter import * # PEP8: `import *` is not preferred

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure


# (not so) random data
import random
random.seed(0) # will give the same values in every execution
Z_filt_1 = [random.randint(0, 100) for _ in range(10)]
Z_filt_2 = [random.randint(0, 100) for _ in range(10)]


class MatPlotLibSwitchGraphs:

    def __init__(self, master):
        self.master = master

        self.frame = Frame(self.master)
        self.frame.pack(expand=YES, fill=BOTH)

        self.fig = Figure(figsize=(5, 4), dpi=100)
        self.ax = self.fig.gca() #config_plot()

        self.canvas = FigureCanvasTkAgg(self.fig, self.master)  
        self.config_window()

        self.graphIndex = 0
        self.draw_graph_one()

    def config_window(self):
        toolbar = NavigationToolbar2Tk(self.canvas, self.master)
        toolbar.update()

        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)

        print('connect')
        self.canvas.mpl_connect("key_press_event", self.on_key_press)
        self.canvas.mpl_connect("button_press_event", self.on_button_press)

        self.button = Button(self.master, text="QUIT", command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="CHANGE PLOT", command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)

    def draw_graph_one(self):
        self.ax.clear()
        self.ax.plot(Z_filt_1)
        self.ax.set(title='First Plot')
        self.canvas.draw()

    def draw_graph_two(self):
        self.ax.clear()
        self.ax.plot(Z_filt_2)
        self.ax.set(title='Second Plot')
        self.canvas.draw()

    def on_key_press(self, event):
        print('key:', event.key)

    def on_button_press(self, event):
        print('-----')
        print('button:', event.button)
        print('xdata, ydata:', event.xdata, event.ydata)
        print('x, y:', event.x, event.y)
        print('canvas:', event.canvas)
        print('inaxes:', event.inaxes)

    def _quit(self):
        #self.master.quit()  # stops mainloop
        self.master.destroy() # works better then `quit()` (at least on Linux)

    def switch_graphs(self):
        # Need to call the correct draw, whether we're on graph one or two
        self.graphIndex = (self.graphIndex + 1 ) % 2
        if self.graphIndex == 0:
            self.draw_graph_one()
        else:
            self.draw_graph_two()

def main():
    root = Tk()
    MatPlotLibSwitchGraphs(root)
    root.mainloop()

if __name__ == '__main__':
    main()

顺便说一句: PEP 8——Python 代码风格指南


推荐阅读