简体   繁体   English

将 Pyqtgraph 嵌入 Pyqt Textedit

[英]Embed Pyqtgraph into Pyqt Textedit

I'd like to create a text editor where you can drag and drop Pyqtgraphs and interact with them real-time.我想创建一个文本编辑器,您可以在其中拖放 Pyqtgraphs 并与它们实时交互。 I am having trouble understanding the behavior of TextEdit and how a Widget could be 'embedded' within the TextEdit itself.我无法理解 TextEdit 的行为以及如何将小部件“嵌入”到 TextEdit 本身中。 After review the API it seems that only text, html, and images can be added into the QTextEdit.查看 API 后,似乎只能将文本、html 和图像添加到 QTextEdit 中。

I might be grasping at straws here, but I was hoping that there was a void QTextEdit::insertWidget(QWidget*) or something of that nature.我可能在这里抓住了稻草,但我希望有一个void QTextEdit::insertWidget(QWidget*)或类似的东西。

To clarify here is an incomplete sample code:澄清这里是一个不完整的示例代码:

import sys
import numpy as np

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import pyqtgraph as pg


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

        self.textEdit = QTextEdit(self)
        self.setCentralWidget(self.textEdit)

        toolbar = QToolBar()

        plotAction = QAction('Plot', self)
        plotAction.triggered.connect(self.addPlot)
        toolbar.addAction(plotAction)

        self.addToolBar(toolbar)

        self.setGeometry(300, 100, 800, 1000)

    def addPlot(self):
        x = np.linspace(0, 10, 100)
        y = np.sin(x)

        glWidget = pg.GraphicsLayoutWidget()
        plot = glWidget.addPlot()
        plot.plot(x, y, pen='r')

        # I'd like to be able to use a line such as this
        # self.textEdit.textCursor().insertWidget(glWidget)
        self.textEdit.textCursor().insertText('I want to insert a widget pointer instead.')


if __name__ == "__main__":
    app = QApplication(sys.argv)
    pte = PlotTextEditor()
    pte.show()
    sys.exit(app.exec_())

Some ideas I had were to overlay the pyqtgraph over a blank image, or try to find some kind of text widget I can insert and override paintevent to give it the pyqtgraph paint.我的一些想法是将 pyqtgraph 覆盖在空白图像上,或者尝试找到某种文本小部件,我可以插入并覆盖 Paintevent 以赋予它 pyqtgraph 绘制。 Ultimately however, I am not sure if this is even possible with the current Qt backend with TextEdit.然而,最终,我不确定当前的 Qt 后端是否可以使用 TextEdit。

Please try this Code.请试试这个代码。

If you want to further information , please ask me by comment.如果您想了解更多信息,请通过评论问我。 I don't know if you like this result or not.不知道你们喜不喜欢这个结果。

UPDATE TRANSITION更新过渡

  1. plot image can be rendered but the data is not rendered.可以渲染绘图图像,但不渲染数据。 I changed pen = 'r': plot.plot(x, y, pen) to plot.plot(x, y, pen = 'r')我改变了pen = 'r': plot.plot(x, y, pen)plot.plot(x, y, pen = 'r')

  2. the data of plot image is dirty and not antialiased, intercepted on and off.绘图图像的数据是脏的,没有抗锯齿,断断续续地截取。 I update intrinsicSize() and return image width and image height, You can look a bad result if you set return QSizeF() argument in intrinsicSize as you like.我更新了intrinsicSize()并返回图像宽度和图像高度,如果您根据return QSizeF()intrinsicSize设置return QSizeF()参数,您可能会看到一个糟糕的结果。

  3. Interactively as possible as we can.尽可能互动。 As you can see, this image is drawn by QPainter .如您所见,此图像是由QPainter绘制的。 So , originally, this is uninteractive.I think this is the only way for rendering your result as QTextObject .所以,最初,这是非交互式的。我认为这是将结果呈现为QTextObject的唯一方法。 QTextEdit can't accept a kind of widgets as text. QTextEdit不能接受一种小部件作为文本。

  4. Please click in front of the image.请点击图片前面的。 GraphicsLayoutWidget shows.and you change the graph contents, and you close it. GraphicsLayoutWidget显示。您更改图形内容,然后关闭它。 And the next time, the image is redrawn and rendered again.下一次,图像被重新绘制和渲染。

  5. I deleted needless code.我删除了不必要的代码。

Anyway, I tried to do until this point.不管怎样,我一直努力做到这一点。

Please ask me about further imformation by comment.请通过评论向我询问更多信息。

import sys
import numpy as np

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import pyqtgraph as pg
import pyqtgraph.exporters

import os
plot_image_dict = {}
class PlotObjectInterface(QObject, QTextObjectInterface):
    def __init__(self, parent=None):
        super(PlotObjectInterface, self).__init__(parent=None)
    def drawObject(self, painter, rect, doc, posInDocument, format):      
        img = format.property(1)
        painter.save()        
        painter.setRenderHints(QPainter.Antialiasing)
        painter.drawImage(QRectF(rect), img)
        painter.restore()
    def intrinsicSize(self, doc, posInDocument, format):
        img = format.property(1)
        width = img.size().width()
        height = img.size().height()
        return QSizeF(width, height)

class PlotTextEdit(QTextEdit):
    def __init__(self):
        super().__init__()        
class PlotView(QGraphicsView):
    def __init__(self):
        super().__init__()
        self.plot_scene = QGraphicsScene()
        self.plot_tedit = PlotTextEdit()
        self.plot_tedit.resize(800, 1000)
        self.plot_scene.addWidget(self.plot_tedit)
        self.setScene(self.plot_scene)
