Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.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++ 如何在Qt中的QTextEdit中显示文本后面或前面的图形对象?_C++_Qt_Autocomplete_Syntax Highlighting_Qtextedit - Fatal编程技术网

C++ 如何在Qt中的QTextEdit中显示文本后面或前面的图形对象?

C++ 如何在Qt中的QTextEdit中显示文本后面或前面的图形对象?,c++,qt,autocomplete,syntax-highlighting,qtextedit,C++,Qt,Autocomplete,Syntax Highlighting,Qtextedit,我想在我选择的单词后面显示一个矩形,就像Qt Creator在这里所做的那样: 我正在试验QSyntaxHighlighter的示例。我能够根据关键字模式更改样式。我希望有用于自定义自动完成列表的图形或小部件。对于自动完成,请遵循或 下面的代码是第一个代码的后续代码,我毫不掩饰地将其复制并集成到BackgroundHighlighter类和main.cpp中 这个答案将包含一个项目中的五个文件以及一个Qt资源文件 highlighter.h(用于语法的highlighter类) highli

我想在我选择的单词后面显示一个矩形,就像Qt Creator在这里所做的那样:


我正在试验QSyntaxHighlighter的示例。我能够根据关键字模式更改样式。我希望有用于自定义自动完成列表的图形或小部件。

对于自动完成,请遵循或

下面的代码是第一个代码的后续代码,我毫不掩饰地将其复制并集成到
BackgroundHighlighter
类和
main.cpp


