将 Pyqtgraph 嵌入 Pyqt Textedit

Embed Pyqtgraph into Pyqt Textedit

我想创建一个文本编辑器,您可以在其中拖放 Pyqtgraph 并与它们实时交互。我无法理解 TextEdit 的行为以及 Widget 如何在 TextEdit 本身中 'embedded'。查看 API 后,似乎只有文本、html 和图像可以添加到 QTextEdit 中。

我可能在这里抓住了救命稻草,但我希望有一个 void QTextEdit::insertWidget(QWidget*) 或类似的东西。

为了澄清这里是一个不完整的示例代码:

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_())

我的一些想法是将 pyqtgraph 覆盖在空白图像上,或者尝试找到某种我可以插入并覆盖 paintevent 的文本小部件以为其提供 pyqtgraph 绘画。然而,最终,我不确定这在当前带有 TextEdit 的 Qt 后端是否可行。

请尝试此代码。

如果您想了解更多信息,请通过评论询问我。 不知道大家喜不喜欢这样的结果

更新过渡

  1. plot图像可以渲染但是数据不渲染。 我将 pen = 'r': plot.plot(x, y, pen) 更改为 plot.plot(x, y, pen = 'r')

  2. plot图片数据脏,没有抗锯齿,断断续续截取。 我更新 intrinsicSize() 和 return 图像宽度和图像高度, 如果你在 intrinsicSize 中随意设置 return QSizeF() 参数,你可能会看到一个糟糕的结果。

  3. 尽可能互动。 可以看到,这张图是由QPainter绘制的。所以,最初,这是 uninteractive.I 认为这是将结果呈现为 QTextObject 的唯一方法。 QTextEdit 无法接受一种小部件作为文本。

  4. 请点击图片前的 GraphicsLayoutWidget shows.and 您更改图表内容,然后关闭它。下一次,图像被重新绘制并再次渲染。

  5. 我删除了不需要的代码。

无论如何,我尝试做到这一点。

请通过评论向我询问更多信息。

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_())