Highlight text that matches a search string in Qt5












1














First let me explain what I'm trying to achieve:



In your browser, hit Ctrl + f and type "q". The result of that operation is what I'm trying to achieve. It seems like this should be a solved problem, but despite the many hours I've spent researching, reading documentation, and asking around in the Qt IRC, I'm still stuck. Maybe somebody here will be able to give me a hand.



The following Qt classes are what I'm currently dealing with, in case you want to brush up a bit.:
Qt::DisplayRole
QModelIndex::data
QAbstractItemView::setDelegate
QTextEdit::setExtraSelections (only as a reference)
QAbstractDocumentLayout::Selection
QTextDocument::drawContents
QStyledItemDelegate::paint
QStyleOptionViewItem
QStyleOption::rect
QTableView
QAbstractItemModel::match
Learn to Model/View Program with Qt



So now, let me explain how I have things set up, and what the results of my research and interactions with the Qt IRC has lead me to believe I should do.



I am using a QStandardItemModel along with a QTableView. Each row that gets appended to the QStandardItemModel has several columns. As we know, each of these columns is represented in the QStandardItemModel as a QModelIndex. We can pull its displayed text by accessing its data(Qt::DisplayRole).



Conveniently, given a search string, QStandardItemModel::match will return a QModelIndexList of every QModelIndex that, well, matched in the column. Of course, if you have several columns in every row, you would need to preform this match over each column, but I can worry about performance here later.



So cool, that problem is solved. We have our list of every QModelIndex that had a matching string. Now, what I want to do is highlight that string in each column. For example:



Search string: "col"

This is a column | This is aColumn | This is aColumn | This is a co



Parts that would appear highlighted are what I have in bold above. In order to achieve this, I knew from reading the Model/View docs that I needed to subclass a QStyledItemDelegate and reimplement its paint function. So I started there.



The next problem to solve would be, how in the world to select a specific piece of text in the DisplayRole and only highlight it? You can't use Qt::BackgroundRole, that would set the entire index's background color. Enter QTextDocument.



I still need to do more digging to see how exactly I can implement that behavior, but from what I was told in Qt IRC, QTextEdit has a function called setExtraSelections. Looking at how that is implemented, it leverages QAbstractTextDocumentLayout::Selection and various cursor functions available to me in QTextDocument.



However, sadly I cannot even begin to solve that problem, because the first step is to actually ensure that I can render a QTextDocument to the QTableView with my reimplemented custom delegate paint function. This is where I'm stuck currently. I've seen this post, here and the one it references:
Similar question that doesn't solve my issue



Its not exactly what I was looking for, but I figured it would help me at least get something rendering. It looks though like in his code, he's drawing the control (which is literally what QStyledItemDelegate does), and then tries to paint his QTextDocument over it. Maybe that's not what that is doing but it sure looks like it.



In any case, when I tried that, it looked like the QTextDocument had no effect. If I commented out the drawControl call, then no text would be rendered at all. Here is my code for that:



void CustomDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 
{
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);

if (index.column() == contentColumn)
{
painter->save();

QTextDocument contentDocument;
//opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);

opt.text = "Things";
painter->setBrush(QBrush(Qt::darkCyan));
contentDocument.drawContents(painter, opt.rect);

painter->restore();
}
else
{
QStyledItemDelegate::paint(painter, option, index);
}
}


You can see I just typed text "Things" to see if I could just get that to render. To no avail.



Before summarizing my question I want to mention that no, I cannot use a QTextEdit. There are specific columns that I need to word wrap, while others I do not want to word wrap. QTableView displays the data exactly as I expect to see it.



So my question is this:
Is the QTextDocument rendering through the paint event of a subclassed QStyledItemDelegate the preferred way to handle this? If not, how else should I deal with it?



If so, how do I make it work as I expect? What is wrong with the code that I have?



Bonus 2 parter question
Once I can render, how can I actually leverage the QTextDocument API to highlight only specific pieces, given that the list of model indexes that contain the text to be highlighted is discovered in a completely different function and at a different time than when the paint function executes?



Update 0
Using the QTextDocument API to make multiple selections is looking like an impossible feat. The column that I would be drawing contents to needs to word wrap and expand.



From what I can tell, I calling drawContents manually means handling resizing, word wrapping, and many other things manually which is not a path I want to go down if that is indeed the case.



I've got another way in mind, I will update if it works.



Update 1
I have accomplished what I want in another way. Unfortunately, I cannot use Qt for what I want. Qt's Model/View system is entirely too inefficient and getting it to do what I need causes it to be extremely and unacceptably slow. How did I accomplish the highlighting?



I will describe in an answer. If nobody gives me a better answer, I will pick mine as the best.










