Created
March 31, 2018 19:31
-
-
Save andr1972/0bf62c320d12b66f88a2b260a5e9f322 to your computer and use it in GitHub Desktop.
Qt: editor with line numbers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef LINENUMBERAREA_H | |
#define LINENUMBERAREA_H | |
#include <QWidget> | |
#include "numberededit.h" | |
class LineNumberArea : public QWidget | |
{ | |
public: | |
LineNumberArea(NumberedEdit *editor) : QWidget(editor) { | |
numberedEdit = editor; | |
setParent(editor); | |
} | |
QSize sizeHint() const override { | |
return QSize(numberedEdit->lineNumberAreaWidth(), 0); | |
} | |
protected: | |
void paintEvent(QPaintEvent *event) override { | |
numberedEdit->lineNumberAreaPaintEvent(event); | |
} | |
private: | |
NumberedEdit *numberedEdit; | |
}; | |
#endif // LINENUMBERAREA_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
QT += widgets | |
HEADERS = \ | |
mainwindow.h \ | |
linenumberarea.h \ | |
numberededit.h | |
SOURCES = \ | |
mainwindow.cpp \ | |
main.cpp \ | |
numberededit.cpp | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "mainwindow.h" | |
#include <QApplication> | |
int main(int argc, char *argv[]) | |
{ | |
QApplication app(argc, argv); | |
MainWindow window; | |
window.resize(640, 512); | |
window.show(); | |
return app.exec(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <QtWidgets> | |
#include "mainwindow.h" | |
MainWindow::MainWindow(QWidget *parent) | |
: QMainWindow(parent) | |
{ | |
setupFileMenu(); | |
editor = new NumberedEdit; | |
setCentralWidget(editor); | |
setWindowTitle(tr("line numbers")); | |
} | |
void MainWindow::openFile(const QString &path) | |
{ | |
QString fileName = path; | |
if (fileName.isNull()) | |
fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", "All Files (*)"); | |
if (!fileName.isEmpty()) { | |
QFile file(fileName); | |
if (file.open(QFile::ReadOnly | QFile::Text)) | |
{ | |
QString text = file.readAll(); | |
editor->setPlainText(text); | |
} | |
} | |
} | |
void MainWindow::setupFileMenu() | |
{ | |
QMenu *fileMenu = new QMenu(tr("&File"), this); | |
menuBar()->addMenu(fileMenu); | |
fileMenu->addAction(tr("&Open..."), this, SLOT(openFile()), QKeySequence::Open); | |
fileMenu->addAction(tr("E&xit"), qApp, SLOT(quit()), QKeySequence::Quit); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MAINWINDOW_H | |
#define MAINWINDOW_H | |
#include <QMainWindow> | |
#include "numberededit.h" | |
QT_BEGIN_NAMESPACE | |
class QTextEdit; | |
QT_END_NAMESPACE | |
//! [0] | |
class MainWindow : public QMainWindow | |
{ | |
Q_OBJECT | |
public: | |
MainWindow(QWidget *parent = 0); | |
public slots: | |
void openFile(const QString &path = QString()); | |
private: | |
void setupFileMenu(); | |
NumberedEdit *editor; | |
}; | |
//! [0] | |
#endif // MAINWINDOW_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "numberededit.h" | |
#include "linenumberarea.h" | |
NumberedEdit::NumberedEdit(QWidget *parent) : QTextEdit(parent) | |
{ | |
lineNumberArea = new LineNumberArea(this); | |
connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); | |
connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateLineNumberArea(QRect,int))); | |
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine())); | |
updateLineNumberAreaWidth(0); | |
} | |
NumberedEdit::~NumberedEdit() | |
{ | |
delete lineNumberArea; | |
} | |
int NumberedEdit::lineNumberAreaWidth() | |
{ | |
int digits = 1; | |
int max = qMax(1, document()->blockCount()); | |
while (max >= 10) { | |
max /= 10; | |
++digits; | |
} | |
int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; | |
return space; | |
} | |
void NumberedEdit::updateLineNumberAreaWidth(int /* newBlockCount */) | |
{ | |
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); | |
} | |
void NumberedEdit::updateLineNumberArea(const QRect &rect, int dy) | |
{ | |
if (dy) | |
lineNumberArea->scroll(0, dy); | |
else | |
lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height()); | |
if (rect.contains(viewport()->rect())) | |
updateLineNumberAreaWidth(0); | |
} | |
void NumberedEdit::resizeEvent(QResizeEvent *e) | |
{ | |
QTextEdit::resizeEvent(e); | |
QRect cr = contentsRect(); | |
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); | |
} | |
FirstLineInfo NumberedEdit::getFirstLineInfo() | |
{ | |
FirstLineInfo result; | |
QFontMetrics fm(font()); | |
result.height = fm.ascent() + fm.descent() + fm.leading(); | |
result.firstVisible = verticalScrollBar()->value()/result.height; | |
result.top = result.firstVisible*result.height - verticalScrollBar()->value(); | |
return result; | |
} | |
void NumberedEdit::lineNumberAreaPaintEvent(QPaintEvent *event) | |
{ | |
QPainter painter(lineNumberArea); | |
painter.fillRect(event->rect(), Qt::lightGray); | |
FirstLineInfo fli = getFirstLineInfo(); | |
QTextBlock block = document()->findBlockByLineNumber(fli.firstVisible); | |
int blockNumber = fli.firstVisible; | |
int top = fli.top; | |
int bottom = top + fli.height; | |
while (block.isValid() && top <= event->rect().bottom()) { | |
if (block.isVisible() && bottom >= event->rect().top()) { | |
QString number = QString::number(blockNumber + 1); | |
painter.setPen(Qt::black); | |
painter.drawText(0, top+4, lineNumberArea->width(), fontMetrics().height(), | |
Qt::AlignRight, number); | |
} | |
block = block.next(); | |
top = bottom; | |
bottom = top + fli.height; | |
blockNumber++; | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef NUMBEREDEDIT_H | |
#define NUMBEREDEDIT_H | |
#include <QtWidgets> | |
class LineNumberArea; | |
struct FirstLineInfo | |
{ | |
int height; | |
int firstVisible; | |
int top; | |
}; | |
class NumberedEdit : public QTextEdit | |
{ | |
Q_OBJECT | |
public: | |
explicit NumberedEdit(QWidget *parent = 0); | |
~NumberedEdit(); | |
void lineNumberAreaPaintEvent(QPaintEvent *event); | |
int lineNumberAreaWidth(); | |
protected: | |
void resizeEvent(QResizeEvent *event) override; | |
private slots: | |
void updateLineNumberAreaWidth(int newBlockCount); | |
void updateLineNumberArea(const QRect &, int); | |
private: | |
QWidget *lineNumberArea; | |
FirstLineInfo getFirstLineInfo(); | |
}; | |
#endif // NUMBEREDEDIT_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment