2015-10-20 152 views
2

我試圖學習一些Qt(PyQt)。爲此,我使用了文檔的Code Editor example。當前行的突出顯示正常工作。行號然而不顯示。pyqt中的代碼編輯器示例

其實LineNumberArea.paintEvent甚至沒有被稱爲。其次也不是CodeEditor.lineNumberAreaPaintEvent。據我瞭解,數字欄的paintEvent應該定期調用。或者至少有一個updateRequest或滾動事件(由CodeEditor.updateLineNumberArea調用)。

這是我取端口從C++代碼的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,OS:RHEL 6

回答

3

你的例子看起來基本上是正確的。缺少繪畫事件的問題是由於未在LineNumberArea小部件上設置父項而導致的。所以,你只需要:

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

此外,lineNumberAreaPaintEvent方法有一些問題,但他們很容易固定:

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,因爲它似乎沒有給出正確的結果。原來的實現完全按照預期工作,雖然(也是更快):

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 
+0

謝謝你的回答。我不知何故錯過了超級構造函數調用。即使我看了大約一百次。同樣感謝你的其他建議,當然你也有權利。 –