PyQt5桌面应用开发(7):文本编辑+语法高亮与行号

PyQt5桌面应用系列

代码编辑和语法高亮的亿点点细节

接着上回的文件对话框,我们来看看代码编辑器和语法高亮的实现。文件打开和显示、文件编辑这是跟文本相关的用户界面的两个核心的功能,在严肃的桌面应用开发中,这是必不可少的。

  • 用户报表,例如:显示Log文件;
  • 用户交互,例如:编辑配置文件。

PyQt5提供了三个控件,继承关系如下图。

  • QTextEdit:支持HTML语法的控件;
    • QTextBrowser:只读,支持链接和跳转。
  • QPlainTextEdit:基于纯文本的控件。

这两个控件的主要不同在与文本布局计算的方式,实际上QPlainTextEdit实现了基于行的文本布局,其文本滚动则是基于段落的。

在这里插入图片描述

我们想要实现代码编辑器,那就必须不考虑采用HTML语法来格式化显示的文本,就算是HTML代码编辑器,也要用纯文本!所以我们选择QPlainTextEdit

QPlainTextEdit是一个高级的查看器/编辑器,支持纯文本。它被优化用于处理大型文档,并快速响应用户输入。 这个控件使用了和QTextEdit相同的技术和概念,但是它是为了纯文本处理而优化的。控件的文档是由段落组成的,段落是格式化的字符串,它会自动换行以适应控件的宽度。默认情况下,一个换行符表示一个段落。一个文档由零个或多个段落组成。段落由硬换行符分隔。段落中的每个字符都有自己的属性,例如字体和颜色。

鼠标光标的形状默认是Qt::IBeamCursor。可以通过viewport()cursor属性来改变。

作为用户报表的文本控件

文本采用setPlainText()设置或替换,该函数删除现有文本并用传递给setPlainText()的文本替换它。

文本可以使用QTextCursor类或使用insertPlainText()appendPlainText()paste()的便利函数插入。

默认情况下,文本编辑器在空格处换行以适应文本编辑器窗体。 setLineWrapMode()函数用于指定所需的换行方式,如果不需要任何换行,则为WidgetWidthNoWrap。如果使用单词换行到窗体宽度WidgetWidth,则可以使用setWordWrapMode()指定是否在空格处或任何位置中断。

find函数可以用于查找和选择文本中的字符串。

如果要限制QPlainTextEdit中段落的总数,例如在日志查看器中非常有用,则可以使用maximumBlockCount属性。 setMaximumBlockCount()appendPlainText()的组合将QPlainTextEdit变为日志文本的高效查看器。 可以使用centerOnScroll()属性减少滚动,从而使日志查看器更快。 可以以有限的方式格式化文本,要么使用语法突出显示器,要么使用appendHtml()附加html格式的文本。 虽然QPlainTextEdit不支持具有表格和浮动的复杂富文本呈现,但它支持您可能需要的日志查看器中的有限基于段落的格式。

作为编辑器的文本控件

编辑器首先也是一个展示文本的控件,所以上述的内容也适用于编辑器。

选择文本由QTextCursor类处理,该类提供了创建选择,检索文本内容或删除选择的功能。 您可以使用textCursor()方法检索与用户可见光标对应的对象。 如果要在QPlainTextEdit中设置选择,只需在QTextCursor对象上创建一个选择,然后使用setCursor()将该光标设置为可见光标。 可以使用copy()将选择复制到剪贴板,或使用cut()将其剪切到剪贴板。 可以使用selectAll()选择整个文本。

QPlainTextEdit组合了一个QTextDocument对象,可以使用document()方法检索该对象。 您还可以使用setDocument()设置自己的文档对象。 如果文本更改,则QTextDocument发出textChanged()信号,它还提供了一个isModified()函数,如果自加载以来文本已被修改或自上次调用setModified(),则返回true,参数为false。 此外,它提供了撤消和重做的方法。

代码编辑器的需求

  • QPlainTextEdit是一个纯文本编辑/查看器;
  • 它提供了很强大的编辑和查看功能;
  • 编辑对象由QTextDocument类提供。

实现代码编辑器,则主要有两个方面的内容:

  • 显示行号,高亮当前行;
  • 语法高亮。

这都有现成的参考例子,例如我们正在编的代码,用的是IDEA,它的代码编辑器就是这样的:

在这里插入图片描述

代码编辑1

这个地方,就是简单的实现行号显示和高亮当前行。从图中可以看出,编辑器在编辑区域左侧的区域中显示行号。 编辑器将突出显示包含光标的行。

参考官方代码,我们实现继承自QPlainTextEditCodeEditor类;增加LineNumberArea类,用于显示行号。LineNumberArea类继承自QWidget,并与CodeEditor类形成组合关系,也就是作为一个成员变量。

下面就是LineNumberArea的代码,这个类与一个Editor联系在一起,当Editor的块计数变化、更新的时候,就调用这里的两个方法来计算宽度、行数,更新外观。 这里重载了QWidget.paintEvent方法,来设置相应的字体、背景,显示行数,可以看到,这里的行数从1开始计数。

painter.drawText(paint_rect, Qt.AlignRight, str(block_number + 1))
from PyQt5.QtCore import Qt
from PyQt5.QtCore import QRect
from PyQt5.QtGui import QFont, QColor, QPainter
from PyQt5.QtWidgets import QWidget
class LineNumberArea(QWidget):
    def __init__(self, editor):
        QWidget.__init__(self, editor)
        self.editor = editor
        self.editor.blockCountChanged.connect(self.update_width)
        self.editor.updateRequest.connect(self.update_contents)
        self.font = QFont()
        self.numberBarColor = QColor("#e8e8e8")

    def paintEvent(self, event):
        # Override paintEvent to draw the line numbers
        painter = QPainter(self)
        painter.fillRect(event.rect(), self.numberBarColor)

        block = self.editor.firstVisibleBlock()

        # Iterate over all visible text blocks in the document.
        while block.isValid():
            block_number = block.blockNumber()
            block_top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top()

            # Check if the position of the block is outside the visible area.
            if not block.isVisible() or block_top >= event.rect().bottom():
                break

            # We want the line number for the selected line to be bold.
            if block_number == self.editor.textCursor().blockNumber():
                self.font.setBold(True)
                painter.setPen(QColor("#000000"))
            else:
                self.font.setBold(False)
                painter.setPen(QColor(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大福是小强

除非你钱多烧得慌……

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值