1

I use method1 to find some text in qtablewidget rows. method1 :

def FindItem(self):
    items = self.SuraBRS.findItems(
        self.SearchTbox.text(), QtCore.Qt.MatchContains)
    if items:
        results = '\n'.join(
            'row %d column %d' % (item.row() + 1, item.column() + 1)
            for item in items)
    else:
        results = 'Found Nothing'
    print(results)

Now I want to know how to highlight results or change their color.I want to select and highlight that text or character not all of the row or column.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241

1 Answers1

5

To be able to change only a part of the text you must use an HTMLdelegate that I built in this other answer, but it must be modified to avoid changing the html that can be the information and not the text that is desired:

from PyQt5 import QtCore, QtGui, QtWidgets

import random

try:
    from html import escape
except ImportError:
    from cgi import escape

words = [
    "Hello",
    "world",
    "Stack",
    "Overflow",
    "Hello world",
    """<font color="red">Hello world</font>""",
]


class HTMLDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HTMLDelegate, self).__init__(parent)
        self.doc = QtGui.QTextDocument(self)

    def paint(self, painter, option, index):
        substring = index.data(QtCore.Qt.UserRole)
        painter.save()
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        res = ""
        color = QtGui.QColor("orange")
        if substring:
            substrings = options.text.split(substring)
            res = """<font color="{}">{}</font>""".format(
                color.name(QtGui.QColor.HexRgb), substring
            ).join(list(map(escape, substrings)))
        else:
            res = escape(options.text)
        self.doc.setHtml(res)

        options.text = ""
        style = (
            QtWidgets.QApplication.style()
            if options.widget is None
            else options.widget.style()
        )
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
        if option.state & QtWidgets.QStyle.State_Selected:
            ctx.palette.setColor(
                QtGui.QPalette.Text,
                option.palette.color(
                    QtGui.QPalette.Active, QtGui.QPalette.HighlightedText
                ),
            )
        else:
            ctx.palette.setColor(
                QtGui.QPalette.Text,
                option.palette.color(QtGui.QPalette.Active, QtGui.QPalette.Text),
            )

        textRect = style.subElementRect(QtWidgets.QStyle.SE_ItemViewItemText, options)

        if index.column() != 0:
            textRect.adjust(5, 0, 0, 0)

        thefuckyourshitup_constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - thefuckyourshitup_constant
        textRect.setTop(textRect.top() + margin)

        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        self.doc.documentLayout().draw(painter, ctx)

        painter.restore()

    def sizeHint(self, option, index):
        return QSize(self.doc.idealWidth(), self.doc.size().height())


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        hlay = QtWidgets.QHBoxLayout()
        lay = QtWidgets.QVBoxLayout(self)

        self.le = QtWidgets.QLineEdit()
        self.button = QtWidgets.QPushButton("filter")
        self.table = QtWidgets.QTableWidget(5, 5)
        hlay.addWidget(self.le)
        hlay.addWidget(self.button)
        lay.addLayout(hlay)
        lay.addWidget(self.table)
        self.button.clicked.connect(self.find_items)
        self.table.setItemDelegate(HTMLDelegate(self.table))

        for i in range(self.table.rowCount()):
            for j in range(self.table.columnCount()):
                it = QtWidgets.QTableWidgetItem(random.choice(words))
                self.table.setItem(i, j, it)

    def find_items(self):
        text = self.le.text()
        # clear
        allitems = self.table.findItems("", QtCore.Qt.MatchContains)
        selected_items = self.table.findItems(self.le.text(), QtCore.Qt.MatchContains)
        for item in allitems:
            item.setData(QtCore.Qt.UserRole, text if item in selected_items else None)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

enter image description here

PyQt4:

from PyQt4 import QtCore, QtGui
import random

try:
    from html import escape
except ImportError:
    from cgi import escape

words = [
    "Hello",
    "world",
    "Stack",
    "Overflow",
    "Hello world",
    """<font color="red">Hello world</font>""",
]


