views:

463

answers:

2

I have a custom subclass of a QTreeView in a pyqt application. I'm trying to give the user the ability to highlight and "lowlight" (for lack of a better term) rows. Highlighted rows should have bold text and (optionally) a different background color. Any ideas?
I'm considering StyleSheets as an option, but have so far been unable to get that to work. If I set the QTreeView's stylesheet:

self.setStyleSheet("QTreeView::item:selected {border: 1px solid #567dbc;}")

I can't figure out how to manually enable 'states' that would keep only the desired rows at a particular state. If I try setting an individual item's stylesheet:

#modelIndex is a valid QModelIndex
modelIndex.internalPointer().setStyleSheet()

I get a segfault.
I'm not convinced stylesheets are the way to go, I'm open to all ideas. Thanks!

+3  A: 

I can think of a few ways to do this. The easiest, if you have access to the model, is to add some state tracking of the indexes in the model, and return the proper options for the roles requested in the data() function. The drawback to this is if you are using the same model in different views, and want to keep the highlights local to one view.

The second-easiest is probably to make a proxy model, which keeps track of the data itself, and gets all other data from the original model. In this situation (where you aren't changing the rows or columns of the original model) it would probably be pretty easy.

The hardest would be to make a custom delegate that keeps track of which rows/columns should be highlighted, and draws itself differently based on the row/column of the model index it is drawing. You would have to keep access to the delegate so that you could tell it which rows and columns need to be set. You would also need to deal with what happens when the model changes.

Caleb Huitt - cjhuitt
I'd want the state to be viewable by all views, but the model will routinely update in the background, so I think I would want to add some state thing to the items themselves.Once I have the state variable set and accessible, however, I'm still not sure how I would actually display the items as bold.
taynaron
@taynaron: The model's data function takes a parameter for the role of the data to return. Odds are you're only looking at the DisplayRole, and returning the data to be drawn. However, there is also a FontRole that you could use to return a font to be used to render the item (hence, bold), and a BackgroundColorRole and TextColorRole you can use to change the colors used to draw those items. That's for the first two (model) options. The delegate option has a paint method that you would have to override and draw bold text.
Caleb Huitt - cjhuitt
+1  A: 

From what you've said it looks like the easiest solution would be to define a custom item delegate for your treeview and set items font weight to bold whenever it's needed. Pls, check if an example below would work for you, it should create a treeview with custom item delegate which would change item's font style.

import sys
from PyQt4 import QtGui, QtCore

class BoldDelegate(QtGui.QStyledItemDelegate):
    def paint(self, painter, option, index):
        # decide here if item should be bold and set font weight to bold if needed 
        option.font.setWeight(QtGui.QFont.Bold)
        QtGui.QStyledItemDelegate.paint(self, painter, option, index)


class MainForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        model = QtGui.QStandardItemModel()

        for k in range(0, 4):
            parentItem = model.invisibleRootItem()
            for i in range(0, 4):
                item = QtGui.QStandardItem(QtCore.QString("item %0 %1").arg(k).arg(i))
                parentItem.appendRow(item)
                parentItem = item

        self.view = QtGui.QTreeView()
        self.view.setModel(model)
        self.view.setItemDelegate(BoldDelegate(self))

        self.setCentralWidget(self.view)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

hope this helps, regards

serge_gubenko