【问题标题】:Embed Pyqtgraph into Pyqt Textedit将 Pyqtgraph 嵌入 Pyqt Textedit
【发布时间】:2019-09-18 11:07:06
【问题描述】:

我想创建一个文本编辑器,您可以在其中拖放 Pyqtgraph 并与它们实时交互。我无法理解 TextEdit 的行为以及如何将小部件“嵌入”到 TextEdit 本身中。在查看 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 绘画。但最终,我不确定当前 Qt 后端是否可以使用 TextEdit。

【问题讨论】:

  • 我更新了,请看我的回答。
  • @user9402680 谢谢。我需要一些时间来消化所有代码,但它具有我想要的功能。
  • 如果您有难以理解的地方,请随时通过评论或新问题向我提问。不过,如果可能的话,这可能是一个新问题。

标签: python pyqt pyqtgraph qtextedit


【解决方案1】:

请试试这个代码。

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

更新转换

  1. 可以渲染绘图图像,但不渲染数据。 我把pen = 'r': plot.plot(x, y, pen)改成了plot.plot(x, y, pen = 'r')

  2. 绘图图像的数据是脏的并且没有抗锯齿,截取和关闭。 我更新intrinsicSize() 并返回图像宽度和图像高度, 如果您随意在intrinsicSize 中设置return QSizeF() 参数,则结果可能看起来很糟糕。

  3. 尽可能以交互方式进行。 可以看到,这张图是QPainter绘制的。所以,最初,这是非交互式的。我认为这是将结果呈现为QTextObject 的唯一方法。 QTextEdit 不能接受一种小部件作为文本。

  4. 请点击图片前面的。 GraphicsLayoutWidgetshows.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_())

【讨论】:

  • 嘿,我很欣赏写这篇文章的努力,但实际的绘图数据没有显示出来。这是故意的吗?
  • @Michael Choi 之所以会这样是因为我在plot.plot(x, y, pen)之外写了pen = 'r'。我没有想到原因,所以我坚持了一段时间。对不起。
猜你喜欢
  • 2015-04-03
  • 2017-05-31
  • 2019-03-03
  • 2018-08-19
  • 2021-06-18
  • 2017-10-25
  • 2020-08-16
相关资源
最近更新 更多