Eu olhei para este editor de código de exemplo a partir de oficial Qt5 site https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html. Ele é escrito em C++, mas eu implementado em Python usando Pyside2.
O código de exemplo funciona bem como é, no entanto, quando tento alterar a família de tipos de letra e o tamanho do QPlainTextEdit
as coisas começam a ficar confuso. Eu tentei fuçar um monte de diferentes campos, como a fontMetrics
para determinar a altura etc.
Aqui está um exemplo mínimo para reproduzir o problema
import sys
import signal
from PySide2.QtCore import Qt, QSize, QRect
from PySide2.QtGui import QPaintEvent, QPainter, QColor, QResizeEvent
from PySide2.QtWidgets import QWidget, QPlainTextEdit, QVBoxLayout
from PySide2 import QtCore
from PySide2.QtWidgets import QApplication
FONT_SIZE = 20
FONT_FAMILY = 'Source Code Pro'
class PlainTextEdit(QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
self.init_settings_font()
def init_settings_font(self):
font = self.document().defaultFont()
font.setFamily(FONT_FAMILY)
font.setFixedPitch(True)
font.setPixelSize(FONT_SIZE)
self.document().setDefaultFont(font)
class LineNumberArea(QWidget):
TMP = dict()
def __init__(self, editor):
super().__init__(editor)
self._editor = editor
self._editor.blockCountChanged.connect(lambda new_count: self._update_margin())
self._editor.updateRequest.connect(lambda rect, dy: self._update_request(rect, dy))
self._update_margin()
def width(self) -> int:
# we use 1000 as a default size, so from 0-9999 this length will be applied
_max = max(1000, self._editor.blockCount())
digits = len(f'{_max}')
space = self._editor.fontMetrics().horizontalAdvance('0', -1) * (digits + 1) + 6
return QSize(space, 0).width()
def _update_line_geometry(self):
content_rect = self._editor.contentsRect()
self._update_geometry(content_rect)
def _update_geometry(self, content_rect: QRect):
self.setGeometry(
QRect(content_rect.left(), content_rect.top(), self.width(), content_rect.height())
)
def _update_margin(self):
self._editor.setViewportMargins(self.width(), 0, 0, 0)
def _update_request(self, rect: QRect, dy: int):
self._update(0, rect.y(), self.width(), rect.height(), self._editor.contentsRect())
if rect.contains(self._editor.viewport().rect()):
self._update_margin()
def _update(self, x: int, y: int, w: int, h: int, content_rect: QRect):
self.update(x, y, w, h)
self._update_geometry(content_rect)
# override
def resizeEvent(self, event: QResizeEvent) -> None:
self._update_line_geometry()
# override
def paintEvent(self, event: QPaintEvent):
painter = QPainter(self)
area_color = QColor('darkgrey')
# Clearing rect to update
painter.fillRect(event.rect(), area_color)
visible_block_num = self._editor.firstVisibleBlock().blockNumber()
block = self._editor.document().findBlockByNumber(visible_block_num)
top = self._editor.blockBoundingGeometry(block).translated(self._editor.contentOffset()).top()
bottom = top + self._editor.blockBoundingRect(block).height()
active_line_number = self._editor.textCursor().block().blockNumber() + 1
# font_size = storage.get_setting(Constants.Editor_font_size).value
font = self._editor.font()
while block.isValid() and top <= event.rect().bottom():
if block.isVisible() and bottom >= event.rect().top():
number_to_draw = visible_block_num + 1
if number_to_draw == active_line_number:
painter.setPen(QColor('black'))
else:
painter.setPen(QColor('white'))
font.setPixelSize(self._editor.document().defaultFont().pixelSize())
painter.setFont(font)
painter.drawText(
-5,
top,
self.width(),
self._editor.fontMetrics().height(),
int(Qt.AlignRight | Qt.AlignHCenter),
str(number_to_draw)
)
block = block.next()
top = bottom
bottom = top + self._editor.blockBoundingGeometry(block).height()
visible_block_num += 1
painter.end()
if __name__ == "__main__":
app = QApplication(sys.argv)
signal.signal(signal.SIGINT, signal.SIG_DFL)
window = QWidget()
layout = QVBoxLayout()
editor = PlainTextEdit()
line_num = LineNumberArea(editor)
layout.addWidget(editor)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
Um dos maiores problemas são que parece haver uma margem superior deslocamento em texto simples saída que eu sou incapaz de obter dinamicamente no linenumber widget. E quando a definição do editor de tipos de letra para o pintor, os números não será desenhado o mesmo tamanho!?
Alguém sabe como ajustar os números de linha para o mesmo nível horizontal como o texto correspondente e também levá-los a ter o mesmo tamanho de uma forma dinâmica, o que significa que, se o tipo de letra vai ser definido para algo que eles devem ser ajustados automaticamente.