首页 > 解决方案 > How to Add line Number in this TextEditor

问题描述

This is my code for the text Editor,

import sys
from collections import Counter
from PyQt5.QtCore import pyqtRemoveInputHook
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction
from PyQt5 import uic
Ui_MainWindow, QtBaseClass = uic.loadUiType('EditorUI.ui')

class MyApp(QMainWindow):
    def __init__(self):
        self.newLines = 1
        super(MyApp, self).__init__(None)
        menuBar = self.menuBar()
        fileMenu = menuBar.addMenu('&File')

        # New Action
        self.newAction = QAction('&New', self)
        self.newAction.triggered.connect(self.NewCall)
        fileMenu.addAction(self.newAction)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.textEdit.setViewportMargins(35, 0, 0, 0)
        self.ui.textEdit.textChanged.connect(self.NumNewLines)

    def NumNewLines(self): # Returns Number of lines Of text written in the editor
        self.newLines = Counter(self.ui.textEdit.toPlainText())['\n']+1

    def NewCall(self):
        print('new')

if __name__ == '__main__':
    pyqtRemoveInputHook()
    app = QApplication(sys.argv)
    window = MyApp()
    window.setWindowTitle('PyEditor')
    window.showMaximized()
    window.show()
    sys.exit(app.exec())

This is my EditorUI.ui file!

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1364</width>
    <height>681</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPlainTextEdit" name="textEdit">
    <property name="geometry">
     <rect>
      <x>123</x>
      <y>0</y>
      <width>1241</width>
      <height>681</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">background-color: rgb(33, 33, 50);
font: 75 15pt &quot;Consolas&quot;;
color: rgb(255, 255, 255);</string>
    </property>
    <property name="plainText">
     <string/>
    </property>
   </widget>
   <widget class="Line" name="line">
    <property name="geometry">
     <rect>
      <x>150</x>
      <y>0</y>
      <width>20</width>
      <height>681</height>
     </rect>
    </property>
    <property name="orientation">
     <enum>Qt::Vertical</enum>
    </property>
   </widget>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

I have tried Using QDraw still got no idea what to do, i have drawn a margin where to the left there should be line numbers, and to the write this is place to Write the text.

Now i want it to show line numbers beside the lines of text i write in the editor, but so far no success!

Please fellow programmers help me with this problem! !!Thanks in advance!!

标签: pythonpython-3.xpyqtpyqt5

解决方案


一个简单的解决方案是创建一个满足您要求的自定义小部件,然后将其推广以在 .ui 中使用它,使用代码编辑器示例创建自定义小部件。

代码编辑器.py

from PyQt5.QtWidgets import QWidget, QPlainTextEdit, QApplication, QTextEdit
from PyQt5.QtGui import QColor, QTextFormat, QPainter
from PyQt5.QtCore import QRect, pyqtSlot, Qt


class LineNumberArea(QWidget):
    def __init__(self, editor):
        QWidget.__init__(self, parent=editor)
        self.codeEditor = editor

    def sizeHint(self):
        return QSize(self.codeEditor.lineNumberAreaWidth(), 0)

    def paintEvent(self, event):
        self.codeEditor.lineNumberAreaPaintEvent(event)

class CodeEditor(QPlainTextEdit):
    def __init__(self, parent=None):
        QPlainTextEdit.__init__(self, parent)
        self.lineNumberArea = LineNumberArea(self)
        self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
        self.updateRequest.connect(self.updateLineNumberArea)
        self.cursorPositionChanged.connect(self.highlightCurrentLine)
        self.updateLineNumberAreaWidth(0)
        self.highlightCurrentLine()

    def lineNumberAreaPaintEvent(self, event):
        painter = QPainter(self.lineNumberArea)
        painter.fillRect(event.rect(), Qt.lightGray)

        block = self.firstVisibleBlock()
        blockNumber = block.blockNumber();
        top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
        bottom = top + self.blockBoundingRect(block).height()

        while block.isValid() and top <= event.rect().bottom():
            if block.isVisible() and bottom >= event.rect().top():
                number = str(blockNumber + 1)
                painter.setPen(Qt.black)
                painter.drawText(0, top, self.lineNumberArea.width(), 
                    self.fontMetrics().height(),
                    Qt.AlignRight, number)
            block = block.next()
            top = bottom
            bottom = top + self.blockBoundingRect(block).height()
            blockNumber += 1

    def lineNumberAreaWidth(self):
        digits = len(str(self.blockCount()))
        space = 3 + self.fontMetrics().width('9')*digits
        return space

    def resizeEvent(self, event):
        QPlainTextEdit.resizeEvent(self, event)
        cr = self.contentsRect()
        self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height()))

    @pyqtSlot(int)
    def updateLineNumberAreaWidth(self, newBlockCount):
        self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0);

    @pyqtSlot()
    def highlightCurrentLine(self):
        extraSelections = []
        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()
            lineColor = QColor(Qt.blue).lighter(160)
            selection.format.setBackground(lineColor)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)
            selection.cursor = self.textCursor()
            selection.cursor.clearSelection()
            extraSelections.append(selection)
        self.setExtraSelections(extraSelections)

    @pyqtSlot(QRect, int)
    def updateLineNumberArea(self, rect, dy):
        if dy:
            self.lineNumberArea.scroll(0, dy)
        else:
            self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
        if rect.contains(self.viewport().rect()):
            self.updateLineNumberAreaWidth(0)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = CodeEditor()
    w.show()
    sys.exit(app.exec_())

现在您必须推广小部件,因此您必须将 3 个文件放在同一个文件夹中:

.
├── codeeditor.py
├── EditorUI.ui
└── main.py

然后我们.ui用 Qt Designer 打开,然后右键单击QPlainTextEdit并选择Promoted Widgets,将出现一个对话框并填写如图所示的字段:

在此处输入图像描述

然后按下Add按钮并在Promote按钮之后。

注意:不需要使用Line,去掉slot计算位置。

主文件

import sys
from collections import Counter
from PyQt5.QtCore import pyqtRemoveInputHook
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction
from PyQt5 import uic
Ui_MainWindow, QtBaseClass = uic.loadUiType('EditorUI.ui')

class MyApp(QMainWindow):
    def __init__(self):
        self.newLines = 1
        super(MyApp, self).__init__(None)
        menuBar = self.menuBar()
        fileMenu = menuBar.addMenu('&File')

        # New Action
        self.newAction = QAction('&New', self)
        self.newAction.triggered.connect(self.NewCall)
        fileMenu.addAction(self.newAction)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

    def NewCall(self):
        print('new')

if __name__ == '__main__':
    pyqtRemoveInputHook()
    app = QApplication(sys.argv)
    window = MyApp()
    window.setWindowTitle('PyEditor')
    window.showMaximized()
    window.show()
    sys.exit(app.exec())

输出:

在此处输入图像描述

您可以在以下链接中找到完整的示例


推荐阅读