Results 1 to 6 of 6

Thread: On mouse click changing selection's background color in tableview

  1. #1
    Join Date
    Apr 2015
    Posts
    20
    Thanks
    7
    Qt products
    Platforms
    Unix/X11

    Arrow On mouse click changing selection's background color in tableview

    Program is for linux distributions.
    I am trying to notify user when something is wrong with the item in the list when it is double clicked.
    I used setStyleSheet, only to find out that it does not work on unity and cinnamon, while it works on KDE and i3.

    I am not all that savvy with qbrushes or some other stuff I am googling out.
    So whats the best way to solve this, so that it works everywhere? Thanks.

    Heres a gif of my solution in action on i3wm.

    Vp6r052.gif

    Qt Code:
    1. from PyQt5.QtCore import *
    2. from PyQt5.QtGui import *
    3. from PyQt5.QtWidgets import *
    4. import sys
    5.  
    6.  
    7. class My_Model_table(QAbstractTableModel):
    8. def __init__(self, table_data=[], parent=None):
    9. super().__init__()
    10. self.table_data = table_data
    11.  
    12. def rowCount(self, parent):
    13. return len(self.table_data)
    14.  
    15. def columnCount(self, parent):
    16. return 1
    17.  
    18. def data(self, index, role):
    19. if role == Qt.DisplayRole:
    20. value = self.table_data[index.row()]
    21. return value
    22. if role == Qt.TextAlignmentRole:
    23. return Qt.AlignCenter
    24.  
    25.  
    26. class My_table(QTableView):
    27. def __init__(self, parent=None):
    28. super().__init__()
    29. self.activated.connect(self.double_click_enter)
    30.  
    31. def double_click_enter(self, QModelIndex):
    32. row = QModelIndex.row()
    33.  
    34. self.setStyleSheet('selection-background-color:red;')
    35.  
    36. self.alarm = QTimer()
    37. self.alarm.timeout.connect(self.row_color_back)
    38. self.alarm.setSingleShot(True)
    39. self.alarm.start(200)
    40. return
    41.  
    42. def row_color_back(self):
    43. self.setStyleSheet('')
    44.  
    45.  
    46. if __name__ == '__main__':
    47. app = QApplication(sys.argv)
    48. data = ['1', '2', '3', '4', '5']
    49. main_table = My_table()
    50. main_table.setModel(My_Model_table(data))
    51.  
    52. main_table.show()
    53. sys.exit(app.exec_())
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: On mouse click changing selection's background color in tableview

    I'm not that good at Python, but hopefully you can get my meaning.

    At some point, you will need to add logic to your model that contains the information about whether a table entry is valid or not, right?

    So, add a case to your model's data() method to handle the Qt::BackgroundRole role. In this role, for an entry in error you will return a QBrush with the error color, otherwise you do nothing and the superclass data() method will be invoked to return the default color.

    If you want the color to blink in response to your double-click, then your timer approach is on the right track. In this case, you must also implement the setData() method for your model, and within that, implement a handler for the Qt::BackgroundRole case. In that handler, you will store the QBrush and model index that are passed in. You'll need new member variables somewhere in your model. Since this is a transient thing, you don't need to add storage for every model index, just the row / column of the item with the error that has been clicked.

    In the double-click handler, when you determine that the item has an error, you call setData() with the index, Qt::BackgroundRole, and QBrush for the error color. Start your timer. When the double-click handler exits, the model will tell the view to update the background color for the changed index (it will send the "dataChanged()" signal, which the table listens for).

    When your timer times out, in the timeout slot call setData() again with the same index and role, but with the default background color. This will again cause the table to update the cell.

    There may be other ways to do this, but this way uses the machinery already in place in the model / view architecture to change the background color.

  3. The following user says thank you to d_stranz for this useful post:

    DoTheEvo (25th January 2016)

  4. #3
    Join Date
    Apr 2015
    Posts
    20
    Thanks
    7
    Qt products
    Platforms
    Unix/X11

    Default Re: On mouse click changing selection's background color in tableview

    THANKS for replying.

    But theres some initial problems with this approach.

    Playing here with backgroundRole and the brush, if I use this code to color every other row green. Well the problem is that it is the background color of the cell
    not the color of the selection indicator. So I am assuming it might not even be visible if I managed to call from view a change in model with custom setData() method.
    Qt Code:
    1. elif role == Qt.BackgroundRole:
    2. if index.row() % 2 == 0:
    3. return QBrush(Qt.green)
    To copy to clipboard, switch view to plain text mode 
    But will play with it more I guess and try to make it work, I only need to indicate to user that shit went wrong on double click(text in status bar is already telling that but I feel some color emphasis would be nice), so flashing background of all rows red for 0.2sec would serve well as notice of this, even if bit less elegant than just that row...

    Last edited by DoTheEvo; 25th January 2016 at 11:52.

  5. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,229
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: On mouse click changing selection's background color in tableview

    What I suggested is that you use the setData() method as a way to accomplish flashing the color:

    1 - When the user double-clicks, use a setData() call to send the index of the offending cell into the model. You have to implement setData() and in the BackgroundRole handler, you use the information in the call to set member variables that "remember" the index (or row / column) as being the one with the problem.
    2 - The setData call will cause the view to update. In your data() method, you compare the index passed in with the index you "remembered", and if there's a match, you return a red brush. Otherwise, you return whatever brush you want to use for that index under normal conditions.
    3 - In your double-click handler, you also start a timer, as you showed in your example.
    4 - When the timer times out, the slot should call setData() again, this time with an invalid index for the background role. This resets the index you "remembered".
    5 - When the view again updates, none of the indexes will match the invalid one, so the indexes get painted with their normal background colors.

    Thus, the only index that turns red is the one that was double-clicked, and only during the period between the end of the double-click and the timeout. The view takes care of updating itself.

  6. #5
    Join Date
    Apr 2015
    Posts
    20
    Thanks
    7
    Qt products
    Platforms
    Unix/X11

    Default Re: On mouse click changing selection's background color in tableview

    Finally got some free time and taste for looking in to this again.

    As I said before, returning of the QBrush in data() only changes background color, while the color of the selected row stays the same as the "selection-background-color"
    so going for some passing of index and trying to find which row to have color change, well that seem waste of time (apart from learning experience) since we would never see the color change, it would be covered by the defauly highlight color




    Above is gif of changing qbrush color for everything. I got problem getting the default color of the background of the table... but solved it by just not applying any brush when I am not setting it
    Anyway, this code works on ubuntu and it does give me some control over colors, but not over selection/highlight color.
    It looks worse, less elegant than the stylesheet way that can be viewed in OP post in this thread, but still better than nothing, and this makes me appreciate how awesome stylesheets are.

    Qt Code:
    1. from PyQt5.QtCore import *
    2. from PyQt5.QtGui import *
    3. from PyQt5.QtWidgets import *
    4. import sys
    5.  
    6.  
    7. class My_Model_table(QAbstractTableModel):
    8. def __init__(self, table_data=[], parent=None):
    9. super().__init__()
    10. self.table_data = table_data
    11. self.color_enabled = False
    12. self.color_back = Qt.magenta # just something there
    13.  
    14. def rowCount(self, parent):
    15. return len(self.table_data)
    16.  
    17. def columnCount(self, parent):
    18. return 1
    19.  
    20. def data(self, index, role):
    21. if role == Qt.DisplayRole:
    22. value = self.table_data[index.row()]
    23. return value
    24. if role == Qt.TextAlignmentRole:
    25. return Qt.AlignCenter
    26.  
    27. if role == Qt.BackgroundRole and self.color_enabled:
    28. return QBrush(self.color_back)
    29.  
    30. def change_color(self, qt_color, color_enabled):
    31. self.layoutAboutToBeChanged.emit()
    32. self.color_enabled = color_enabled
    33. self.color_back = qt_color
    34. self.layoutChanged.emit()
    35.  
    36.  
    37. class My_table(QTableView):
    38. def __init__(self, parent=None):
    39. super().__init__()
    40. self.activated.connect(self.double_click_enter)
    41.  
    42. def double_click_enter(self, QModelIndex):
    43. QModelIndex.model().change_color(Qt.red, True)
    44.  
    45. self.alarm = QTimer()
    46. self.alarm.setSingleShot(True)
    47. self.alarm.timeout.connect(self.color_timeout)
    48. self.alarm.start(200)
    49.  
    50. def color_timeout(self):
    51. self.model().change_color(Qt.magenta, False)
    52.  
    53.  
    54. if __name__ == '__main__':
    55. app = QApplication(sys.argv)
    56. data = ['1', '2', '3', '4', '5']
    57. main_table = My_table()
    58. main_table.setModel(My_Model_table(data))
    59.  
    60. main_table.show()
    61. sys.exit(app.exec_())
    To copy to clipboard, switch view to plain text mode 
    Last edited by DoTheEvo; 15th February 2016 at 19:53.

  7. #6
    Join Date
    Apr 2015
    Posts
    20
    Thanks
    7
    Qt products
    Platforms
    Unix/X11

    Angry Re: On mouse click changing selection's background color in tableview

    OK, final edit since I figured it out when I started to play with qdarkstylesheet and noticed that everything worked nicely even on ubuntu...
    my mistake in original code was just using selection-background-color, when I use QTableView::item:selected:active everything now works perfectly



    Qt Code:
    1. from PyQt5.QtCore import *
    2. from PyQt5.QtGui import *
    3. from PyQt5.QtWidgets import *
    4. import sys
    5.  
    6.  
    7. class My_Model_table(QAbstractTableModel):
    8. def __init__(self, table_data=[], parent=None):
    9. super().__init__()
    10. self.table_data = table_data
    11.  
    12. def rowCount(self, parent):
    13. return len(self.table_data)
    14.  
    15. def columnCount(self, parent):
    16. return 1
    17.  
    18. def data(self, index, role):
    19. if role == Qt.DisplayRole:
    20. value = self.table_data[index.row()]
    21. return value
    22. if role == Qt.TextAlignmentRole:
    23. return Qt.AlignCenter
    24.  
    25.  
    26. class My_table(QTableView):
    27. def __init__(self, parent=None):
    28. super().__init__()
    29. self.activated.connect(self.double_click_enter)
    30.  
    31. def double_click_enter(self, QModelIndex):
    32. row = QModelIndex.row()
    33.  
    34. self.setStyleSheet(
    35. '''
    36. QTableView::item:selected:active {
    37. background: #ff0000;
    38. }
    39. '''
    40. )
    41.  
    42. self.alarm = QTimer()
    43. self.alarm.timeout.connect(self.row_color_back)
    44. self.alarm.setSingleShot(True)
    45. self.alarm.start(200)
    46. return
    47.  
    48. def row_color_back(self):
    49. self.setStyleSheet('')
    50.  
    51.  
    52. if __name__ == '__main__':
    53. app = QApplication(sys.argv)
    54. data = ['1', '2', '3', '4', '5']
    55. main_table = My_table()
    56. main_table.setModel(My_Model_table(data))
    57.  
    58. main_table.show()
    59. sys.exit(app.exec_())
    To copy to clipboard, switch view to plain text mode 

    /EDIT



    damn, and it does not work in my actual code because I use delegate to get html rich text to get bold emphasize
    oh how I hate it, I undertand very little and its always huge pain in the ass in getting it to done things without screwing something else
    heres my delegate if someone is guru with them
    Last edited by DoTheEvo; 15th February 2016 at 22:47.

Similar Threads

  1. Replies: 4
    Last Post: 3rd July 2014, 15:52
  2. Setting the background color of a header in TableView
    By sunilqt in forum Qt Programming
    Replies: 1
    Last Post: 13th April 2013, 14:06
  3. Replies: 6
    Last Post: 28th September 2012, 00:44
  4. changing background color in qvfb
    By John Douma in forum Qt for Embedded and Mobile
    Replies: 0
    Last Post: 31st March 2011, 20:30
  5. Replies: 1
    Last Post: 22nd February 2010, 10:38

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.