M-am uitat la acest editor de cod exemplu de la oficial Qt5-ul https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html. Este scris în C++, dar am pus-o în aplicare în Python folosind Pyside2.
De exemplu, codul funcționează bine ca este, cu toate acestea, atunci când am încerca să schimbe familia de fonturi și dimensiunea QPlainTextEdit
lucrurile încep să devină murdar. Am încercat să tweak o mulțime de diferite domenii, cum ar fi utilizarea fontMetrics
pentru a determina la înălțime etc.
Aici este un minim exemplu pentru a reproduce 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_())
Una dintre cele mai mari probleme sunt că nu pare a fi un top marja de offset în plaintext ieșire care sunt în imposibilitatea de a obține în mod dinamic în linenumber widget. Și când setarea fontului editor pentru a pictorului numerele nu vor fi trase la aceeași dimensiune!?
Stie cineva cum se poate regla numerele de linie la același nivel orizontal ca textul corespunzător și, de asemenea, obține-le să fie de aceeași dimensiune într-un mod dinamic, în sensul că, dacă fontul va fi setat la altceva, acestea ar trebui să fie ajustate în mod automat.