Вставить Pyqtgraph в Pyqt Textedit - PullRequest
2 голосов
/ 29 апреля 2019

Я хотел бы создать текстовый редактор, где вы можете перетаскивать Pyqtgraphs и взаимодействовать с ними в режиме реального времени.У меня возникают проблемы с пониманием поведения TextEdit и того, как виджет может быть «встроен» в сам TextEdit.После просмотра API кажется, что в QTextEdit могут быть добавлены только текст, html и изображения.

Я мог бы ухватиться здесь за соломинку, но я надеялся, что там было void QTextEdit::insertWidget(QWidget*) или что-то подобноеnature.

Для пояснения приведен неполный пример кода:

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 поверх пустого изображения или попытаться найти какой-нибудь текстовый виджет Iможно вставить и переопределить painttevent, чтобы дать ему краску pyqtgraph.В конечном счете, однако, я не уверен, возможно ли это даже с текущим бэкэндом Qt с TextEdit.

1 Ответ

2 голосов
/ 01 мая 2019

Пожалуйста, попробуйте этот код.

Если вы хотите получить дополнительную информацию, пожалуйста, спросите меня по комментарию.Я не знаю, нравится вам этот результат или нет.

ОБНОВЛЕНИЕ ПЕРЕХОДА

  1. графическое изображение может быть отображено, но данные не отображаются,Я изменил pen = 'r': plot.plot(x, y, pen) на plot.plot(x, y, pen = 'r')

  2. данные изображения графика загрязнены и не сглажены, перехватываются, включаются и выключаются.Я обновляю intrinsicSize() и возвращаю ширину и высоту изображения. Вы можете получить плохой результат, если установите intrinsicSize аргумент в *1019* как хотите.

  3. Интерактивно, насколько это возможно, какмы можем.Как видите, это изображение нарисовано QPainter.Итак, изначально это неинтересно. Я думаю, что это единственный способ отобразить ваш результат как QTextObject.QTextEdit не может принимать виджеты в виде текста.

  4. Пожалуйста, нажмите перед изображением.GraphicsLayoutWidget показывает.и вы меняете содержимое графика, и закрываете его.И в следующий раз изображение перерисовывается и снова отображается.

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