如何在此TextEditor中添加行号

时间:2018-04-28 07:44:11

标签: python python-3.x pyqt pyqt5

这是我的文本编辑器的代码,

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())

这是我的EditorUI.ui文件!

<?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>

我试过使用QDraw仍然不知道该怎么做 我画了一个边距,左边应该有行号,写到这是写文字的地方。

现在我希望它在编辑器中写的文本行旁边显示行号,但到目前为止还没有成功!

请其他程序员帮我解决这个问题! !!提前致谢!!

1 个答案:

答案 0 :(得分:3)

一个简单的解决方案是创建一个符合您要求的自定义窗口小部件,然后将其提升为在.ui中使用它,使用Code Editor Example创建自定义窗口小部件。

<强> codeeditor.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

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

enter image description here

然后按Add按钮,然后按Promote按钮。

注意:没有必要使用Line,并删除插槽计算位置。

<强> main.py

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())

输出:

enter image description here

您可以在以下link

中找到完整的示例