这个答案将包含一个项目中的五个文件以及一个Qt资源文件

  • highlighter.h
    (用于语法的highlighter类)
  • highlighter.cpp
  • backgroundHighlighter.h
    (backgroundHighlighter类)
  • backgroundHighlighter.cpp
  • main.cpp
  • res.qrc
    (可选,不需要,您可以硬编码文本)
  • res
    (目录)(可选)
  • |-symbols.txt
    (可选,您可以设置自己的默认文本)
  • |-wordlist.txt
    (可选,从中复制,但您可以使用自己的行分隔单词列表,并在
    main.cpp
    中使用
  • 请注意,(1)和(2)的荧光灯类的实现可以在中找到。我将把它的实现留给读者作为练习

    在调用
    BackgroundHighlighter
    类时,可以向其传递文件名以从文件加载文本。(这不在OP的规范中,但由于我想测试大量文本,因此实现起来很方便。)

    还要注意的是,我已经将

    以下是
    backgroundHighlighter.h
    (3)(约45行,约60行带补全符):

    最后,这里是
    main.cpp
    (5)(~10行,~45行带完成符)

    大约需要1秒,这可能并不理想(100ms可能更理想)

    但是,您可能希望在行数增长时注意它。对于1000行的同一文本文件,程序将开始用大约3秒的时间突出显示

    请注意。。。我没有完全优化它。可能有一个更好的实现,它只在符号滚动到用户视图时格式化。这只是一个建议。我不知道如何实现它


    注释

    • 为了便于参考,我在上附加了symbols.txt和wordlist.txt
    • 如果要更改格式的背景颜色,请转到
      backgroundhighlighter.cpp
      的第27至29行。在那里,你可以看到我集中了格式
    • BackgroundHighlighter::clearHighlights()
      可能会清除最初添加的任何背景高光,因为它会将整个文档的字符背景设置为默认格式。这可能是结果的意外后果

    嗨!你试过什么?你如何尝试QSyntaxHighlighter?我有这个例子,到目前为止我没有遇到任何问题:上面的图像是Qtcreator的外观,也是我希望我的应用程序的外观,那么我如何在QTextEdit中渲染矩形或其他形状(可以吗?)?你签出了吗,?否。我将检查它们是否符合我的要求。我将为已执行此操作或能够在QTextedit中显示图形的人打开线程。您可以为我提供symbols.txt和wordlist.txt,因为我不知道放在那里什么。我尝试了:symbols.txt:“inc incl includ include class include”wordlist.txt:“class include typedef printf int main{\n}返回“完成列表是如何触发的?有了这些文件,我无法触发它。highlition在这里工作你去:。犯错误应在输入至少3个字符后触发完成。如果它不起作用,可能首先尝试一个单独的实现?编辑:我没有纠正这两个文件的路径。现在它自己触发。嗯。。。所以不用打字,它就会自动弹出?在
    main.cpp
    中,尝试将
    setModel
    实现替换为
    completer->setModel(QStringListModel(QStringList())不,我的意思是,现在当我添加3个字母时,会触发补全符。它工作得很好。你能给我解释一下symbols.txt的作用吗?世界主义者不是我自动补全唯一需要的东西吗?symbols.txt的用途是什么?
    
    #ifndef BACKGROUNDHIGHLIGHTER_H
    #define BACKGROUNDHIGHLIGHTER_H
    
    #include <QtWidgets>
    #include <QtGui>
    
    //  this is the file to your highlighter
    #include "myhighlighter.h"
    
    class BackgroundHighlighter : public QTextEdit
    {
        Q_OBJECT
    public:
        BackgroundHighlighter(const QString &fileName = QString(), QWidget *parent = nullptr);
    
        void loadFile(const QString &fileName);
    
        void setCompleter(QCompleter *completer);
        QCompleter *completer() const;
    
    protected:
        void keyPressEvent(QKeyEvent *e) override;
        void focusInEvent(QFocusEvent *e) override;
    
    public slots:
        void onCursorPositionChanged();
    
    private slots:
        void insertCompletion(const QString &completion);
    
    private:
        //  this is your syntax highlighter
        Highlighter *syntaxHighlighter;
    
        //  stores the symbol being highlighted
        QString highlightSymbol;
    
        //  stores the position (front of selection) where the cursor was originally placed
        int mainHighlightPosition;
    
        //  stores character formats to be used
        QTextCharFormat mainFmt;           //  refers to format block directly under the cursor   
        QTextCharFormat subsidiaryFmt;     //  refers to the formatting blocks on matching words  
        QTextCharFormat defaultFmt;        //  refers to the default format of the **entire** document which will be used in resetting the format     
    
        void setWordFormat(const int &position, const QTextCharFormat &format);
        void runHighlight();
        void clearHighlights();
        void highlightMatchingSymbols(const QString &symbol);
    
        //  completer, copied from example
        QString textUnderCursor() const;
        QCompleter *c;
    
    };
    
    #endif // BACKGROUNDHIGHLIGHTER_H
    
    #include "backgroundhighlighter.h"
    
    #include <QDebug>
    
    //  constructor
    BackgroundHighlighter::BackgroundHighlighter(const QString &fileName, QWidget *parent) :
        QTextEdit(parent)
    {
        //  I like Monaco
        setFont(QFont("Monaco"));
        setMinimumSize(QSize(500, 200));
    
        //  load initial text from a file OR from a hardcoded default
        if (!fileName.isEmpty())
            loadFile(fileName);
        else
        {
            QString defaultText = "This is a default text implemented by "
                                  "a stackoverflow user. Please upvote the answer "
                                  "at https://stackoverflow.com/a/53351512/10239789.";
    
            setPlainText(defaultText);
        }
    
        //  set the highlighter here
        QTextDocument *doc = document();
        syntaxHighlighter = new Highlighter(doc);
    
        //  TODO change brush/colours to match theme
        mainFmt.setBackground(Qt::yellow);
        subsidiaryFmt.setBackground(Qt::lightGray);
        defaultFmt.setBackground(Qt::white);
    
        //  connect the signal to our handler
        connect(this, &QTextEdit::cursorPositionChanged, this, &BackgroundHighlighter::onCursorPositionChanged);
    }
    
    //  convenience function for reading a file
    void BackgroundHighlighter::loadFile(const QString &fileName)
    {
        QFile file(fileName);
        if (!file.open(QIODevice::ReadOnly))
            return;
    
        //  the file could be in Plain Text OR Html
        setText(file.readAll());
    }
    
    void BackgroundHighlighter::setCompleter(QCompleter *completer)
    {
        if (c)
            QObject::disconnect(c, 0, this, 0);
    
        c = completer;
    
        if (!c)
            return;
    
        c->setWidget(this);
        c->setCompletionMode(QCompleter::PopupCompletion);
        c->setCaseSensitivity(Qt::CaseInsensitive);
        QObject::connect(c, SIGNAL(activated(QString)),
                         this, SLOT(insertCompletion(QString)));
    }
    
    QCompleter *BackgroundHighlighter::completer() const
    {
        return c;
    }
    
    void BackgroundHighlighter::keyPressEvent(QKeyEvent *e)
    {
        if (c && c->popup()->isVisible()) {
            // The following keys are forwarded by the completer to the widget
           switch (e->key()) {
           case Qt::Key_Enter:
           case Qt::Key_Return:
           case Qt::Key_Escape:
           case Qt::Key_Tab:
           case Qt::Key_Backtab:
                e->ignore();
                return; // let the completer do default behavior
           default:
               break;
           }
        }
    
        bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
        if (!c || !isShortcut) // do not process the shortcut when we have a completer
            QTextEdit::keyPressEvent(e);
    
        const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
       if (!c || (ctrlOrShift && e->text().isEmpty()))
           return;
    
       static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word
       bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
       QString completionPrefix = textUnderCursor();
    
       if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 3
                         || eow.contains(e->text().right(1)))) {
           c->popup()->hide();
           return;
       }
    
       if (completionPrefix != c->completionPrefix()) {
           c->setCompletionPrefix(completionPrefix);
           c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
       }
       QRect cr = cursorRect();
       cr.setWidth(c->popup()->sizeHintForColumn(0)
                   + c->popup()->verticalScrollBar()->sizeHint().width());
       c->complete(cr); // pop it up!
    }
    
    void BackgroundHighlighter::focusInEvent(QFocusEvent *e)
    {
        if (c)
            c->setWidget(this);
        QTextEdit::focusInEvent(e);
    }
    
    //  convenience function for setting a `charFmt` at a `position`
    void BackgroundHighlighter::setWordFormat(const int &position, const QTextCharFormat &charFmt)
    {
        QTextCursor cursor = textCursor();
        cursor.setPosition(position);
        cursor.select(QTextCursor::WordUnderCursor);
        cursor.setCharFormat(charFmt);
    }
    
    //  this will handle the `QTextEdit::cursorPositionChanged()` signal
    void BackgroundHighlighter::onCursorPositionChanged()
    {
        //  if cursor landed on different format, the `currentCharFormat` will be changed
        //  we need to change it back to white
        setCurrentCharFormat(defaultFmt);
    
        //  this is the function you're looking for
        runHighlight(); 
    }
    
    void BackgroundHighlighter::insertCompletion(const QString &completion)
    {
        if (c->widget() != this)
            return;
        QTextCursor tc = textCursor();
        int extra = completion.length() - c->completionPrefix().length();
        tc.movePosition(QTextCursor::Left);
        tc.movePosition(QTextCursor::EndOfWord);
        tc.insertText(completion.right(extra));
        setTextCursor(tc);
    }
    
    QString BackgroundHighlighter::textUnderCursor() const
    {
        QTextCursor tc = textCursor();
        tc.select(QTextCursor::WordUnderCursor);
        return tc.selectedText();
    }
    
    /**
     * BRIEF
     * Check if new highlighting is needed
     * Clear previous highlights
     * Check if the word under the cursor is a symbol (i.e. matches ^[A-Za-z0-9_]+$)
     * Highlight all relevant symbols
     */
    void BackgroundHighlighter::runHighlight()
    {
        //  retrieve cursor
        QTextCursor cursor = textCursor();
    
        //  retrieve word under cursor
        cursor.select(QTextCursor::WordUnderCursor);
        QString wordUnder = cursor.selectedText();
        qDebug() << "Word Under Cursor:" << wordUnder;
    
        //  get front of cursor, used later for storing in `highlightPositions` or `mainHighlightPosition`
        int cursorFront = cursor.selectionStart();
    
        //  if the word under cursor is the same, then save time
        //  by skipping the process
        if (wordUnder == highlightSymbol)
        {
            //  switch formats
            setWordFormat(mainHighlightPosition, subsidiaryFmt);    //  change previous main to subsidiary                     
            setWordFormat(cursorFront, mainFmt);                  //  change position under cursor to main               
    
            //  update main position
            mainHighlightPosition = cursorFront;
    
            //  jump the gun
            return;
        }
    
        //  clear previous highlights
        if (mainHighlightPosition != -1)
            clearHighlights();
    
        //  check if selected word is a symbol
        if (!wordUnder.contains(QRegularExpression("^[A-Za-z0-9_]+$")))
        {
            qDebug() << wordUnder << "is not a symbol!";
            return;
        }
    
        //  set the highlight symbol
        highlightSymbol = wordUnder;
    
        //  store the cursor position to check later
        mainHighlightPosition = cursorFront;
    
        //  highlight all relevant symbols
        highlightMatchingSymbols(wordUnder);
    
        qDebug() << "Highlight done\n\n";
    }
    
    //  clear previously highlights
    void BackgroundHighlighter::clearHighlights()
    {
        QTextCursor cursor = textCursor();
    
        //  wipe the ENTIRE document with the default background, this should be REALLY fast
        //  WARNING: this may have unintended consequences if you have other backgrounds you want to keep                 
        cursor.select(QTextCursor::Document);
        cursor.setCharFormat(defaultFmt);
    
        //  reset variables
        mainHighlightPosition = -1;
        highlightSymbol.clear();
    }
    
    //  highlight all matching symbols
    void BackgroundHighlighter::highlightMatchingSymbols(const QString &symbol)
    {
        //  highlight background of congruent symbols
        QString docText = toPlainText();
    
        //  use a regex with \\b to look for standalone symbols
        QRegularExpression regexp("\\b" + symbol + "\\b");
    
        //  loop through all matches in the text
        int matchPosition = docText.indexOf(regexp);
        while (matchPosition != -1)
        {
            //  if the position 
            setWordFormat(matchPosition, matchPosition == mainHighlightPosition ? mainFmt : subsidiaryFmt);            
    
            //  find next match
            matchPosition = docText.indexOf(regexp, matchPosition + 1);
        }
    }
    
    #include <QApplication>
    #include <backgroundhighlighter.h>
    
    QAbstractItemModel *modelFromFile(const QString& fileName, QCompleter *completer)     
    {
        QFile file(fileName);
        if (!file.open(QFile::ReadOnly))
            return new QStringListModel(completer);
    
    #ifndef QT_NO_CURSOR
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    #endif
        QStringList words;
    
        while (!file.atEnd()) {
            QByteArray line = file.readLine();
            if (!line.isEmpty())
                words << line.trimmed();
        }
    
    #ifndef QT_NO_CURSOR
        QApplication::restoreOverrideCursor();
    #endif
    
        return new QStringListModel(words, completer);
    }
    
    int main(int argc, char *argv[]) {
        QApplication a(argc, argv);
    
        BackgroundHighlighter bh(":/res/symbols.txt");
    
        QCompleter *completer = new QCompleter();
    
        completer->setModel(modelFromFile(":/res/wordlist.txt", completer));
    
        // use this and comment the above if you don't have or don't want to use wordlist.txt
        // QStringListModel *model = new QStringListModel(QStringList() << "aaaaaaa" << "aaaaab" << "aaaabb" << "aaacccc",     
                                                   completer);
        // completer->setModel(model);
    
        completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
        completer->setCaseSensitivity(Qt::CaseInsensitive);
        completer->setWrapAround(false);
        bh.setCompleter(completer);
    
        bh.show();
    
        return a.exec();
    }
    
    symbol1 symbol2 symbol3 symbol4 symbol5
    symbol1 symbol2 symbol3 symbol4 symbol5
    symbol1 symbol2 symbol3 symbol4 symbol5
    // ... ditto 500 lines