如何在鼠标单击时在 FigureCanvasQTAgg 上绘制一个圆圈 [英] How to draw a circle on a FigureCanvasQTAgg on mouse click

查看:32
本文介绍了如何在鼠标单击时在 FigureCanvasQTAgg 上绘制一个圆圈的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 Qt 的新手,我正在尝试做一个我以前在 tkinter 中做过的程序,以了解如何使用它.我在 Qt 窗口中嵌入了一个 FigureCanvasQtAgg .我已经在上面画了东西.现在我想在这个画布上绘制一个用户点击鼠标的圆圈.

I am new to Qt and I am trying to do a program, that I've previously done in tkinter, to learn how to use it. I have embedded a FigureCanvasQtAgg in a Qt window. I have ploted thing on it. Now I want to plot on this canvas a circle on user's mouse click.

我在Tkinter上所做的就是使用

What I have done to do it on Tkinter is to use :

self.canvas.get_tk_widget().create_oval()

在PySide2中是否有一种简单的方法来获得相同的结果?

Is there a simple way to have the same results in PySide2?

这是我尝试过的更简单的代码:

Here is a simpler code with what I've tried :

from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt


import numpy as np
import sys


class MyPaintWidget(QWidget):

    def __init__(self):
        super().__init__()
        layout_canvas = QVBoxLayout()
        self.fig = plt.gcf()
        plt.plot(np.cos([i for i in np.arange(0, 10, 0.1)]))
        self.canvas = FigureCanvas(self.fig)
        self.canvas.mpl_connect('button_press_event', self._on_left_click)
        layout_canvas.addWidget(self.canvas)
        self.setLayout(layout_canvas)

    def _on_left_click(self, event):
        print(event.xdata, event.ydata)
        qp = QPainter()
        qp.drawEllipse(QPointF(event.x, event.y), 10, 10)
        qp.end()
        self.canvas.draw()

if __name__=="__main__":
    app = QApplication(sys.argv)

    w = MyPaintWidget()
    w.show()

    app.exec_()

我在tkinter中所做的事情(当我在画布上单击时,确实出现了绿点):

What I have done in tkinter (when I click on the canvas a green point does appear) :

import tkinter as tk
import tkinter.ttk as ttk
import numpy as np
import sys

from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
import matplotlib.pyplot as plt


class MainFrame(ttk.Frame):
    def __init__(self, master):
        ttk.Frame.__init__(self, master)
        self.master = master
        self.fig = plt.gcf()
        plt.plot(np.cos([i for i in np.arange(0, 10, 0.1)]))
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.master)  # A tk.DrawingArea.
        self.canvas.get_tk_widget().grid(row=0, column=0)
        self.canvas.draw()
        self.canvas.mpl_connect('button_press_event', self._on_left_click)

    def _on_left_click(self, event):
        self._add_point(event.x, event.y)

    def _add_point(self, x, y):
        self.canvas.get_tk_widget().create_oval(x - 4, self.canvas.get_tk_widget().winfo_height() - (y - 4), x + 4,
                                                self.canvas.get_tk_widget().winfo_height() - (y + 4), fill='green')


if __name__=="__main__":
    window = tk.Tk()
    main_frame = MainFrame(window)
    window.mainloop()

有什么想法可以在 QT 中得到这个结果吗?谢谢!

Any ideas to get this result in QT ? Thanks !

推荐答案

与 tkinter 不同,Qt 没有实现像 create_oval() 这样的函数来制作圆圈,所以另一种选择是使用 matplotlib 的工具.

Unlike tkinter Qt does not implement a function like create_oval() to make the circles so an alternative is to use the tools of matplotlib.

from PySide2 import QtCore, QtGui, QtWidgets

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt

import numpy as np


class MyPaintWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        self.figure = plt.gcf()
        self.canvas = FigureCanvas(self.figure)
        self.canvas.mpl_connect("button_press_event", self._on_left_click)
        self.axes = self.figure.add_subplot(111)
        x = np.arange(0, 10, 0.1)
        y = np.cos(x)
        self.axes.plot(x, y)

        layout_canvas = QtWidgets.QVBoxLayout(self)
        layout_canvas.addWidget(self.canvas)

    def _on_left_click(self, event):
        self.axes.scatter(event.xdata, event.ydata)
        self.figure.canvas.draw()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MyPaintWidget()
    w.show()
    sys.exit(app.exec_())

另一种可能的解决方案是实现从类 FigureCanvas 继承的 create_oval() 方法:

Another possible solution is to implement the method create_oval() inheriting from the class FigureCanvas:

from PySide2 import QtCore, QtGui, QtWidgets

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

import numpy as np


class PainterCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        self._instructions = []
        self.axes = self.figure.add_subplot(111)

    def paintEvent(self, event):
        super().paintEvent(event)
        painter = QtGui.QPainter(self)
        painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
        width, height = self.get_width_height()
        for x, y, rx, ry, br_color in self._instructions:
            x_pixel, y_pixel_m = self.axes.transData.transform((x, y))
            # In matplotlib, 0,0 is the lower left corner, 
            # whereas it's usually the upper right 
            # for most image software, so we'll flip the y-coor
            y_pixel = height - y_pixel_m
            painter.setBrush(QtGui.QColor(br_color))
            painter.drawEllipse( QtCore.QPoint(x_pixel, y_pixel), rx, ry)

    def create_oval(self, x, y, radius_x=5, radius_y=5, brush_color="red"):
        self._instructions.append([x, y, radius_x, radius_y, brush_color])
        self.update()


class MyPaintWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        self.canvas = PainterCanvas()
        self.canvas.mpl_connect("button_press_event", self._on_left_click)
        x = np.arange(0, 10, 0.1)
        y = np.cos(x)
        self.canvas.axes.plot(x, y)

        layout_canvas = QtWidgets.QVBoxLayout(self)
        layout_canvas.addWidget(self.canvas)

    def _on_left_click(self, event):
        self.canvas.create_oval(event.xdata, event.ydata, brush_color="green")


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MyPaintWidget()
    w.show()
    sys.exit(app.exec_())

这篇关于如何在鼠标单击时在 FigureCanvasQTAgg 上绘制一个圆圈的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