0

i need help changing the color of one word in my QTableView.

What i need to do is: when i open the csv file in my table, now i have sentences/words in my columns~rows and i need to color some words, like:

Here you can see my program with my csv. https://i.stack.imgur.com/NwO1C.jpg

Example: In the [3][0] ( 4 row, 1 column) i have the word "filme" as u can see in my image.

I want to color this word, and if exists the same word, in the [3][2] ( 4 row, 3 column) i want to color this word too.

Here is my full code:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sip
sip.setapi('QVariant', 2)
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import csv


try:
    _fromUtf8 = QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s:s



class MyWindow(QWidget):
def __init__(self, fileName, parent=None):
    super(MyWindow, self).__init__(parent)
    self.fileName = fileName

    self.model = QStandardItemModel(self)

    self.tableView = QTableView(self)
    self.tableView.setModel(self.model)
    self.tableView.horizontalHeader().setStretchLastSection(True)

    self.pushButtonLoad = QPushButton(self)
    self.pushButtonLoad.setText("Load Csv File!")
    self.pushButtonLoad.clicked.connect(self.on_pushButtonLoad_clicked)

    self.pushButtonWrite = QPushButton(self)
    self.pushButtonWrite.setText("Write Csv File!")
    self.pushButtonWrite.setStyleSheet('color:red;background-color:rgb(155, 255, 153);border:1px solid purple;')
    self.pushButtonWrite.clicked.connect(self.on_pushButtonWrite_clicked)

    self.layoutVertical = QVBoxLayout(self)
    self.layoutVertical.addWidget(self.tableView)
    self.layoutVertical.addWidget(self.pushButtonLoad)
    self.layoutVertical.addWidget(self.pushButtonWrite)


def loadCsv(self, fileName):
    with open(fileName, "rb") as fileInput:
        for row in csv.reader(fileInput):    
            items = [
                QStandardItem(field.decode('utf8'))
                for field in row
            ]
            self.model.appendRow(items)
            self.tableView.resizeRowsToContents()
            self.model.setHeaderData(0, Qt.Horizontal, "Feature")
            self.model.setHeaderData(1, Qt.Horizontal, "Polarity(-1,0,1)")
            self.model.setHeaderData(2, Qt.Horizontal, "texto")
            self.tableView.setColumnWidth(2,1000)
            self.tableView.resizeRowsToContents() 

def writeCsv(self, fileName):
    with open(fileName, "w") as fileOutput:
        writer = csv.writer(fileOutput)
        for rowNumber in range(self.model.rowCount()):
            fields = [
                self.model.data(
                    self.model.index(rowNumber, columnNumber),
                    Qt.DisplayRole
                )
                for columnNumber in range(self.model.columnCount())
            ]
            writer.writerow(fields)
@pyqtSlot()
def on_pushButtonWrite_clicked(self):
    self.writeCsv(self.fileName)

@pyqtSlot()
def on_pushButtonLoad_clicked(self):
    self.loadCsv(self.fileName)

if __name__ == "__main__":
import sys

app = QApplication(sys.argv)
app.setApplicationName('MyWindow')

main = MyWindow("marcoteste.csv")  

main.show()

sys.exit(app.exec_())
Marco
  • 339
  • 2
  • 11
  • 20

2 Answers2

0

there are actually two method, as I know

the first one is just like Oleg said, use delegates, but my implement are a little bit stupid, here is the pesudo code

self.table = QTableView()
self.model = QStandItemModel()
self.table.setMode(model)
self.table.pressed.connect(self.detectWord)

def detectWord(self):
    self.to_color = []
    for row in range(self.model.rowCount()):
        for column in range(self.model.colunCount()):
            raw = self.model.data(self.model.index(row, column), Qt.DisplayRole)
            # needs decode, it's QString/utf-16 by default
            if 'word' in codecs.decode(raw.toString(), 'utf-16'):
                self.to_color.append([row, column])
                
    # apply delegate
    self.table.setItemDelegate(ColorColumn(self.to_color, self)

class ColorColumn(QItemDelegate):
    def __init__(self, to_color, parent = None):
        self.to_color = to_color
        
    def paint(self, painter, option, index):
        masked = False
        for pos in self.to_delete:
            if index.row() == pos[0] and index.column == pos[1]:
                text = index.model().data(index).toString()
                palette = QApplication.palette()
                
                document = QTextDocument()
                document.setDefaultFont(option.font)
                document.setPlainText(text)
                painter.save()
                palette.fillRect(option.rect, QColor(255, 255, 0, 50))
                document.drawContent(painter)
                painter.restore()
                masked = True
        
        if not masked:
            QItemDelegate.paint(self, paint, option, index)

but this would somehow scan the whole data again and again, got potential performance issue

the second one is more standard, use QAbstractTableModel, see shuman's answer

basically do the following thing

  1. create a class to represent one entry of data ( inherit object )

    in addition, def contain(self, column, to_color_word) to indicate should it be colored

  2. create a model to represent the table ( inherit QAbstractTableModel )

    and just like he did, in the data(self, index, role), which means the 'read' or model, at backgroundrole, use the method you defined in above to indicate color

  3. setModel to combine at the top level

this is is more suitable than to use QstandardItem

Community
  • 1
  • 1
Jack Wu
  • 447
  • 4
  • 14
-1

I don't know much about Python but here's an idea. The solution is to use a custom delegate for the column of QTableView and implement its paint() method with rich text support. In delegate's paint() logic wrap your keyword into HTML tags like <font color="red">keyword</font> before displaying.

You can find a sample C++ code here.

Oleg Shparber
  • 2,732
  • 1
  • 18
  • 19