class HTMLDelegate(QtGui.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HTMLDelegate, self).__init__(parent)
        self.doc = QtGui.QTextDocument(self)

    def paint(self, painter, option, index):
        substring = index.data(QtCore.Qt.UserRole)
        if hasattr(substring, "toPyObject"):
            substring = str(substring.toPyObject())
        painter.save()
        options = QtGui.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        text = index.data()
        if hasattr(text, "toPyObject"):
            text = str(text.toPyObject())
        res = ""
        color = QtGui.QColor("orange")
        if substring:
            substrings = text.split(substring)
            res = """<font color="{}">{}</font>""".format(color.name(), substring).join(
                list(map(escape, substrings))
            )
        else:
            res = escape(text)
        self.doc.setHtml(res)

        options.text = ""
        style = (
            QtGui.QApplication.style()
            # if options.widget is None
            # else options.widget.style()
        )
        style.drawControl(QtGui.QStyle.CE_ItemViewItem, options, painter)

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
        if option.state & QtGui.QStyle.State_Selected:
            ctx.palette.setColor(
                QtGui.QPalette.Text,
                option.palette.color(
                    QtGui.QPalette.Active, QtGui.QPalette.HighlightedText
                ),
            )
        else:
            ctx.palette.setColor(
                QtGui.QPalette.Text,
                option.palette.color(QtGui.QPalette.Active, QtGui.QPalette.Text),
            )

        textRect = (
            options.rect
        )  # style.subElementRect(QtGui.QStyle.SE_ItemViewItemText, options)

        if index.column() != 0:
            textRect.adjust(5, 0, 0, 0)

        thefuckyourshitup_constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - thefuckyourshitup_constant
        textRect.setTop(textRect.top() + margin)

        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        self.doc.documentLayout().draw(painter, ctx)

        painter.restore()

    def sizeHint(self, option, index):
        return QSize(self.doc.idealWidth(), self.doc.size().height())


class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        hlay = QtGui.QHBoxLayout()
        lay = QtGui.QVBoxLayout(self)

        self.le = QtGui.QLineEdit()
        self.button = QtGui.QPushButton("filter")
        self.table = QtGui.QTableWidget(5, 5)
        hlay.addWidget(self.le)
        hlay.addWidget(self.button)
        lay.addLayout(hlay)
        lay.addWidget(self.table)
        self.button.clicked.connect(self.find_items)
        self.table.setItemDelegate(HTMLDelegate(self.table))

        for i in range(self.table.rowCount()):
            for j in range(self.table.columnCount()):
                it = QtGui.QTableWidgetItem(random.choice(words))
                self.table.setItem(i, j, it)

    def find_items(self):
        text = self.le.text()
        # clear
        allitems = self.table.findItems("", QtCore.Qt.MatchContains)
        selected_items = self.table.findItems(self.le.text(), QtCore.Qt.MatchContains)
        for item in allitems:
            item.setData(QtCore.Qt.UserRole, text if item in selected_items else None)


if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • It select the whole cell – Maziar Parsijani Jul 31 '18 at 14:22
  • I think you misunderstand the question – Maziar Parsijani Jul 31 '18 at 14:26
  • try to select or highlight "He" in all of your cell not the cell background. – Maziar Parsijani Jul 31 '18 at 14:27
  • I was mentioned NOT THE WHOLE CELL OR ROW isn't that clear – Maziar Parsijani Jul 31 '18 at 14:34
  • if you don't want to accept it then read my first comment .There I told you. – Maziar Parsijani Jul 31 '18 at 14:39
  • Hi eyllanesc .I checked that was use full ,But would You please explain more here.I knew that I have to change data like this but I want to know that if there are other possibilities to use the widget signals and functions. – Maziar Parsijani Aug 02 '18 at 06:30
  • @MaziarParsijani I do not understand, why do you want signals? – eyllanesc Aug 02 '18 at 06:31
  • @MaziarParsijani Qt implements the MVC pattern: http://doc.qt.io/qt-5/model-view-programming.html , where there is a model (the information), a view (QTableWidget) and the controller that is the logic. In addition to the basics, a delegate is implemented to customize the view, and that is what I have used, on the other hand HTML allows us to change the color of the font in a simple way. The advantage is simplicity, I do not think you'll find another solution simpler than this. – eyllanesc Aug 02 '18 at 06:36
  • @ eyllanesc . I did a lot of works in it but as you said it changed my table because of Arabic text format.Do you have any suggestion? – Maziar Parsijani Aug 03 '18 at 11:30
  • @eyllanesc, Its works fine. .How to convert this into case insensitive. – Kumar Jun 01 '21 at 17:35