class PlotGraphicsLayoutWidget(pg.GraphicsLayoutWidget):
    def __init__(self):
        super().__init__()        
        self.current_edit_filename = ""
        self.current_edit_imagenum = 0
        self.current_edit_image = QImage()
        self.current_edit_position = 0
    def updateImage(self):
        #overwrite the image
        pg.QtGui.QApplication.processEvents()
        exporter = pg.exporters.ImageExporter(self.scene())
        filename = os.path.join(self.current_edit_filename)
        exporter.export(filename)     
        image = QImage()
        image.load(filename)
        image_info = plot_image_dict[self.current_edit_imagenum]  
        tc = QTextCursor(self.current_text_edit.document())
        tc.setPosition(image_info[3] - 1, tc.MoveAnchor)
        tc.movePosition(tc.Right, tc.KeepAnchor, 1)
        tc.setKeepPositionOnInsert(True)
        char = QTextCharFormat()
        char.setObjectType(QTextFormat.UserObject + 1)              
        char.setProperty(1, image)
        char.setProperty(2, image_info[1])
        char.setProperty(3, image_info[2])
        char.setProperty(4, image_info[3])        
        plot_image_dict[self.current_edit_imagenum] = [image, image_info[1], image_info[2], image_info[3]]
        tc.insertText("\ufffc", char)
        tc.setKeepPositionOnInsert(False)
    def closeEvent(self, event):
        self.updateImage()
        return pg.GraphicsLayoutWidget.closeEvent(self, event)
class PlotTextEditor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.plotview = PlotView()
        self.pyplotObjectInterface = PlotObjectInterface()
        self.plotview.plot_tedit.document().documentLayout().registerHandler(QTextFormat.UserObject+1,self.pyplotObjectInterface)    
        self.plotview.plot_tedit.viewport().installEventFilter(self)
        self.setCentralWidget(self.plotview)
        toolbar = QToolBar()
        plotAction = QAction('Plot', self)
        plotAction.triggered.connect(self.insertImage)
        toolbar.addAction(plotAction)
        self.addToolBar(toolbar)
        self.setGeometry(300, 100, 800, 1000)    
        self.test_glWidget = PlotGraphicsLayoutWidget()
        self.test_glWidget.current_text_edit = self.plotview.plot_tedit

        self.test_manipulation = False
        x = np.linspace(0, 10, 100)
        y = np.sin(x)               
        plot = self.test_glWidget.addPlot()       
        #PlotDataItem
        plot.plot(x, y, pen = 'b')
    def closeEvent(self, event):
        QApplication.closeAllWindows()
        return QMainWindow.closeEvent(self, event)
    def eventFilter(self, obj, event):    
        if event.type() == QMouseEvent.MouseButtonPress and  obj == self.plotview.plot_tedit.viewport():
            tc = self.plotview.plot_tedit.textCursor()
            position = tc.position()
            tc.movePosition(tc.Left, tc.KeepAnchor,1)
            if tc.selectedText() == "\ufffc":                
                self.editImage(tc)                            
            tc.clearSelection()
            tc.setPosition(position)            
            p_next = position + 1
            tc.setPosition(p_next, tc.KeepAnchor)
            if tc.selectedText() == "\ufffc":
                print("next character is \ufffc")
                tc.clearSelection()
                self.editImage(tc)                  
            return False
        return QMainWindow.eventFilter(self, obj, event)
    def editImage(self, tc):        
        tc = QTextCursor(tc)
        rect = self.plotview.plot_tedit.cursorRect(tc)
        topLeft = rect.topLeft()
        child_topLeft = self.plotview.mapToGlobal(topLeft)
        char = tc.charFormat()
        plot_img =  char.property(1)
        plot_num = char.property(2)
        filename = char.property(3)
        char.setProperty(4, tc.position())
        if plot_img  is not None:                    
            geometry = QRect(topLeft,QSize(plot_img .width(), plot_img .height()))
            self.test_glWidget.current_edit_filename = filename
            self.test_glWidget.current_edit_imagenum = plot_num
            self.test_glWidget.current_edit_image = plot_img
            self.test_glWidget.current_edit_position = tc.position()
            plot_image_dict[self.test_glWidget.current_edit_imagenum] = [plot_img, plot_num, filename,  tc.position()]
            self.test_glWidget.setGeometry(geometry)
            self.test_glWidget.show()    
    def insertImage(self):        
        pg.QtGui.QApplication.processEvents()
        exporter = pg.exporters.ImageExporter(self.test_glWidget.scene())
        filename = os.path.join(os.getcwd(), "plot.png")
        exporter.export(filename)
        plot_img = QImage()
        plot_img.load(filename)        
        plot_num = len(plot_image_dict)
        plot_char = QTextCharFormat()
        plot_char.setObjectType(QTextFormat.UserObject+1)        
        plot_char.setProperty(1, plot_img)     
        plot_char.setProperty(2, plot_num)
        plot_char.setProperty(3, filename)        
        plot_char.setProperty(4, 0)
        self.plotview.plot_tedit.textCursor().insertText("\ufffc", plot_char)
        plot_image_dict[plot_num] = [plot_img, plot_num, filename, 0]
if __name__ == "__main__":
    app = QApplication(sys.argv)
    pte = PlotTextEditor()
    pte.show()
    sys.exit(app.exec_())

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

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