share|improve this question





























    1














    First let me explain what I'm trying to achieve:



    In your browser, hit Ctrl + f and type "q". The result of that operation is what I'm trying to achieve. It seems like this should be a solved problem, but despite the many hours I've spent researching, reading documentation, and asking around in the Qt IRC, I'm still stuck. Maybe somebody here will be able to give me a hand.



    The following Qt classes are what I'm currently dealing with, in case you want to brush up a bit.:
    Qt::DisplayRole
    QModelIndex::data
    QAbstractItemView::setDelegate
    QTextEdit::setExtraSelections (only as a reference)
    QAbstractDocumentLayout::Selection
    QTextDocument::drawContents
    QStyledItemDelegate::paint
    QStyleOptionViewItem
    QStyleOption::rect
    QTableView
    QAbstractItemModel::match
    Learn to Model/View Program with Qt



    So now, let me explain how I have things set up, and what the results of my research and interactions with the Qt IRC has lead me to believe I should do.



    I am using a QStandardItemModel along with a QTableView. Each row that gets appended to the QStandardItemModel has several columns. As we know, each of these columns is represented in the QStandardItemModel as a QModelIndex. We can pull its displayed text by accessing its data(Qt::DisplayRole).



    Conveniently, given a search string, QStandardItemModel::match will return a QModelIndexList of every QModelIndex that, well, matched in the column. Of course, if you have several columns in every row, you would need to preform this match over each column, but I can worry about performance here later.



    So cool, that problem is solved. We have our list of every QModelIndex that had a matching string. Now, what I want to do is highlight that string in each column. For example:



    Search string: "col"

    This is a column | This is aColumn | This is aColumn | This is a co



    Parts that would appear highlighted are what I have in bold above. In order to achieve this, I knew from reading the Model/View docs that I needed to subclass a QStyledItemDelegate and reimplement its paint function. So I started there.



    The next problem to solve would be, how in the world to select a specific piece of text in the DisplayRole and only highlight it? You can't use Qt::BackgroundRole, that would set the entire index's background color. Enter QTextDocument.



    I still need to do more digging to see how exactly I can implement that behavior, but from what I was told in Qt IRC, QTextEdit has a function called setExtraSelections. Looking at how that is implemented, it leverages QAbstractTextDocumentLayout::Selection and various cursor functions available to me in QTextDocument.



    However, sadly I cannot even begin to solve that problem, because the first step is to actually ensure that I can render a QTextDocument to the QTableView with my reimplemented custom delegate paint function. This is where I'm stuck currently. I've seen this post, here and the one it references:
    Similar question that doesn't solve my issue



    Its not exactly what I was looking for, but I figured it would help me at least get something rendering. It looks though like in his code, he's drawing the control (which is literally what QStyledItemDelegate does), and then tries to paint his QTextDocument over it. Maybe that's not what that is doing but it sure looks like it.



    In any case, when I tried that, it looked like the QTextDocument had no effect. If I commented out the drawControl call, then no text would be rendered at all. Here is my code for that:



    void CustomDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 
    {
    QStyleOptionViewItem opt = option;
    initStyleOption(&opt, index);

    if (index.column() == contentColumn)
    {
    painter->save();

    QTextDocument contentDocument;
    //opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);

    opt.text = "Things";
    painter->setBrush(QBrush(Qt::darkCyan));
    contentDocument.drawContents(painter, opt.rect);

    painter->restore();
    }
    else
    {
    QStyledItemDelegate::paint(painter, option, index);
    }
    }


    You can see I just typed text "Things" to see if I could just get that to render. To no avail.



    Before summarizing my question I want to mention that no, I cannot use a QTextEdit. There are specific columns that I need to word wrap, while others I do not want to word wrap. QTableView displays the data exactly as I expect to see it.



    So my question is this:
    Is the QTextDocument rendering through the paint event of a subclassed QStyledItemDelegate the preferred way to handle this? If not, how else should I deal with it?



    If so, how do I make it work as I expect? What is wrong with the code that I have?



    Bonus 2 parter question
    Once I can render, how can I actually leverage the QTextDocument API to highlight only specific pieces, given that the list of model indexes that contain the text to be highlighted is discovered in a completely different function and at a different time than when the paint function executes?



    Update 0
    Using the QTextDocument API to make multiple selections is looking like an impossible feat. The column that I would be drawing contents to needs to word wrap and expand.



    From what I can tell, I calling drawContents manually means handling resizing, word wrapping, and many other things manually which is not a path I want to go down if that is indeed the case.



    I've got another way in mind, I will update if it works.



    Update 1
    I have accomplished what I want in another way. Unfortunately, I cannot use Qt for what I want. Qt's Model/View system is entirely too inefficient and getting it to do what I need causes it to be extremely and unacceptably slow. How did I accomplish the highlighting?



    I will describe in an answer. If nobody gives me a better answer, I will pick mine as the best.










    share|improve this question



























      1












      1








      1


      1





      First let me explain what I'm trying to achieve:



      In your browser, hit Ctrl + f and type "q". The result of that operation is what I'm trying to achieve. It seems like this should be a solved problem, but despite the many hours I've spent researching, reading documentation, and asking around in the Qt IRC, I'm still stuck. Maybe somebody here will be able to give me a hand.



      The following Qt classes are what I'm currently dealing with, in case you want to brush up a bit.:
      Qt::DisplayRole
      QModelIndex::data
      QAbstractItemView::setDelegate
      QTextEdit::setExtraSelections (only as a reference)
      QAbstractDocumentLayout::Selection
      QTextDocument::drawContents
      QStyledItemDelegate::paint
      QStyleOptionViewItem
      QStyleOption::rect
      QTableView
      QAbstractItemModel::match
      Learn to Model/View Program with Qt



      So now, let me explain how I have things set up, and what the results of my research and interactions with the Qt IRC has lead me to believe I should do.



      I am using a QStandardItemModel along with a QTableView. Each row that gets appended to the QStandardItemModel has several columns. As we know, each of these columns is represented in the QStandardItemModel as a QModelIndex. We can pull its displayed text by accessing its data(Qt::DisplayRole).



      Conveniently, given a search string, QStandardItemModel::match will return a QModelIndexList of every QModelIndex that, well, matched in the column. Of course, if you have several columns in every row, you would need to preform this match over each column, but I can worry about performance here later.



      So cool, that problem is solved. We have our list of every QModelIndex that had a matching string. Now, what I want to do is highlight that string in each column. For example:



      Search string: "col"

      This is a column | This is aColumn | This is aColumn | This is a co



      Parts that would appear highlighted are what I have in bold above. In order to achieve this, I knew from reading the Model/View docs that I needed to subclass a QStyledItemDelegate and reimplement its paint function. So I started there.



      The next problem to solve would be, how in the world to select a specific piece of text in the DisplayRole and only highlight it? You can't use Qt::BackgroundRole, that would set the entire index's background color. Enter QTextDocument.



      I still need to do more digging to see how exactly I can implement that behavior, but from what I was told in Qt IRC, QTextEdit has a function called setExtraSelections. Looking at how that is implemented, it leverages QAbstractTextDocumentLayout::Selection and various cursor functions available to me in QTextDocument.



      However, sadly I cannot even begin to solve that problem, because the first step is to actually ensure that I can render a QTextDocument to the QTableView with my reimplemented custom delegate paint function. This is where I'm stuck currently. I've seen this post, here and the one it references:
      Similar question that doesn't solve my issue



      Its not exactly what I was looking for, but I figured it would help me at least get something rendering. It looks though like in his code, he's drawing the control (which is literally what QStyledItemDelegate does), and then tries to paint his QTextDocument over it. Maybe that's not what that is doing but it sure looks like it.



      In any case, when I tried that, it looked like the QTextDocument had no effect. If I commented out the drawControl call, then no text would be rendered at all. Here is my code for that:



      void CustomDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 
      {
      QStyleOptionViewItem opt = option;
      initStyleOption(&opt, index);

      if (index.column() == contentColumn)
      {
      painter->save();

      QTextDocument contentDocument;
      //opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);

      opt.text = "Things";
      painter->setBrush(QBrush(Qt::darkCyan));
      contentDocument.drawContents(painter, opt.rect);

      painter->restore();
      }
      else
      {
      QStyledItemDelegate::paint(painter, option, index);
      }
      }


      You can see I just typed text "Things" to see if I could just get that to render. To no avail.



      Before summarizing my question I want to mention that no, I cannot use a QTextEdit. There are specific columns that I need to word wrap, while others I do not want to word wrap. QTableView displays the data exactly as I expect to see it.



      So my question is this:
      Is the QTextDocument rendering through the paint event of a subclassed QStyledItemDelegate the preferred way to handle this? If not, how else should I deal with it?



      If so, how do I make it work as I expect? What is wrong with the code that I have?



      Bonus 2 parter question
      Once I can render, how can I actually leverage the QTextDocument API to highlight only specific pieces, given that the list of model indexes that contain the text to be highlighted is discovered in a completely different function and at a different time than when the paint function executes?



      Update 0
      Using the QTextDocument API to make multiple selections is looking like an impossible feat. The column that I would be drawing contents to needs to word wrap and expand.



      From what I can tell, I calling drawContents manually means handling resizing, word wrapping, and many other things manually which is not a path I want to go down if that is indeed the case.



      I've got another way in mind, I will update if it works.



      Update 1
      I have accomplished what I want in another way. Unfortunately, I cannot use Qt for what I want. Qt's Model/View system is entirely too inefficient and getting it to do what I need causes it to be extremely and unacceptably slow. How did I accomplish the highlighting?



      I will describe in an answer. If nobody gives me a better answer, I will pick mine as the best.










      share|improve this question















      First let me explain what I'm trying to achieve:



      In your browser, hit Ctrl + f and type "q". The result of that operation is what I'm trying to achieve. It seems like this should be a solved problem, but despite the many hours I've spent researching, reading documentation, and asking around in the Qt IRC, I'm still stuck. Maybe somebody here will be able to give me a hand.



      The following Qt classes are what I'm currently dealing with, in case you want to brush up a bit.:
      Qt::DisplayRole
      QModelIndex::data
      QAbstractItemView::setDelegate
      QTextEdit::setExtraSelections (only as a reference)
      QAbstractDocumentLayout::Selection
      QTextDocument::drawContents
      QStyledItemDelegate::paint
      QStyleOptionViewItem
      QStyleOption::rect
      QTableView
      QAbstractItemModel::match
      Learn to Model/View Program with Qt



      So now, let me explain how I have things set up, and what the results of my research and interactions with the Qt IRC has lead me to believe I should do.



      I am using a QStandardItemModel along with a QTableView. Each row that gets appended to the QStandardItemModel has several columns. As we know, each of these columns is represented in the QStandardItemModel as a QModelIndex. We can pull its displayed text by accessing its data(Qt::DisplayRole).



      Conveniently, given a search string, QStandardItemModel::match will return a QModelIndexList of every QModelIndex that, well, matched in the column. Of course, if you have several columns in every row, you would need to preform this match over each column, but I can worry about performance here later.



      So cool, that problem is solved. We have our list of every QModelIndex that had a matching string. Now, what I want to do is highlight that string in each column. For example:



      Search string: "col"

      This is a column | This is aColumn | This is aColumn | This is a co



      Parts that would appear highlighted are what I have in bold above. In order to achieve this, I knew from reading the Model/View docs that I needed to subclass a QStyledItemDelegate and reimplement its paint function. So I started there.



      The next problem to solve would be, how in the world to select a specific piece of text in the DisplayRole and only highlight it? You can't use Qt::BackgroundRole, that would set the entire index's background color. Enter QTextDocument.



      I still need to do more digging to see how exactly I can implement that behavior, but from what I was told in Qt IRC, QTextEdit has a function called setExtraSelections. Looking at how that is implemented, it leverages QAbstractTextDocumentLayout::Selection and various cursor functions available to me in QTextDocument.



      However, sadly I cannot even begin to solve that problem, because the first step is to actually ensure that I can render a QTextDocument to the QTableView with my reimplemented custom delegate paint function. This is where I'm stuck currently. I've seen this post, here and the one it references:
      Similar question that doesn't solve my issue



      Its not exactly what I was looking for, but I figured it would help me at least get something rendering. It looks though like in his code, he's drawing the control (which is literally what QStyledItemDelegate does), and then tries to paint his QTextDocument over it. Maybe that's not what that is doing but it sure looks like it.



      In any case, when I tried that, it looked like the QTextDocument had no effect. If I commented out the drawControl call, then no text would be rendered at all. Here is my code for that:



      void CustomDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 
      {
      QStyleOptionViewItem opt = option;
      initStyleOption(&opt, index);

      if (index.column() == contentColumn)
      {
      painter->save();

      QTextDocument contentDocument;
      //opt.widget->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);

      opt.text = "Things";
      painter->setBrush(QBrush(Qt::darkCyan));
      contentDocument.drawContents(painter, opt.rect);

      painter->restore();
      }
      else
      {
      QStyledItemDelegate::paint(painter, option, index);
      }
      }


      You can see I just typed text "Things" to see if I could just get that to render. To no avail.



      Before summarizing my question I want to mention that no, I cannot use a QTextEdit. There are specific columns that I need to word wrap, while others I do not want to word wrap. QTableView displays the data exactly as I expect to see it.



      So my question is this:
      Is the QTextDocument rendering through the paint event of a subclassed QStyledItemDelegate the preferred way to handle this? If not, how else should I deal with it?



      If so, how do I make it work as I expect? What is wrong with the code that I have?



      Bonus 2 parter question
      Once I can render, how can I actually leverage the QTextDocument API to highlight only specific pieces, given that the list of model indexes that contain the text to be highlighted is discovered in a completely different function and at a different time than when the paint function executes?



      Update 0
      Using the QTextDocument API to make multiple selections is looking like an impossible feat. The column that I would be drawing contents to needs to word wrap and expand.



      From what I can tell, I calling drawContents manually means handling resizing, word wrapping, and many other things manually which is not a path I want to go down if that is indeed the case.



      I've got another way in mind, I will update if it works.



      Update 1
      I have accomplished what I want in another way. Unfortunately, I cannot use Qt for what I want. Qt's Model/View system is entirely too inefficient and getting it to do what I need causes it to be extremely and unacceptably slow. How did I accomplish the highlighting?



      I will describe in an answer. If nobody gives me a better answer, I will pick mine as the best.







      c++ qt search






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 23 '17 at 11:51









      Community

      11




      11










      asked May 29 '15 at 3:56









      Josh Sanders

      382515




      382515
























          3 Answers
          3






          active

          oldest

          votes


















          0














          I believe what you need to do here is override this method in your QItemDelegate subclass:



          void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const


          The problem with QItemDelegate's implementation of this method is at the end, where we see this method call (it's actually called in two places, but since they are identical calls I'm just showing it once):



          d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);


          It's that third argument that you'd want to change -- in QItemDelegate::drawDisplay(), it's hard-coded to always be an empty QVector, which means that all of the characters in the drawn text-string will be always have the same formatting. If you could somehow get it to be called with a QVector<QTextLayout::FormatRange> that contained your per-substring formatting preferences instead, you would get the effect you want.



          Of course, the devil is in the details. If you don't mind hacking the Qt source code to fit your purpose, you could do that; but that would be an ugly solution since it would mean your program would no longer work correctly when compiled with a non-customized Qt release (and you'd have to re-patch every time you upgraded to a new Qt release).



          So instead you'd probably want to start by copying the contents of the QItemDelegate::drawDisplay() method over to your subclass's method, then modifying the copied version as necessary. (Of course that has its own problems, since QItemDelegate::drawDisplay() references private member variables that your subclass doesn't have access to, but you can probably work around those. You might also want to check with the Qt people to see if there are any legal problems with copying out a method body like that; I'm not sure if there are or not. If you're not comfortable with copying it, you can at least look at it for inspiration about the sorts of things your implementation of drawDisplay() will probably also need to do)






          share|improve this answer























          • I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
            – Josh Sanders
            May 29 '15 at 4:40










          • Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
            – Jeremy Friesner
            May 29 '15 at 5:09










          • Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
            – Josh Sanders
            May 29 '15 at 17:27










          • Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
            – Josh Sanders
            May 29 '15 at 17:52



















          0














          Essentially, I found that getting the QTableView to display rich text was a common use case that people on forums were trying to accomplish. Since this was a solved problem, I tried to see how I could leverage HTML.



          First, I set up my custom delegate to handle rich text. Then I had an algorithm that went a bit like this:



             clear all html tags from the display role in every row of the specified column

          for every row in the specified column
          populate a list of QModelIndex with matching text in the Display Role

          for every QModelIndex with matching text in the display role
          while there is another occurance of the matching string in the display role
          inject html highlight (span) around the matching word


          This is, of course, extremely, painfully, unacceptably slow. It does work though, has the exact same effect as hitting ctrl + f. But, I cannot use it. Its a shame that Qt doesn't support something as basic as this. Oh well.






          share|improve this answer





























            0














            My approach to that problem was to use the paint function from the delegate to render one or several positions from a cursor in a QTextDocument.



            void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
            {
            if ( !index.isValid() )
            return;


            // Higlight some text
            {
            QString dataHighlight QString("col"); // The text to highlight.
            QString value = index.model()->data(index, Qt::DisplayRole).toString();

            QTextDocument *doc = new QTextDocument(value);
            QTextCharFormat selection;

            int position = 0;
            QTextCursor cur;

            // We have to iterate through the QTextDocument to find ALL matching places
            do {

            cur = doc->find(dataHighlight,position);
            cur.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
            cur.selectionStart();
            cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
            cur.selectionEnd();
            position = cur.position();
            selection.setBackground(Qt::yellow);
            cur.setCharFormat(selection);

            } while (!cur.isNull());

            painter->save();
            painter->translate(option.rect.x(), option.rect.y());
            doc->drawContents(painter);
            painter->restore();

            delete doc;
            }
            }





            share|improve this answer





















              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f30520865%2fhighlight-text-that-matches-a-search-string-in-qt5%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              0














              I believe what you need to do here is override this method in your QItemDelegate subclass:



              void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const


              The problem with QItemDelegate's implementation of this method is at the end, where we see this method call (it's actually called in two places, but since they are identical calls I'm just showing it once):



              d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);


              It's that third argument that you'd want to change -- in QItemDelegate::drawDisplay(), it's hard-coded to always be an empty QVector, which means that all of the characters in the drawn text-string will be always have the same formatting. If you could somehow get it to be called with a QVector<QTextLayout::FormatRange> that contained your per-substring formatting preferences instead, you would get the effect you want.



              Of course, the devil is in the details. If you don't mind hacking the Qt source code to fit your purpose, you could do that; but that would be an ugly solution since it would mean your program would no longer work correctly when compiled with a non-customized Qt release (and you'd have to re-patch every time you upgraded to a new Qt release).



              So instead you'd probably want to start by copying the contents of the QItemDelegate::drawDisplay() method over to your subclass's method, then modifying the copied version as necessary. (Of course that has its own problems, since QItemDelegate::drawDisplay() references private member variables that your subclass doesn't have access to, but you can probably work around those. You might also want to check with the Qt people to see if there are any legal problems with copying out a method body like that; I'm not sure if there are or not. If you're not comfortable with copying it, you can at least look at it for inspiration about the sorts of things your implementation of drawDisplay() will probably also need to do)






              share|improve this answer























              • I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
                – Josh Sanders
                May 29 '15 at 4:40










              • Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
                – Jeremy Friesner
                May 29 '15 at 5:09










              • Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
                – Josh Sanders
                May 29 '15 at 17:27










              • Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
                – Josh Sanders
                May 29 '15 at 17:52
















              0














              I believe what you need to do here is override this method in your QItemDelegate subclass:



              void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const


              The problem with QItemDelegate's implementation of this method is at the end, where we see this method call (it's actually called in two places, but since they are identical calls I'm just showing it once):



              d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);


              It's that third argument that you'd want to change -- in QItemDelegate::drawDisplay(), it's hard-coded to always be an empty QVector, which means that all of the characters in the drawn text-string will be always have the same formatting. If you could somehow get it to be called with a QVector<QTextLayout::FormatRange> that contained your per-substring formatting preferences instead, you would get the effect you want.



              Of course, the devil is in the details. If you don't mind hacking the Qt source code to fit your purpose, you could do that; but that would be an ugly solution since it would mean your program would no longer work correctly when compiled with a non-customized Qt release (and you'd have to re-patch every time you upgraded to a new Qt release).



              So instead you'd probably want to start by copying the contents of the QItemDelegate::drawDisplay() method over to your subclass's method, then modifying the copied version as necessary. (Of course that has its own problems, since QItemDelegate::drawDisplay() references private member variables that your subclass doesn't have access to, but you can probably work around those. You might also want to check with the Qt people to see if there are any legal problems with copying out a method body like that; I'm not sure if there are or not. If you're not comfortable with copying it, you can at least look at it for inspiration about the sorts of things your implementation of drawDisplay() will probably also need to do)






              share|improve this answer























              • I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
                – Josh Sanders
                May 29 '15 at 4:40










              • Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
                – Jeremy Friesner
                May 29 '15 at 5:09










              • Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
                – Josh Sanders
                May 29 '15 at 17:27










              • Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
                – Josh Sanders
                May 29 '15 at 17:52














              0












              0








              0






              I believe what you need to do here is override this method in your QItemDelegate subclass:



              void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const


              The problem with QItemDelegate's implementation of this method is at the end, where we see this method call (it's actually called in two places, but since they are identical calls I'm just showing it once):



              d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);


              It's that third argument that you'd want to change -- in QItemDelegate::drawDisplay(), it's hard-coded to always be an empty QVector, which means that all of the characters in the drawn text-string will be always have the same formatting. If you could somehow get it to be called with a QVector<QTextLayout::FormatRange> that contained your per-substring formatting preferences instead, you would get the effect you want.



              Of course, the devil is in the details. If you don't mind hacking the Qt source code to fit your purpose, you could do that; but that would be an ugly solution since it would mean your program would no longer work correctly when compiled with a non-customized Qt release (and you'd have to re-patch every time you upgraded to a new Qt release).



              So instead you'd probably want to start by copying the contents of the QItemDelegate::drawDisplay() method over to your subclass's method, then modifying the copied version as necessary. (Of course that has its own problems, since QItemDelegate::drawDisplay() references private member variables that your subclass doesn't have access to, but you can probably work around those. You might also want to check with the Qt people to see if there are any legal problems with copying out a method body like that; I'm not sure if there are or not. If you're not comfortable with copying it, you can at least look at it for inspiration about the sorts of things your implementation of drawDisplay() will probably also need to do)






              share|improve this answer














              I believe what you need to do here is override this method in your QItemDelegate subclass:



              void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const


              The problem with QItemDelegate's implementation of this method is at the end, where we see this method call (it's actually called in two places, but since they are identical calls I'm just showing it once):



              d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);


              It's that third argument that you'd want to change -- in QItemDelegate::drawDisplay(), it's hard-coded to always be an empty QVector, which means that all of the characters in the drawn text-string will be always have the same formatting. If you could somehow get it to be called with a QVector<QTextLayout::FormatRange> that contained your per-substring formatting preferences instead, you would get the effect you want.



              Of course, the devil is in the details. If you don't mind hacking the Qt source code to fit your purpose, you could do that; but that would be an ugly solution since it would mean your program would no longer work correctly when compiled with a non-customized Qt release (and you'd have to re-patch every time you upgraded to a new Qt release).



              So instead you'd probably want to start by copying the contents of the QItemDelegate::drawDisplay() method over to your subclass's method, then modifying the copied version as necessary. (Of course that has its own problems, since QItemDelegate::drawDisplay() references private member variables that your subclass doesn't have access to, but you can probably work around those. You might also want to check with the Qt people to see if there are any legal problems with copying out a method body like that; I'm not sure if there are or not. If you're not comfortable with copying it, you can at least look at it for inspiration about the sorts of things your implementation of drawDisplay() will probably also need to do)







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited May 29 '15 at 4:27

























              answered May 29 '15 at 4:21









              Jeremy Friesner

              38.2k1078159




              38.2k1078159












              • I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
                – Josh Sanders
                May 29 '15 at 4:40










              • Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
                – Jeremy Friesner
                May 29 '15 at 5:09










              • Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
                – Josh Sanders
                May 29 '15 at 17:27










              • Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
                – Josh Sanders
                May 29 '15 at 17:52


















              • I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
                – Josh Sanders
                May 29 '15 at 4:40










              • Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
                – Jeremy Friesner
                May 29 '15 at 5:09










              • Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
                – Josh Sanders
                May 29 '15 at 17:27










              • Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
                – Josh Sanders
                May 29 '15 at 17:52
















              I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
              – Josh Sanders
              May 29 '15 at 4:40




              I see, thank you so much for taking the time to reply! Sorry, I should have been more clear about what my CustomDelegate is a subclass of. The docs mention that when subclassing for a custom delegate, one should use QStyledItemDelegate, so that is what I am subclassing. QStyledItemDelegate, and its base class QAbstractitemDelegate, do not have the function drawDisplay. Though, I'm searching both for the same defect but I haven't found the equivalent to what you're describing in either one. It doesn't seem that a call to layout->draw is made.
              – Josh Sanders
              May 29 '15 at 4:40












              Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
              – Jeremy Friesner
              May 29 '15 at 5:09




              Hmm, it looks like QStyledItemDelegate::paint() calls drawControl(Style::CE_ItemViewItem) to draw the text (amongst other things). QCommonStyle::drawControl(CE_ItemViewItem) then calls viewItemDrawText(), which then makes a call to p->drawText() for each line of text in the cell. Assuming I'm following the right code path, I don't think there's an easy way to make that drawText() call draw different letters in different colors. For QStyledItemDelegate you'd probably just have to override QStyledItemDelegate::paint() to call QTextLayout::draw() directly, instead.
              – Jeremy Friesner
              May 29 '15 at 5:09












              Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
              – Josh Sanders
              May 29 '15 at 17:27




              Yes, that is one approach I have seen. Though doing it that way, I'd render the original text and then overlay highlighted text on top of it. Besides being inefficient, it seems like a hack. QStyledItemDelegate::paint does indeed call QStyle::drawControl, but since I'm reimplementing that function, I don't necessarily need to use QStyle::drawControl at all. In fact, I would assume that doing so wouldn't give the desired results since QStyledItemDelegate is used by QTableView by default. Maybe something else in QStyle could be leveraged? But this is why I tried QTextDocument::drawContent.
              – Josh Sanders
              May 29 '15 at 17:27












              Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
              – Josh Sanders
              May 29 '15 at 17:52




              Also, I should point out that the goal is not to draw different letters in different colors. If you hit Crtl+f in your browser and search for things, you will see that the text becomes highlighted rather than its font color changed. This would be equivalent to the Qt::BackgroundRole color. There does not seem to be any way to partially set a backgroundRole, however, using the QTextDocument API, I can programmatically 'select' text and change the highlight color. So I can give the illusion of highlighting by just selecting, as you would if you dragged your mouse cursor over text in an edit box.
              – Josh Sanders
              May 29 '15 at 17:52













              0














              Essentially, I found that getting the QTableView to display rich text was a common use case that people on forums were trying to accomplish. Since this was a solved problem, I tried to see how I could leverage HTML.



              First, I set up my custom delegate to handle rich text. Then I had an algorithm that went a bit like this:



                 clear all html tags from the display role in every row of the specified column

              for every row in the specified column
              populate a list of QModelIndex with matching text in the Display Role

              for every QModelIndex with matching text in the display role
              while there is another occurance of the matching string in the display role
              inject html highlight (span) around the matching word


              This is, of course, extremely, painfully, unacceptably slow. It does work though, has the exact same effect as hitting ctrl + f. But, I cannot use it. Its a shame that Qt doesn't support something as basic as this. Oh well.






              share|improve this answer


























                0














                Essentially, I found that getting the QTableView to display rich text was a common use case that people on forums were trying to accomplish. Since this was a solved problem, I tried to see how I could leverage HTML.



                First, I set up my custom delegate to handle rich text. Then I had an algorithm that went a bit like this:



                   clear all html tags from the display role in every row of the specified column

                for every row in the specified column
                populate a list of QModelIndex with matching text in the Display Role

                for every QModelIndex with matching text in the display role
                while there is another occurance of the matching string in the display role
                inject html highlight (span) around the matching word


                This is, of course, extremely, painfully, unacceptably slow. It does work though, has the exact same effect as hitting ctrl + f. But, I cannot use it. Its a shame that Qt doesn't support something as basic as this. Oh well.






                share|improve this answer
























                  0












                  0








                  0






                  Essentially, I found that getting the QTableView to display rich text was a common use case that people on forums were trying to accomplish. Since this was a solved problem, I tried to see how I could leverage HTML.



                  First, I set up my custom delegate to handle rich text. Then I had an algorithm that went a bit like this:



                     clear all html tags from the display role in every row of the specified column

                  for every row in the specified column
                  populate a list of QModelIndex with matching text in the Display Role

                  for every QModelIndex with matching text in the display role
                  while there is another occurance of the matching string in the display role
                  inject html highlight (span) around the matching word


                  This is, of course, extremely, painfully, unacceptably slow. It does work though, has the exact same effect as hitting ctrl + f. But, I cannot use it. Its a shame that Qt doesn't support something as basic as this. Oh well.






                  share|improve this answer












                  Essentially, I found that getting the QTableView to display rich text was a common use case that people on forums were trying to accomplish. Since this was a solved problem, I tried to see how I could leverage HTML.



                  First, I set up my custom delegate to handle rich text. Then I had an algorithm that went a bit like this:



                     clear all html tags from the display role in every row of the specified column

                  for every row in the specified column
                  populate a list of QModelIndex with matching text in the Display Role

                  for every QModelIndex with matching text in the display role
                  while there is another occurance of the matching string in the display role
                  inject html highlight (span) around the matching word


                  This is, of course, extremely, painfully, unacceptably slow. It does work though, has the exact same effect as hitting ctrl + f. But, I cannot use it. Its a shame that Qt doesn't support something as basic as this. Oh well.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered May 30 '15 at 3:43









                  Josh Sanders

                  382515




                  382515























                      0














                      My approach to that problem was to use the paint function from the delegate to render one or several positions from a cursor in a QTextDocument.



                      void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                      {
                      if ( !index.isValid() )
                      return;


                      // Higlight some text
                      {
                      QString dataHighlight QString("col"); // The text to highlight.
                      QString value = index.model()->data(index, Qt::DisplayRole).toString();

                      QTextDocument *doc = new QTextDocument(value);
                      QTextCharFormat selection;

                      int position = 0;
                      QTextCursor cur;

                      // We have to iterate through the QTextDocument to find ALL matching places
                      do {

                      cur = doc->find(dataHighlight,position);
                      cur.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
                      cur.selectionStart();
                      cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
                      cur.selectionEnd();
                      position = cur.position();
                      selection.setBackground(Qt::yellow);
                      cur.setCharFormat(selection);

                      } while (!cur.isNull());

                      painter->save();
                      painter->translate(option.rect.x(), option.rect.y());
                      doc->drawContents(painter);
                      painter->restore();

                      delete doc;
                      }
                      }





                      share|improve this answer


























                        0














                        My approach to that problem was to use the paint function from the delegate to render one or several positions from a cursor in a QTextDocument.



                        void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                        {
                        if ( !index.isValid() )
                        return;


                        // Higlight some text
                        {
                        QString dataHighlight QString("col"); // The text to highlight.
                        QString value = index.model()->data(index, Qt::DisplayRole).toString();

                        QTextDocument *doc = new QTextDocument(value);
                        QTextCharFormat selection;

                        int position = 0;
                        QTextCursor cur;

                        // We have to iterate through the QTextDocument to find ALL matching places
                        do {

                        cur = doc->find(dataHighlight,position);
                        cur.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
                        cur.selectionStart();
                        cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
                        cur.selectionEnd();
                        position = cur.position();
                        selection.setBackground(Qt::yellow);
                        cur.setCharFormat(selection);

                        } while (!cur.isNull());

                        painter->save();
                        painter->translate(option.rect.x(), option.rect.y());
                        doc->drawContents(painter);
                        painter->restore();

                        delete doc;
                        }
                        }





                        share|improve this answer
























                          0












                          0








                          0






                          My approach to that problem was to use the paint function from the delegate to render one or several positions from a cursor in a QTextDocument.



                          void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                          {
                          if ( !index.isValid() )
                          return;


                          // Higlight some text
                          {
                          QString dataHighlight QString("col"); // The text to highlight.
                          QString value = index.model()->data(index, Qt::DisplayRole).toString();

                          QTextDocument *doc = new QTextDocument(value);
                          QTextCharFormat selection;

                          int position = 0;
                          QTextCursor cur;

                          // We have to iterate through the QTextDocument to find ALL matching places
                          do {

                          cur = doc->find(dataHighlight,position);
                          cur.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
                          cur.selectionStart();
                          cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
                          cur.selectionEnd();
                          position = cur.position();
                          selection.setBackground(Qt::yellow);
                          cur.setCharFormat(selection);

                          } while (!cur.isNull());

                          painter->save();
                          painter->translate(option.rect.x(), option.rect.y());
                          doc->drawContents(painter);
                          painter->restore();

                          delete doc;
                          }
                          }





                          share|improve this answer












                          My approach to that problem was to use the paint function from the delegate to render one or several positions from a cursor in a QTextDocument.



                          void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                          {
                          if ( !index.isValid() )
                          return;


                          // Higlight some text
                          {
                          QString dataHighlight QString("col"); // The text to highlight.
                          QString value = index.model()->data(index, Qt::DisplayRole).toString();

                          QTextDocument *doc = new QTextDocument(value);
                          QTextCharFormat selection;

                          int position = 0;
                          QTextCursor cur;

                          // We have to iterate through the QTextDocument to find ALL matching places
                          do {

                          cur = doc->find(dataHighlight,position);
                          cur.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
                          cur.selectionStart();
                          cur.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
                          cur.selectionEnd();
                          position = cur.position();
                          selection.setBackground(Qt::yellow);
                          cur.setCharFormat(selection);

                          } while (!cur.isNull());

                          painter->save();
                          painter->translate(option.rect.x(), option.rect.y());
                          doc->drawContents(painter);
                          painter->restore();

                          delete doc;
                          }
                          }






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 21 at 8:29









                          lolo67

                          12615




                          12615






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f30520865%2fhighlight-text-that-matches-a-search-string-in-qt5%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              404 Error Contact Form 7 ajax form submitting

                              How to know if a Active Directory user can login interactively

                              TypeError: fit_transform() missing 1 required positional argument: 'X'