Skip to content

Instantly share code, notes, and snippets.

@eyllanesc
Created April 28, 2018 08:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eyllanesc/e614ea9689e025c16b10fc92b68f0afd to your computer and use it in GitHub Desktop.
Save eyllanesc/e614ea9689e025c16b10fc92b68f0afd to your computer and use it in GitHub Desktop.
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_())
<?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="CodeEditor" 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>
</widget>
<customwidgets>
<customwidget>
<class>CodeEditor</class>
<extends>QPlainTextEdit</extends>
<header>codeeditor.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
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())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment