Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将行号添加到QTextEdit?_C++_Ide_Qt4 - Fatal编程技术网

C++ 如何将行号添加到QTextEdit?

C++ 如何将行号添加到QTextEdit?,c++,ide,qt4,C++,Ide,Qt4,我正在编写一个Visual Basic IDE,需要将行号添加到QTextEdit并突出显示当前行。我已经找到了,但是它是用java编写的,我用C++编写了我的项目。 < p>这里是C++中的等效教程: Qt4: Qt5:我知道Qt教程建议使用QPlainTextEdit实现文本编辑器,并且这个问题(除了标题中提到的以外)比处理QTextEdit小部件(绝对)更一般,但是我成功地实现了这个行为(行号+当前行号突出显示),我认为这对一些人(比如我)可能会有帮助,他们真的希望继续使用富文本小部件,并

我正在编写一个Visual Basic IDE,需要将行号添加到QTextEdit并突出显示当前行。我已经找到了,但是它是用java编写的,我用C++编写了我的项目。

< p>这里是C++中的等效教程:

Qt4:


Qt5:

我知道Qt教程建议使用
QPlainTextEdit
实现文本编辑器,并且这个问题(除了标题中提到的以外)比处理
QTextEdit
小部件(绝对)更一般,但是我成功地实现了这个行为(行号+当前行号突出显示),我认为这对一些人(比如我)可能会有帮助,他们真的希望继续使用
富文本
小部件,并希望分享我的实现(这远不是完美的-非常快的编码…)

行号rea.h:(与“Qplainntextedit”教程相同)

LineNumberArea.cpp:(与“QPlainTextEdit”教程相同)

>qtextedithighlighter.h:

class QTextEditHighlighter : public QTextEdit
{
    Q_OBJECT

public:

    explicit QTextEditHighlighter(QWidget *parent = 0);

    int getFirstVisibleBlockId();
    void lineNumberAreaPaintEvent(QPaintEvent *event);
    int lineNumberAreaWidth();

signals:


public slots:

    void resizeEvent(QResizeEvent *e);

private slots:

    void updateLineNumberAreaWidth(int newBlockCount);
    void updateLineNumberArea(QRectF /*rect_f*/);
    void updateLineNumberArea(int /*slider_pos*/);
    void updateLineNumberArea();

private:

    QWidget *lineNumberArea;

};
#include "qtextedithighlighter.h"

QTextEditHighlighter::QTextEditHighlighter(QWidget *parent) :
    QTextEdit(parent)
{
    // Line numbers
    lineNumberArea = new LineNumberArea(this);
    ///
    connect(this->document(), SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
    connect(this->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateLineNumberArea/*_2*/(int)));
    connect(this, SIGNAL(textChanged()), this, SLOT(updateLineNumberArea()));
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateLineNumberArea()));
    ///
    updateLineNumberAreaWidth(0);
}

int QTextEditHighlighter::lineNumberAreaWidth()
{
    int digits = 1;
    int max = qMax(1, this->document()->blockCount());
    while (max >= 10) {
        max /= 10;
        ++digits;
    }

    int space = 13 +  fontMetrics().width(QLatin1Char('9')) * (digits);

    return space;
}

void QTextEditHighlighter::updateLineNumberAreaWidth(int /* newBlockCount */)
{
    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}


void QTextEditHighlighter::updateLineNumberArea(QRectF /*rect_f*/)
{
    QTextEditHighlighter::updateLineNumberArea();
}
void QTextEditHighlighter::updateLineNumberArea(int /*slider_pos*/)
{
    QTextEditHighlighter::updateLineNumberArea();
}
void QTextEditHighlighter::updateLineNumberArea()
{
    /*
     * When the signal is emitted, the sliderPosition has been adjusted according to the action,
     * but the value has not yet been propagated (meaning the valueChanged() signal was not yet emitted),
     * and the visual display has not been updated. In slots connected to this signal you can thus safely
     * adjust any action by calling setSliderPosition() yourself, based on both the action and the
     * slider's value.
     */
    // Make sure the sliderPosition triggers one last time the valueChanged() signal with the actual value !!!!
    this->verticalScrollBar()->setSliderPosition(this->verticalScrollBar()->sliderPosition());

    // Since "QTextEdit" does not have an "updateRequest(...)" signal, we chose
    // to grab the imformations from "sliderPosition()" and "contentsRect()".
    // See the necessary connections used (Class constructor implementation part).

    QRect rect =  this->contentsRect();
    lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
    updateLineNumberAreaWidth(0);
    //----------
    int dy = this->verticalScrollBar()->sliderPosition();
    if (dy > -1) {
        lineNumberArea->scroll(0, dy);
    }

    // Addjust slider to alway see the number of the currently being edited line...
    int first_block_id = getFirstVisibleBlockId();
    if (first_block_id == 0 || this->textCursor().block().blockNumber() == first_block_id-1)
        this->verticalScrollBar()->setSliderPosition(dy-this->document()->documentMargin());

//    // Snap to first line (TODO...)
//    if (first_block_id > 0)
//    {
//        int slider_pos = this->verticalScrollBar()->sliderPosition();
//        int prev_block_height = (int) this->document()->documentLayout()->blockBoundingRect(this->document()->findBlockByNumber(first_block_id-1)).height();
//        if (dy <= this->document()->documentMargin() + prev_block_height)
//            this->verticalScrollBar()->setSliderPosition(slider_pos - (this->document()->documentMargin() + prev_block_height));
//    }

}


void QTextEditHighlighter::resizeEvent(QResizeEvent *e)
{
    QTextEdit::resizeEvent(e);

    QRect cr = this->contentsRect();
    lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}


int QTextEditHighlighter::getFirstVisibleBlockId()
{
    // Detect the first block for which bounding rect - once translated 
    // in absolute coordinated - is contained by the editor's text area

    // Costly way of doing but since "blockBoundingGeometry(...)" doesn't 
    // exists for "QTextEdit"...

    QTextCursor curs = QTextCursor(this->document());
    curs.movePosition(QTextCursor::Start);
    for(int i=0; i < this->document()->blockCount(); ++i)
    {
        QTextBlock block = curs.block();

        QRect r1 = this->viewport()->geometry();
        QRect r2 = this->document()->documentLayout()->blockBoundingRect(block).translated(
                    this->viewport()->geometry().x(), this->viewport()->geometry().y() - (
                        this->verticalScrollBar()->sliderPosition()
                        ) ).toRect();

        if (r1.contains(r2, true)) { return i; }

        curs.movePosition(QTextCursor::NextBlock);
    }

    return 0;
}

void QTextEditHighlighter::lineNumberAreaPaintEvent(QPaintEvent *event)
{
    this->verticalScrollBar()->setSliderPosition(this->verticalScrollBar()->sliderPosition());

    QPainter painter(lineNumberArea);
    painter.fillRect(event->rect(), Qt::lightGray);
    int blockNumber = this->getFirstVisibleBlockId();

    QTextBlock block = this->document()->findBlockByNumber(blockNumber);
    QTextBlock prev_block = (blockNumber > 0) ? this->document()->findBlockByNumber(blockNumber-1) : block;
    int translate_y = (blockNumber > 0) ? -this->verticalScrollBar()->sliderPosition() : 0;

    int top = this->viewport()->geometry().top();

    // Adjust text position according to the previous "non entirely visible" block 
    // if applicable. Also takes in consideration the document's margin offset.
    int additional_margin;
    if (blockNumber == 0)
        // Simply adjust to document's margin
        additional_margin = (int) this->document()->documentMargin() -1 - this->verticalScrollBar()->sliderPosition();
    else
        // Getting the height of the visible part of the previous "non entirely visible" block
        additional_margin = (int) this->document()->documentLayout()->blockBoundingRect(prev_block)
                .translated(0, translate_y).intersect(this->viewport()->geometry()).height();

    // Shift the starting point
    top += additional_margin;

    int bottom = top + (int) this->document()->documentLayout()->blockBoundingRect(block).height();

    QColor col_1(90, 255, 30);      // Current line (custom green)
    QColor col_0(120, 120, 120);    // Other lines  (custom darkgrey)

    // Draw the numbers (displaying the current line number in green)
    while (block.isValid() && top <= event->rect().bottom()) {
        if (block.isVisible() && bottom >= event->rect().top()) {
            QString number = QString::number(blockNumber + 1);
            painter.setPen(QColor(120, 120, 120));
            painter.setPen((this->textCursor().blockNumber() == blockNumber) ? col_1 : col_0);
            painter.drawText(-5, top,
                             lineNumberArea->width(), fontMetrics().height(),
                             Qt::AlignRight, number);
        }

        block = block.next();
        top = bottom;
        bottom = top + (int) this->document()->documentLayout()->blockBoundingRect(block).height();
        ++blockNumber;
    }

}
>qtextedhighlighter.cpp:

class QTextEditHighlighter : public QTextEdit
{
    Q_OBJECT

public:

    explicit QTextEditHighlighter(QWidget *parent = 0);

    int getFirstVisibleBlockId();
    void lineNumberAreaPaintEvent(QPaintEvent *event);
    int lineNumberAreaWidth();

signals:


public slots:

    void resizeEvent(QResizeEvent *e);

private slots:

    void updateLineNumberAreaWidth(int newBlockCount);
    void updateLineNumberArea(QRectF /*rect_f*/);
    void updateLineNumberArea(int /*slider_pos*/);
    void updateLineNumberArea();

private:

    QWidget *lineNumberArea;

};
#include "qtextedithighlighter.h"

QTextEditHighlighter::QTextEditHighlighter(QWidget *parent) :
    QTextEdit(parent)
{
    // Line numbers
    lineNumberArea = new LineNumberArea(this);
    ///
    connect(this->document(), SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int)));
    connect(this->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateLineNumberArea/*_2*/(int)));
    connect(this, SIGNAL(textChanged()), this, SLOT(updateLineNumberArea()));
    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateLineNumberArea()));
    ///
    updateLineNumberAreaWidth(0);
}

int QTextEditHighlighter::lineNumberAreaWidth()
{
    int digits = 1;
    int max = qMax(1, this->document()->blockCount());
    while (max >= 10) {
        max /= 10;
        ++digits;
    }

    int space = 13 +  fontMetrics().width(QLatin1Char('9')) * (digits);

    return space;
}

void QTextEditHighlighter::updateLineNumberAreaWidth(int /* newBlockCount */)
{
    setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
}


void QTextEditHighlighter::updateLineNumberArea(QRectF /*rect_f*/)
{
    QTextEditHighlighter::updateLineNumberArea();
}
void QTextEditHighlighter::updateLineNumberArea(int /*slider_pos*/)
{
    QTextEditHighlighter::updateLineNumberArea();
}
void QTextEditHighlighter::updateLineNumberArea()
{
    /*
     * When the signal is emitted, the sliderPosition has been adjusted according to the action,
     * but the value has not yet been propagated (meaning the valueChanged() signal was not yet emitted),
     * and the visual display has not been updated. In slots connected to this signal you can thus safely
     * adjust any action by calling setSliderPosition() yourself, based on both the action and the
     * slider's value.
     */
    // Make sure the sliderPosition triggers one last time the valueChanged() signal with the actual value !!!!
    this->verticalScrollBar()->setSliderPosition(this->verticalScrollBar()->sliderPosition());

    // Since "QTextEdit" does not have an "updateRequest(...)" signal, we chose
    // to grab the imformations from "sliderPosition()" and "contentsRect()".
    // See the necessary connections used (Class constructor implementation part).

    QRect rect =  this->contentsRect();
    lineNumberArea->update(0, rect.y(), lineNumberArea->width(), rect.height());
    updateLineNumberAreaWidth(0);
    //----------
    int dy = this->verticalScrollBar()->sliderPosition();
    if (dy > -1) {
        lineNumberArea->scroll(0, dy);
    }

    // Addjust slider to alway see the number of the currently being edited line...
    int first_block_id = getFirstVisibleBlockId();
    if (first_block_id == 0 || this->textCursor().block().blockNumber() == first_block_id-1)
        this->verticalScrollBar()->setSliderPosition(dy-this->document()->documentMargin());

//    // Snap to first line (TODO...)
//    if (first_block_id > 0)
//    {
//        int slider_pos = this->verticalScrollBar()->sliderPosition();
//        int prev_block_height = (int) this->document()->documentLayout()->blockBoundingRect(this->document()->findBlockByNumber(first_block_id-1)).height();
//        if (dy <= this->document()->documentMargin() + prev_block_height)
//            this->verticalScrollBar()->setSliderPosition(slider_pos - (this->document()->documentMargin() + prev_block_height));
//    }

}


void QTextEditHighlighter::resizeEvent(QResizeEvent *e)
{
    QTextEdit::resizeEvent(e);

    QRect cr = this->contentsRect();
    lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}


int QTextEditHighlighter::getFirstVisibleBlockId()
{
    // Detect the first block for which bounding rect - once translated 
    // in absolute coordinated - is contained by the editor's text area

    // Costly way of doing but since "blockBoundingGeometry(...)" doesn't 
    // exists for "QTextEdit"...

    QTextCursor curs = QTextCursor(this->document());
    curs.movePosition(QTextCursor::Start);
    for(int i=0; i < this->document()->blockCount(); ++i)
    {
        QTextBlock block = curs.block();

        QRect r1 = this->viewport()->geometry();
        QRect r2 = this->document()->documentLayout()->blockBoundingRect(block).translated(
                    this->viewport()->geometry().x(), this->viewport()->geometry().y() - (
                        this->verticalScrollBar()->sliderPosition()
                        ) ).toRect();

        if (r1.contains(r2, true)) { return i; }

        curs.movePosition(QTextCursor::NextBlock);
    }

    return 0;
}

void QTextEditHighlighter::lineNumberAreaPaintEvent(QPaintEvent *event)
{
    this->verticalScrollBar()->setSliderPosition(this->verticalScrollBar()->sliderPosition());

    QPainter painter(lineNumberArea);
    painter.fillRect(event->rect(), Qt::lightGray);
    int blockNumber = this->getFirstVisibleBlockId();

    QTextBlock block = this->document()->findBlockByNumber(blockNumber);
    QTextBlock prev_block = (blockNumber > 0) ? this->document()->findBlockByNumber(blockNumber-1) : block;
    int translate_y = (blockNumber > 0) ? -this->verticalScrollBar()->sliderPosition() : 0;

    int top = this->viewport()->geometry().top();

    // Adjust text position according to the previous "non entirely visible" block 
    // if applicable. Also takes in consideration the document's margin offset.
    int additional_margin;
    if (blockNumber == 0)
        // Simply adjust to document's margin
        additional_margin = (int) this->document()->documentMargin() -1 - this->verticalScrollBar()->sliderPosition();
    else
        // Getting the height of the visible part of the previous "non entirely visible" block
        additional_margin = (int) this->document()->documentLayout()->blockBoundingRect(prev_block)
                .translated(0, translate_y).intersect(this->viewport()->geometry()).height();

    // Shift the starting point
    top += additional_margin;

    int bottom = top + (int) this->document()->documentLayout()->blockBoundingRect(block).height();

    QColor col_1(90, 255, 30);      // Current line (custom green)
    QColor col_0(120, 120, 120);    // Other lines  (custom darkgrey)

    // Draw the numbers (displaying the current line number in green)
    while (block.isValid() && top <= event->rect().bottom()) {
        if (block.isVisible() && bottom >= event->rect().top()) {
            QString number = QString::number(blockNumber + 1);
            painter.setPen(QColor(120, 120, 120));
            painter.setPen((this->textCursor().blockNumber() == blockNumber) ? col_1 : col_0);
            painter.drawText(-5, top,
                             lineNumberArea->width(), fontMetrics().height(),
                             Qt::AlignRight, number);
        }

        block = block.next();
        top = bottom;
        bottom = top + (int) this->document()->documentLayout()->blockBoundingRect(block).height();
        ++blockNumber;
    }

}
#包括“qtextedhighlighter.h”
QTextEditHighlighter::QTextEditHighlighter(QWidget*父项):
QTextEdit(父级)
{
//行号
lineNumberArea=新的lineNumberArea(本);
///
连接(此->文档(),信号(blockCountChanged(int)),此,插槽(updateLineNumberAreaWidth(int));
连接(this->verticalScrollBar(),信号(valueChanged(int)),this,插槽(updateLineNumberArea/*_2*/(int));
连接(此,信号(textChanged()),此,插槽(updateLineNumberArea());
连接(此,信号(cursorPositionChanged()),此,插槽(updateLineNumberArea());
///
updateLineNumberAreaWidth(0);
}
int QTextEditHighlighter::lineNumberEAWidth()
{
整数位数=1;
int max=qMax(1,this->document()->blockCount());
而(最大值>=10){
最大/=10;
++数字;
}
int space=13+fontMetrics().width(QLatin1Char('9'))*(数字);
返回空间;
}
void QTextEditHighlighter::updateLineNumberAreaWidth(int/*newBlockCount*/)
{
setViewportMargins(lineNumberEAWidth(),0,0,0);
}
void QTextEditHighlighter::updateLineNumberArea(QRectF/*rect\u f*/)
{
QTextEditHighlighter::updateLineNumberArea();
}
void QTextEditHighlighter::updateLineNumberArea(int/*滑块位置*/)
{
QTextEditHighlighter::updateLineNumberArea();
}
void QTextEditHighlighter::updateLineNumberArea()
{
/*
*当信号发出时,滑块位置已根据动作进行调整,
*但该值尚未传播(意味着valueChanged()信号尚未发出),
*并且视觉显示尚未更新。因此,在连接到该信号的插槽中,您可以安全地
*通过自己调用setSliderPosition()来调整任何操作,方法是基于操作和
*滑块的值。
*/
//确保滑块位置在valueChanged()信号与实际值最后一次触发!!!!
此->垂直滚动条()->设置滑块位置(此->垂直滚动条()->滑块位置());
//因为“QTextEdit”没有“updateRequest(…)”信号,所以我们选择
//从“sliderPosition()”和“contentsRect()”中获取信息。
//请参阅使用的必要连接(类构造函数实现部分)。
QRect rect=this->contentsRect();
lineNumberArea->update(0,rect.y(),lineNumberArea->width(),rect.height());
updateLineNumberAreaWidth(0);
//----------
int dy=此->垂直滚动条()->滑块位置();
如果(dy>-1){
行号区域->滚动(0,dy);
}
//Addjust滑块可始终查看当前正在编辑的行的编号。。。
int first_block_id=getFirstVisibleBlockId();
如果(第一个块id==0 | | this->textCursor().block().blockNumber()==第一个块id-1)
此->垂直滚动条()->setSliderPosition(根据此->文档()->documentMargin());
////捕捉到第一行(TODO…)
//如果(第一块\u id>0)
//    {
//int slider_pos=this->verticalScrollBar()->sliderPosition();
//int prev_block_height=(int)this->document()->documentLayout()->blockBoundingRect(this->document()->findBlockByNumber(first_block_id-1)).height();
//if(dy document()->documentMargin()+上一块高度)
//此->垂直滚动条()->设置滑块位置(滑块位置-(此->文档()->文档边距()+上一块高度));
//    }
}
void qtextedhighlighter::resizeEvent(QResizeEvent*e)
{
QTextEdit::resizeEvent(e);
QRect cr=此->内容引用();
lineNumberArea->setGeometry(QRect(cr.left(),cr.top(),lineNumberAreaWidth(),cr.height());
}
int QTextEditHighlighter::getFirstVisibleBlockId()
{
//检测为其转换边界矩形一次的第一个块
//在绝对坐标中-包含在编辑器的文本区域中
//这是一种代价高昂的方法,但因为“blockBoundingGeometry(…)”并没有这样做
//存在“QTextEdit”。。。
QTextCursor curs=QTextCursor(此->文档());
curs.movePosition(QTextCursor::Start);
对于(int i=0;idocument()->blockCount();++i)
{
QTextBlock=curs.block();
QRect r1=此->视口()->几何体();
QRect r2=this->document()->documentLayout()->blockBoundingRect(block).translated(
此->视口()->几何体().x(),此->视口()->几何体().y()(
此->垂直滚动条()->滑块位置()
)).toRect();
如果(r1.contains(r2,true)){return i;}
curs.movePosition(QTextCursor::NextBlock);
}
返回0;
}
void QTextEditHighlighter::LineNumberEAPAINTEVENT(QPaintEvent*事件)
{
此->垂直滚动条()->设置滑块位置(此->垂直滚动条()->滑块位置());
Q油漆工(线号A);
fillRect(事件->rect(),Qt::lightGray);
int blockNumb
// Here is the key to obtain the y coordinate of the block start
QTextCursor blockCursor(block);
QRect blockCursorRect = this->cursorRect(blockCursor);
painter.drawText(-5, blockCursorRect.y() /* + a little offset to align */,
                 m_lineNumberArea->width(), fixedLineHeight,
                 Qt::AlignRight, number);