pyqt 中的代码编辑器示例 [英] CodeEditor example in pyqt

查看:86
本文介绍了pyqt 中的代码编辑器示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试学习一些 Qt (PyQt).为此,我使用了代码编辑器示例文档.当前行的突出显示工作正常.但是行号不显示.

I tried to learn some Qt (PyQt). To do so I used the Code Editor example of the docs. The highlighting of the current line works fine. The line number however do not show.

实际上 LineNumberArea.paintEvent 甚至没有被调用.随后也不是 CodeEditor.lineNumberAreaPaintEvent.据我了解,应该定期调用数字条的paintEvent.或者至少在有 updateRequest 或滚动事件时(由 CodeEditor.updateLineNumberArea 调用).

Actually the LineNumberArea.paintEvent is not even called. Subequently also not CodeEditor.lineNumberAreaPaintEvent. As far as I understood it the paintEvent of the number bars should be called by periodically. Or at least when there is an updateRequest or scroll event (called by CodeEditor.updateLineNumberArea).

这是我将代码从 C++ 移植到 Python 的过程:

Here is my take to port the code from c++ to python:

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

import numpy as np

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


    def sizeHint(self):
        return Qsize(self.editor.lineNumberAreaWidth(), 0)


    def paintEvent(self, event):
        print('LineNumberArea.paintEvent')
        self.editor.lineNumberAreaPaintEvent(event)


class CodeEditor(QPlainTextEdit):
    def __init__(self):
        super().__init__()
        self.lineNumberArea = LineNumberArea(self)

        self.connect(self, SIGNAL('blockCountChanged(int)'), self.updateLineNumberAreaWidth)
        self.connect(self, SIGNAL('updateRequest(QRect,int)'), self.updateLineNumberArea)
        self.connect(self, SIGNAL('cursorPositionChanged()'), self.highlightCurrentLine)

        self.updateLineNumberAreaWidth(0)


    def lineNumberAreaWidth(self):
        """ This method has been slightly modified (use of log and uses actual
        font rather than standart.) """
        n_lines = self.blockCount()
        digits = np.ceil(np.log10(n_lines)) + 1
        return digits * QFontMetrics(self.font()).width('9') + 3


    def updateLineNumberAreaWidth(self, _):
        print('CodeEditor.updateLineNumberAreaWidth: margin = {}'.format(self.lineNumberAreaWidth()))
        self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)


    def updateLineNumberArea(self, rect, dy):
        print('CodeEditor.updateLineNumberArea: rect = {}, dy = {}'.format(rect, dy))

        if dy:
            self.lineNumberArea.scroll(0, dy)
        else:
            self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(),
                                       rect.height())

        print('CodeEditor.updateLineNumberArea: rect.contains(self.viewport().rect()) = {}'.format(rect.contains(self.viewport().rect())))
        if rect.contains(self.viewport().rect()):
            self.updateLineNumberAreaWidth(0)


    def resizeEvent(self, event):
        super().resizeEvent(event)

        cr = self.contentsRect();
        self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(),
                                        self.lineNumberAreaWidth(), cr.height()))

    def lineNumberAreaPaintEvent(self, event):
        print('CodeEditor.lineNumberAreaPaintEvent')
        painter(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()

        # Just to make sure I use the right font
        height = QFontMetrics(self.font()).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, lineNumberArea.width(), height,
                                 Qt.AlignRight, number)

            block = block.next()
            top = bottom
            bottom = top + self.blockBoundingRect(block).height()
            blockNumber += 1


    def highlightCurrentLine(self):
        extraSelections = []

        if not self.isReadOnly():
            selection = QTextEdit.ExtraSelection()

            lineColor = QColor(Qt.yellow).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)


if __name__ == "__main__":
    app = QApplication(sys.argv)

    txt = CodeEditor()
    txt.show()

    sys.exit(app.exec_())

任何帮助将不胜感激.

如果重要:蟒蛇:3.4.3,PyQt:4.8.6,操作系统:RHEL 6

In case it matters: python: 3.4.3, PyQt: 4.8.6, OS: RHEL 6

推荐答案

您的示例看起来基本正确.缺少绘制事件的问题是由于未在 LineNumberArea 小部件上设置父级引起的.所以你只需要:

Your example looks mostly right. The issue with the missing paint events is caused by not setting a parent on the LineNumberArea widget. So you just need:

class LineNumberArea(QWidget):
    def __init__(self, editor):
        super().__init__(editor)

此外,lineNumberAreaPaintEvent 方法也有一些问题,但很容易修复:

Also, the lineNumberAreaPaintEvent method has a few problems, but they're easily fixed:

def lineNumberAreaPaintEvent(self, event):
    # missing constructor
    painter = QPainter(self.lineNumberArea)
    ...
    # no need to use QFontMetrics
    height = self.fontMetrics().height()
    ...
            # missing self
            painter.drawText(0, top, self.lineNumberArea.width(), height,
                             Qt.AlignRight, number)

我不确定您要对 lineNumberAreaWidth 的实现做什么,因为它似乎没有给出正确的结果.不过,原始实现完全按预期工作(而且速度也快得多):

I'm not sure what you're trying to do with your implementation of lineNumberAreaWidth, as it doesn't seem to give the right results. The original implementation works exactly as expected, though (and is also much faster):

def lineNumberAreaWidth(self):
    digits = 1
    count = max(1, self.blockCount())
    while count >= 10:
        count /= 10
        digits += 1
    space = 3 + self.fontMetrics().width('9') * digits
    return space

这篇关于pyqt 中的代码编辑器示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