lineNumberWidget.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. from PySide2.QtGui import *
  2. from PySide2 import QtCore, QtGui, QtWidgets
  3. from PySide2.QtCore import Qt
  4. class Editor(QtWidgets.QPlainTextEdit):
  5. def __init__(self, parent=None):
  6. super().__init__(parent)
  7. self.lineNumberArea = LineNumberArea(self)
  8. self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
  9. self.updateRequest.connect(self.updateLineNumberArea)
  10. self.cursorPositionChanged.connect(self.highlightCurrentLine)
  11. self.updateLineNumberAreaWidth(0)
  12. self.setLineWrapMode(QtWidgets.QPlainTextEdit.LineWrapMode.NoWrap)
  13. self.setReadOnly(True)
  14. def goToLine(self, center_line):
  15. total_num_of_lines = self.document().lineCount()
  16. # 计算每行的高度
  17. line_height = self.fontMetrics().lineSpacing()
  18. # 获取文本控件可视窗口的高度
  19. viewport_height = self.viewport().height()
  20. # 每行所需滚动条的值
  21. scroll_per_line = (self.verticalScrollBar().pageStep() + self.verticalScrollBar().maximum())/total_num_of_lines
  22. scroll_value = (center_line - viewport_height/2/line_height) * scroll_per_line
  23. # 移动光标
  24. cursor = self.textCursor()
  25. cursor.movePosition(QtGui.QTextCursor.Start)
  26. for i in range(center_line - 1):
  27. cursor.movePosition(QtGui.QTextCursor.Down, QtGui.QTextCursor.MoveAnchor)
  28. self.setTextCursor(cursor)
  29. self.verticalScrollBar().setValue(0)
  30. self.verticalScrollBar().setValue(scroll_value)
  31. def lineNumberAreaWidth(self):
  32. digits = 1
  33. count = max(1, self.blockCount())
  34. while count >= 10:
  35. count /= 10
  36. digits += 1
  37. space = 3 + self.fontMetrics().horizontalAdvance('9') * digits
  38. return space
  39. def updateLineNumberAreaWidth(self, newBlockCount):
  40. self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
  41. def updateLineNumberArea(self, rect, dy):
  42. if dy:
  43. self.lineNumberArea.scroll(0, dy)
  44. else:
  45. self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
  46. if rect.contains(self.viewport().rect()):
  47. self.updateLineNumberAreaWidth(0)
  48. def resizeEvent(self, event):
  49. super().resizeEvent(event)
  50. cr = self.contentsRect()
  51. self.lineNumberArea.setGeometry(QtCore.QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height()))
  52. def highlightCurrentLine(self):
  53. extraSelections = []
  54. selection = QtWidgets.QTextEdit.ExtraSelection()
  55. lineColor = QtGui.QColor(232,232,255)
  56. selection.format.setBackground(lineColor)
  57. selection.format.setProperty(QtGui.QTextFormat.FullWidthSelection, True)
  58. selection.cursor = self.textCursor()
  59. selection.cursor.clearSelection()
  60. extraSelections.append(selection)
  61. self.setExtraSelections(extraSelections)
  62. class LineNumberArea(QtWidgets.QWidget):
  63. def __init__(self, editor):
  64. super().__init__(editor)
  65. self.editor = editor
  66. def sizeHint(self):
  67. return QtCore.QSize(self.editor.lineNumberAreaWidth(), 0)
  68. def paintEvent(self, event):
  69. painter = QtGui.QPainter(self)
  70. painter.fillRect(event.rect(), QtCore.Qt.lightGray)
  71. block = self.editor.firstVisibleBlock()
  72. blockNumber = block.blockNumber()
  73. top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top()
  74. bottom = top + self.editor.blockBoundingRect(block).height()
  75. height = self.editor.fontMetrics().height()
  76. while block.isValid() and top <= event.rect().bottom():
  77. if block.isVisible() and bottom >= event.rect().top():
  78. number = str(blockNumber + 1)
  79. painter.setPen(QtCore.Qt.black)
  80. painter.drawText(0, top, self.width(), height, QtCore.Qt.AlignRight, number)
  81. block = block.next()
  82. top = bottom
  83. bottom = top + self.editor.blockBoundingRect(block).height()
  84. blockNumber += 1