-4

I need some help on how to highlight a specific word in a QTableWidget cell. For example in this image. Let's say I want to highlight the word "James" color green. There are words "James" that are full words and those who aren't so still I needed them to be highlighted

enter image description here

Now take note I have already searched about this and I found this similar solution and I studied on it (It's actually cool!). How to highlight a words in QTableWidget from a Searchlist. But seems that there are some parts that are different on my goal and quite complicated and mine is very very simple. Just like that when the table has its data it will highlight a chosen word, I believe this can be done easily with in a shorter code or much simpler way to implement the coloring of a word. Please I need some help I find this really awesome and looking forward to accomplish this.

Let's take this sample code with a simple PYQT5 QTableWidget for a test.

import sys 
from PyQt5.QtWidgets import * 
                    
   
#Main Window 
class App(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.title = 'PyQt5 - QTableWidget'
        self.left = 0
        self.top = 0
        self.width = 300
        self.height = 200
   
        self.setWindowTitle(self.title) 
        self.setGeometry(self.left, self.top, self.width, self.height) 
   
        self.createTable() 
   
        self.layout = QVBoxLayout() 
        self.layout.addWidget(self.tableWidget) 
        self.setLayout(self.layout) 
   
        #Show window 
        self.show() 
   
    #Create table 
    def createTable(self): 
        self.tableWidget = QTableWidget() 
  
        #Row count 
        self.tableWidget.setRowCount(4)  
  
        #Column count 
        self.tableWidget.setColumnCount(2)   
  
        self.tableWidget.setItem(0,0, QTableWidgetItem("Name")) 
        self.tableWidget.setItem(0,1, QTableWidgetItem("City")) 
        self.tableWidget.setItem(1,0, QTableWidgetItem("Lebron James")) 
        self.tableWidget.setItem(1,1, QTableWidgetItem("King James")) 
        self.tableWidget.setItem(2,0, QTableWidgetItem("KingJames")) 
        self.tableWidget.setItem(2,1, QTableWidgetItem("Champions")) 
        self.tableWidget.setItem(3,0, QTableWidgetItem("World")) 
        self.tableWidget.setItem(3,1, QTableWidgetItem("2020")) 
   
        #Table will fit the screen horizontally 
        self.tableWidget.horizontalHeader().setStretchLastSection(True) 
        self.tableWidget.horizontalHeader().setSectionResizeMode( 
            QHeaderView.Stretch) 
   
if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    ex = App() 
    sys.exit(app.exec_()) 
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Ice Bear
  • 2,676
  • 1
  • 8
  • 24
  • What should be the difference between your case and that of the other question? – musicamante Oct 07 '20 at 09:31
  • I was wondering if there could be a simpler way to do it... since I'm going to modify it and I have some conditions that I need to consider for other words as well... With that I would be able to implement some of my own... I'm still trying right now based on the other answer but I hope there would be a another one. – Ice Bear Oct 07 '20 at 09:35
  • May I post an answer with this question? – Ice Bear Oct 07 '20 at 10:48
  • Sure, as long as it is a valid answer to your question. – musicamante Oct 07 '20 at 11:50

1 Answers1

0

Studying the code from the similar answer was quite challenging but I managed to figure it out and here is the code. The only thing I am still curious about is could there be a simpler way to do this since I've been studying the code and thought of what is really happening and really all these things necessary. But anyways if there's not I will continue to implement the solution from this answer. Thank you!

import sys, re
from PyQt5.QtWidgets import * 
from PyQt5 import QtCore, QtGui, QtWidgets
   
#Main Window 
class App(QWidget): 
    def __init__(self): 
        super().__init__() 
        self.title = 'PyQt5 - QTableWidget'
        self.left = 0
        self.top = 0
        self.width = 300
        self.height = 200
   
        self.setWindowTitle(self.title) 
        self.setGeometry(self.left, self.top, self.width, self.height) 
   
        self.createTable() 
   
        self.layout = QVBoxLayout() 
        self.layout.addWidget(self.tableWidget) 
        self.setLayout(self.layout) 
   
        #Show window 
        self.show() 
   
    #Create table 
    def createTable(self): 
        self.tableWidget = QTableWidget() 
        self._delegate = HighlightDelegate(self.tableWidget)
        self.tableWidget.setItemDelegate(self._delegate)
  
        #Row count 
        self.tableWidget.setRowCount(4)  
  
        #Column count 
        self.tableWidget.setColumnCount(2)   
  
        self.tableWidget.setItem(0,0, QTableWidgetItem("Name")) 
        self.tableWidget.setItem(0,1, QTableWidgetItem("City")) 
        self.tableWidget.setItem(1,0, QTableWidgetItem("Lebron James")) 
        self.tableWidget.setItem(1,1, QTableWidgetItem("King James")) 
        self.tableWidget.setItem(2,0, QTableWidgetItem("KingJames")) 
        self.tableWidget.setItem(2,1, QTableWidgetItem("Champions")) 
        self.tableWidget.setItem(3,0, QTableWidgetItem("World")) 
        self.tableWidget.setItem(3,1, QTableWidgetItem("2020")) 
   
        #Table will fit the screen horizontally 
        self.tableWidget.horizontalHeader().setStretchLastSection(True) 
        self.tableWidget.horizontalHeader().setSectionResizeMode( 
            QHeaderView.Stretch) 

        #Started coloring
        self.on_textChanged()



    def on_textChanged(self, text="James"):
        self._delegate.setFilters(list(set(text.split())))
        self.tableWidget.viewport().update()












class HighlightDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HighlightDelegate, self).__init__(parent)
        self.doc = QtGui.QTextDocument(self)
        self._filters = []

    def paint(self, painter, option, index):
        painter.save()
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        self.doc.setPlainText(options.text)
        self.apply_highlight(options.text)

        
        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)

        the_constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - the_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 apply_highlight(self,text):
        cursor = QtGui.QTextCursor(self.doc)
        cursor.beginEditBlock()
        fmt = QtGui.QTextCharFormat()

        highlight_word = ''.join(self.filters())
        print(text)
        sentence_status = re.search(r'\b'+ highlight_word + r'\b',text,re.IGNORECASE)

        if sentence_status != None:
            fmt.setForeground(QtCore.Qt.darkGreen)
        else:
            fmt.setForeground(QtCore.Qt.red)


        for f in self.filters():
            highlightCursor = QtGui.QTextCursor(self.doc)
            while not highlightCursor.isNull() and not highlightCursor.atEnd():
                highlightCursor = self.doc.find(f, highlightCursor)
                if not highlightCursor.isNull():
                    highlightCursor.mergeCharFormat(fmt)
        cursor.endEditBlock()

    @QtCore.pyqtSlot(list)
    def setFilters(self, filters):
        if self._filters == filters: return
        self._filters = filters

    def filters(self):
        return self._filters



















if __name__ == '__main__': 
    app = QApplication(sys.argv) 
    ex = App() 
    sys.exit(app.exec_()) 
Ice Bear
  • 2,676
  • 1
  • 8
  • 24