相关文章推荐
威武的海龟  ·  查看SQL ...·  3 月前    · 
小眼睛的毛豆  ·  Custom Model Binding ...·  9 月前    · 
着急的毛巾  ·  SSE Engine Fixes ...·  1 年前    · 
PyQt5系列教程(31): QPlainTextEdit

PyQt5系列教程(31): QPlainTextEdit

上期我们介绍了文本输入栏(QLineEdit),这期我们将介绍一下纯文本输入框(QPlainTextEdit)。好吧,这名字是我取得,是难听了点。

总体介绍

QPlainTextEdit类提供了一个用于编辑和显示纯文本的小部件。

介绍和概念

QPlainTextEdit是支持纯文本的高级查看器/编辑器。它经过优化处理大型文档并对用户输入做出快速响应。

QPlainText使用与QTextEdit相同的技术和概念,但是为纯文本处理进行了优化。

QPlainTextEdit适用于段落和字符。段落是一个格式化的字符串,它被字符包装以适应窗口小部件的宽度。默认情况下,当阅读纯文本时,一个换行符表示一个段落。文档由零个或多个段落组成。段落以强硬换行符分隔。段落中的每个字符都有其自己的属性,例如字体和颜色。

QPlainTextEdit上鼠标光标的形状默认为Qt. IBeamCursor。它可以通过viewport()的游标属性进行更改。

使用QPlainTextEdit作为显示小部件

使用setPlainText()来设置或替换文本,删除现有文本并将其替换为传递给setPlainText()的文本。

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

默认情况下,文本编辑会以空格为间隔把单词包装在文本编辑小部件中。

setLineWrapMode()函数用于指定您想要的换行类型,WidgetWidth或NoWrap(如果不需要任何换行)。如果使用WrapgetWidth WidgetWidth的自动换行,则可以使用setWordWrapMode()指定是否在空白处或任何地方断开。

find()函数可用于查找和选择文本中的给定字符串。

如果您想限制QPlainTextEdit中段落的总数,因为它在日志查看器中很有用,那么您可以使用maximumBlockCount属性。 setMaximumBlockCount()和appendPlainText()的组合将QPlainTextEdit转换为日志文本的高效查看器。使用centerOnScroll()属性可以减少滚动,使日志查看器更快。文本可以通过有限的方式进行格式化,可以使用语法高亮显示,也可以使用appendHtml()附加HTML格式的文本。尽管QPlainTextEdit不支持使用表格和浮点数进行复杂的富文本渲染,但它支持您在日志查看器中可能需要的有限段落格式。

只读型键盘组合

当使用QPlainTextEdit时,只读键绑定仅限于导航,并且文本只能用鼠标选择:

使用QPlainTextEdit作为编辑器

关于使用QPlainTextEdit作为显示小部件的所有信息也适用于此处。

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

QPlainTextEdit包含一个可以使用document()方法检索的QTextDocument对象。您也可以使用setDocument()设置自己的文档对象。如果文本改变,QTextDocument将发出一个textChanged()信号,并且它还提供了一个isModified()函数,如果文本自加载或自从上次调用setModified并将其作为参数调用后,将返回true。另外它提供了撤销和重做的方法。

语法高亮

就像QTextEdit一样,QPlainTextEdit和QSyntaxHighlighter一起工作。

可编辑键盘组合

用于编辑的键绑定列表:

与QTextEdit的差异

QPlainTextEdit是一个很单一的类,通过使用QTextEdit和QTextDocument背后的大部分技术来实现。它的性能优于QTextEdit,主要是在文本文档上使用称为QPlainTextDocumentLayout的另一种简化文本布局。纯文本文档布局不支持表格或嵌入帧,并且逐行逐行滚动方式替换像素精确高度计算。这使得可以处理更大的文档,并且仍然可以实时启用换行来调整编辑器的大小。它还可以用于快速日志查看器。

一句话对于纯文本,QPlainTextEdit更合适!

类归属

PyQt5->QtWidgets->QPlainTextEdit

继承关系

继承:QAbstractScrollArea

更多详细的介绍请见官网:

小例子

本期小例子来源于github,作者:Ivan Luchko,具体网址我不记得了。

