Получение ограничительной рамки выбора QTextEdit

Я пытаюсь получить ограничивающую рамку из серии выделенных текстов, сохраненных в списке. Ограничительная рамка - это самый маленький прямоугольник, который может содержать весь выбор. Каждый элемент в списке имеет начальную и конечную точки, измеренные в символах от начала QTextEdit окно, а также идентификатор письма. QTextEdit.cursorRect(cursor) должен сделать это, но производит бессмысленные размеры коробки:

id: A -- PySide.QtCore.QRect(0, 0, 1, 10)
id: B -- PySide.QtCore.QRect(0, 0, 1, 10)
id: C -- PySide.QtCore.QRect(0, 0, 1, 10)

Все выборки начинаются в разных точках, поэтому (0,0) неверно в координатах точки обзора. Кроме того, некоторые из них занимают несколько строк, поэтому ширина и высота должны варьироваться. Проблема может заключаться в том, что курсор находится в цикле, и я не устанавливаю его setTextCursor пока не закончится цикл. Я делаю это, потому что я также рендеринг выделений в качестве основных моментов. Как я могу получить cursorRect правильно работать или иначе получить отдельную ограничивающую рамку для каждого выбора? Вот код:

import sys
from PySide.QtCore import *
from PySide.QtGui import *

db = ((5,8,'A'),(20,35,'B'),(45,60,'C')) # start, end, and identifier of highlights

class TextEditor(QTextEdit):

    def __init__(self, parent=None):
        super().__init__(parent)
        text="This is example text that is several lines\nlong and also\nstrangely broken up and can be\nwrapped."
        self.setText(text)
        for n in range(0,len(db)):
            row = db[n]
            startChar = row[0]
            endChar = row[1]
            id = row[2]

            cursor = self.textCursor()
            cursor.setPosition(startChar)
            cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor, endChar-startChar)

            rect = self.cursorRect(cursor)
            print("id: %s -- %s" % (id,str(rect)))

            charfmt = cursor.charFormat()
            charfmt.setBackground(QColor(Qt.yellow))
            cursor.setCharFormat(charfmt)
        cursor.clearSelection()
        self.setTextCursor(cursor)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    editor = TextEditor()
    editor.show()
    app.exec_()
    sys.exit(app.exec_())

РЕДАКТИРОВАТЬ 1:

Вот текст из программы. Я буду использовать CAPS для выделенного текста:

This IS example text THAT IS SEVERAL lines
loNG AND ALSO
STRangely broken up and can be
wrapped.

Давайте предположим, что каждый символ 10 пикселей на 10 пикселей. "IS " начинается с 5 символов и продолжается до 3 символов (включая пробел в конце). Таким образом, верхний левый угол "я" будет в х =50, у =0. Нижний правый угол пространства будет при х =80, у =10. Если ограничивающий прямоугольник задан в координатах, он будет (50,0,80,10). Если ограничивающий прямоугольник задан в начальных координатах и ​​размере, он будет равен (50,0,30,10).

На второй строке находится выделение, которое продолжается до третьей строки. Его самый левый символ - это буква "S" в начале строки 3, которая находится в точке x=0. Его самый правый символ - "О" в "ТАКЖЕ", оканчивающийся на х =130. Самая верхняя линия - вторая, начинающаяся с y=10. Его самая нижняя линия - третья линия, которая заканчивается у =30. Таким образом, ограничивающая рамка будет (0,10,130,30) в координатах или (0,10,130,20) в начальной точке и размере.

1 ответ

Решение

Ниже приведены первые попытки найти ограничивающие рамки для всех выделенных разделов, указанных в информации из базы данных. Чтобы было ясно, что именно охватывает каждая ограничивающая рамка, в примере сценария отображается соответствующая резиновая полоса. Вот как выглядят результаты:

Изменение размера окна автоматически пересчитает поля в соответствии с текущим переносом слов. Обратите внимание, что это может означать, что несколько блоков перекрывают друг друга, если окно становится очень маленьким.

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

import sys
from PySide.QtCore import *
from PySide.QtGui import *

db = ((5,8,'A'),(20,35,'B'),(45,60,'C')) # start, end, and identifier of highlights

class TextEditor(QTextEdit):
    def __init__(self, parent=None):
        super().__init__(parent)
        text="This is example text that is several lines\nlong and also\nstrangely broken up and can be\nwrapped."
        self.setText(text)
        cursor = self.textCursor()
        for n in range(0,len(db)):
            row = db[n]
            startChar = row[0]
            endChar = row[1]
            id = row[2]
            cursor.setPosition(startChar)
            cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor, endChar-startChar)
            charfmt = cursor.charFormat()
            charfmt.setBackground(QColor(Qt.yellow))
            cursor.setCharFormat(charfmt)
        cursor.clearSelection()
        self.setTextCursor(cursor)

    def getBoundingRect(self, start, end):
        cursor = self.textCursor()
        cursor.setPosition(end)
        last_rect = end_rect = self.cursorRect(cursor)
        cursor.setPosition(start)
        first_rect = start_rect = self.cursorRect(cursor)
        if start_rect.y() != end_rect.y():
            cursor.movePosition(QTextCursor.StartOfLine)
            first_rect = last_rect = self.cursorRect(cursor)
            while True:
                cursor.movePosition(QTextCursor.EndOfLine)
                rect = self.cursorRect(cursor)
                if rect.y() < end_rect.y() and rect.x() > last_rect.x():
                    last_rect = rect
                moved = cursor.movePosition(QTextCursor.NextCharacter)
                if not moved or rect.y() > end_rect.y():
                    break
            last_rect = last_rect.united(end_rect)
        return first_rect.united(last_rect)

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.edit = TextEditor(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.edit)
        self.boxes = []

    def showBoxes(self):
        while self.boxes:
            self.boxes.pop().deleteLater()
        viewport = self.edit.viewport()
        for start, end, ident in db:
            rect = self.edit.getBoundingRect(start, end)
            box = QRubberBand(QRubberBand.Rectangle, viewport)
            box.setGeometry(rect)
            box.show()
            self.boxes.append(box)

    def resizeEvent(self, event):
        self.showBoxes()
        super().resizeEvent(event)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    window = Window()
    window.setGeometry(800, 100, 350, 150)
    window.show()
    window.showBoxes()
    sys.exit(app.exec_())
Другие вопросы по тегам