简体   繁体   English

如何通过鼠标在 gui 或图形中绘制交互式固定网格? /python / matplotlib / pyqt5

[英]how to draw by mouse an interactive fixed grid within a gui or figure? /python / matplotlib / pyqt5

The below code allows me to draw an interactive rectangle and control its size and location by mouse.下面的代码允许我绘制一个交互式矩形并通过鼠标控制它的大小和位置。

In the same way, how do I draw a fixed interactive grid mXn (see the image at the link below) instead of a rectangle?同理,我如何绘制一个固定的交互式网格 mXn(参见下面链接中的图像)而不是矩形?

from matplotlib.widgets import RectangleSelector
import numpy as np
import matplotlib.pyplot as plt


def line_select_callback(eclick, erelease):
    'eclick and erelease are the press and release events'
    x1, y1 = eclick.xdata, eclick.ydata
    x2, y2 = erelease.xdata, erelease.ydata
    print("(%3.2f, %3.2f) --> (%3.2f, %3.2f)" % (x1, y1, x2, y2))
    print(" The button you used were: %s %s" % (eclick.button, erelease.button))


def toggle_selector(event):
    print(' Key pressed.')
    if event.key in ['Q', 'q'] and toggle_selector.RS.active:
        print(' RectangleSelector deactivated.')
        toggle_selector.RS.set_active(False)
    if event.key in ['A', 'a'] and not toggle_selector.RS.active:
        print(' RectangleSelector activated.')
        toggle_selector.RS.set_active(True)


fig, current_ax = plt.subplots()                 # make a new plotting range
N = 100000                                       # If N is large one can see
x = np.linspace(0.0, 10.0, N)                    # improvement by use blitting!

plt.plot(x, +np.sin(.2*np.pi*x), lw=3.5, c='b', alpha=.7)  # plot something
plt.plot(x, +np.cos(.2*np.pi*x), lw=3.5, c='r', alpha=.5)
plt.plot(x, -np.sin(.2*np.pi*x), lw=3.5, c='g', alpha=.3)

print("\n      click  -->  release")

# drawtype is 'box' or 'line' or 'none'
toggle_selector.RS = RectangleSelector(current_ax, line_select_callback,
                                       drawtype='box', useblit=True,
                                       button=[1, 3],  # don't use middle button
                                       minspanx=5, minspany=5,
                                       spancoords='pixels',
                                       interactive=True)
plt.connect('key_press_event', toggle_selector)
plt.show()

image of the mXn fixed grid mXn 固定网格的图像

If I understood it correctly, m and n are constants.如果我理解正确,m 和 n 是常数。 If not, you can set them high enough.如果没有,您可以将它们设置得足够高。 Matplotlib is designed for plotting functions, so PyQt5 is probably a much better choice (especially if you extend the functionality further). Matplotlib 专为绘图功能而设计,因此 PyQt5 可能是更好的选择(尤其是如果您进一步扩展功能)。

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        title = "Grid"
        top = 400
        left = 400
        width = 800
        height = 600

        self.m = 8
        self.n = 6
        self.x1 = 0
        self.x2 = 0
        self.y1 = 0
        self.y2 = 0
        self.st_x = 0
        self.st_y = 0

        self.mode = "draw"

        self.setWindowTitle(title)
        self.setGeometry(top, left, width, height)

        self.image = QImage(self.size(), QImage.Format_RGB32) # creating canvas
        self.image.fill(Qt.white)
    
    def mousePressEvent(self, event):
        if self.x1 < event.x() < self.x2 and self.y1 < event.y() < self.y2:
            # mouse pressed in grid area
            self.mode = "move"
            self.st_x = event.x()
            self.st_y = event.y()

        else:
            self.mode = "draw"
            self.x1 = event.x()
            self.y1 = event.y()
        
        self.image.fill(Qt.white)
        self.update()
    
    def mouseReleaseEvent(self, event):
        if self.mode == "draw":
            self.x2 = event.x()
            self.y2 = event.y()
        
        else:
            x_delta = event.x() - self.st_x # 'delta' would be a x, y vector drawn by mouse press and release
            y_delta = event.y() - self.st_y

            self.x1 += x_delta
            self.y1 += y_delta
            self.x2 += x_delta
            self.y2 += y_delta

        self.draw_grid((self.x1, self.y1), (self.x2, self.y2), 50, 50)

    def paintEvent(self, event):
        canvasPainter = QPainter(self)
        canvasPainter.drawImage(
            self.rect(), self.image, self.image.rect()
        )
         
    def draw_grid(self, start, end, rect_width, rect_height):
        painter = QPainter(self.image)
        painter.setPen(
            QPen(Qt.black, 5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        )
        
        for y in range(self.n):
            for x in range(self.m):
                if start[0] + rect_width*x < end[0] and start[1] + rect_height*y < end[1]:
                    painter.drawRect(
                        QRect(start[0] + rect_width*x, start[1] + rect_height*y, rect_width, rect_height)
                    )

        self.update()
 

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

    sys.exit(app.exec()) # may want to remove sys.exit

Update: In your example, a QGraphicsScene is used, unlike here.更新:在您的示例中,使用了QGraphicsScene ,与此处不同。 I don't know if this object provides any advantage but if you want to see the grid moving, while you are holding the mouse button, you can easily override the mouseMoveEvent , like in the example.我不知道这个 object 是否提供任何优势,但如果您想看到网格移动,同时按住鼠标按钮,您可以轻松地覆盖mouseMoveEvent ,就像在示例中一样。 QMainWindow inherits this event from QWidget . QMainWindowQWidget继承此事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM