我试图通过使用QTextBrowser来显示来自串行端口的传入数据来制作串行终端程序。我设置了一个QTimer以每100ms调用一次paintEvent,并在串口上未收到任何内容时在QTextBrowser小部件上显示字符。

我的问题是,每次我在QTextBrowser的中间单击“说”,就好像光标移动了,然后在所有后续ui->tbOutput->insertPlainText(QString(buf));上一样,只有一半的QTextBrowser得到了更新。

当我单击QTextBrowser小部件的底部时,整个QTextBrowser会再次更新。

这是我所拥有的代码,在其他各种文章中,我都尝试将其滚动到底部,并将文本光标移动到末尾,但是它并没有实现我想要的功能。

void MainWindow::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    static char buf[10240];

    if (terminal->serialport.bytesAvailable() > 0)
    {
        // sizeof(buf)-1 so that there is space for zero termination character
        qint64 numread = terminal->serialport.read(buf,sizeof(buf)-1);

        if ((numread > 0) && (numread < sizeof(buf)))
        {
            buf[numread] = 0; // set zero termination
            ui->tbOutput->insertPlainText(QString(buf));
            ui->tbOutput->verticalScrollBar()->setValue(
                ui->tbOutput->verticalScrollBar()->maximum());

            ui->tbOutput->textCursor().setPosition(QTextCursor::End);
        }
    }
}

最佳答案

一些东西:

  • QTextBrowser::textCursor 返回一个副本,因此任何修改都不应用于
  • 文档
  • QTextBrowser::setPosition 将光标移动到绝对位置,因此您始终会移动到位置11(int值为QTextCursor::End)。使用 QTextBrowser::movePosition 代替
  • 最后是
  • ,最好在添加文本之前移动光标,因此您可以确保将其添加到文档的末尾。

  • 这里是修改后的代码:
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
    
        static char buf[10240];
    
        if (terminal->serialport.bytesAvailable() > 0)
        {
            // sizeof(buf)-1 so that there is space for zero termination character
            qint64 numread = terminal->serialport.read(buf,sizeof(buf)-1);
    
            if ((numread > 0) && (numread < sizeof(buf)))
            {
                buf[numread] = 0; // set zero termination
                auto textCursor = ui->tbOutput->textCursor();
                textCursor.movePosition(QTextCursor::End);
                ui->tbOutput->setTextCursor(textCursor);
                ui->tbOutput->insertPlainText(QString(buf));
                ui->tbOutput->verticalScrollBar()->setValue(
                    ui->tbOutput->verticalScrollBar()->maximum());
            }
        }
    }
    

    另一方面,还有一些其他注意事项:
  • QIODevice::read(char* data, qint64 maxSize) 将最多读取maxSize字节,因此无需检查读取的字节数是否小于缓冲区。
  • 不要在paintEvent中执行此操作,它不是读取数据而是显示数据的地方。取而代之的是,将计时器与插槽连接并在其中读取数据,然后仅在新数据到达时才重新绘制控制台(ui->tbOutput->update())。
  • 07-27 13:35