这个例子我觉得挺好的,没有必要再单独写一个了,所以本期我们一起来学习一下这个例子。为便于学习,我做了部分修改:

  1. 删除了与本次知识点无关的内容
  2. 修改了原作品中存在的bug

总体的效果图如下:

在这个程序当中我们实现了:

  1. 行号
  2. 在当前行时有黄色的标记

核心代码讲解

在正式讲解之前,我们简单的介绍一下Python当中关于嵌套类的概念。嵌套类,(=@__@=)这个东东是什么?我们举个生活中的例子吧,如下图:

从上图中我们了解到老司机和汽车之间的关系,以及作为一个整体的作用。下面我们运行面向对象的编程方法抽象这一生活中的实际例子。

#coding=utf-8
class RunningCar:
    class VeteranDriver:
        def __init__(self, car):
            self.car = car
        def action(self, action):
            if action == 'startup':
                self.car.startup()
            elif action == 'stop':
                self.car.stop()
            elif action == 'turn':
                self.car.turn()
    def __init__(self):
        self.veterandriver = self.VeteranDriver(self)
    def cmd(self, cmd):
        self.veterandriver.action(cmd) 
    def startup(self):
        print('\n老司机:没时间解释了,快上车!\n')
    def stop(self):
        print('\n滴嘟..滴嘟..滴嘟..请让一让,这里是车祸现场,大家不要围观!\n')
    def turn(self):
        print('\n我靠,车翻了~〒_〒!\n')
car = RunningCar()
while True:
    cmd = input("汽车待命中,请输入指令('startup','stop','turn')->")
    if cmd == 'stop':
        car.cmd(cmd)
        break
    car.cmd(cmd)

上面这段代码就是一个类中类的例子了。我们新建了一个汽车RunningCar类,在这个类中我们还有一个类就是老司机VeteranDriver类。

一个汽车肯定是可以 启动、停车、转弯 的。这三个方法是汽车应该有的功能。但是现在无人汽车技术还不成熟啊,所以老司机就有作用了,老司机发出具体的命令然后汽车去执行。

老司机发出指令: 启动、转弯、停车 ,调用的是汽车的这三个方法。即内部类调用外部类的方法。

class VeteranDriver:
    def __init__(self, car):
        self.car = car
    def action(self, action):
        if action == 'startup':
            self.car.startup()
        elif action == 'stop':
            self.car.stop()
        elif action == 'turn':
            self.car.turn()

当然我这里描述的是比较简答,举的例子也是简单的,很多特殊的情况也没有考虑。

我们在实例化RunningCar类的同时会产生VeteranDriver对象

def __init__(self):
    self.veterandriver = self.VeteranDriver(self)

然后通过VeteranDriver对象调用其方法,例如代码中

def cmd(self, cmd):
    self.veterandriver.action(cmd)

不知道大家了解内部类、外部类的关系没有。把效果给大家演示一下(图形化界面):

为什么要说这个呢,因为我们实现QPlainTextEdit的功能中,用到了这个方法。我把大致的代码给大家演示一下:

class QCodeEditor(QPlainTextEdit):
    class NumberBar(QWidget):
        def __init__(self, editor):
            QWidget.__init__(self, editor)
            self.editor = editor
            self.editor.blockCountChanged.connect(self.updateWidth)
            self.editor.updateRequest.connect(self.updateContents)
            self.font = QFont()
            self.numberBarColor = QColor("#e8e8e8")
        def paintEvent(self, event):
        def getWidth(self):  
        def updateWidth(self):
        def updateContents(self, rect, dy):
    def __init__(self):        
        super(QCodeEditor, self).__init__()
        self.setWindowTitle('微信公众号:学点编程吧--带行号和颜色的文本框')
        self.setFont(QFont("Ubuntu Mono", 12))
        self.setLineWrapMode(QPlainTextEdit.NoWrap)
        self.number_bar = self.NumberBar(self)           
        self.currentLineNumber = None
        self.cursorPositionChanged.connect(self.highligtCurrentLine)    
        self.setViewportMargins(40, 0, 0, 0)
        self.highligtCurrentLine()