Issue
import sys
from PySide2.QtGui import QColor, QBrush
from PySide2.QtWidgets import QStyledItemDelegate, QApplication, QTableView, QAbstractItemView, QStyle
from PySide2.QtCore import Qt, QModelIndex, QAbstractTableModel, QEvent
class TBV(QTableView):
def __init__(self) -> None:
super().__init__()
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setMouseTracking(True)
class DEG(QStyledItemDelegate):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self.currentHoveredRow = -1
def paint(self, painter, option, index: QModelIndex) -> None:
if option.state & QStyle.State_MouseOver:
if self.currentHoveredRow == index.row():
option.backgroundBrush = QBrush(QColor(Qt.red))
# option.palette.setBrush(option.palette.Base, QBrush(QColor(Qt.red)))
return super().paint(painter, option, index)
def editorEvent(self, event, model, option, index: QModelIndex) -> bool:
if event.type() == QEvent.MouseMove:
if index.row() != self.currentHoveredRow:
self.currentHoveredRow = index.row()
self.parent().viewport().update()
return super().editorEvent(event, model, option, index)
class MDL(QAbstractTableModel):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self._tabledata = [['mike', 12], ['kk', 13], ['jane', 14]]
def rowCount(self, parent: QModelIndex = ...) -> int:
return len(self._tabledata)
def columnCount(self, parent: QModelIndex = ...) -> int:
return len(self._tabledata[0] if self._tabledata else [])
def data(self, index: QModelIndex, role: int = ...):
if not index.isValid():
return None
if 0 == self.rowCount():
return None
if index.row() >= self.rowCount():
return None
if role == Qt.DisplayRole or role == Qt.EditRole:
return self._tabledata[index.row()][index.column()]
else:
return None
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = TBV()
demo.setItemDelegate(DEG(demo))
model = MDL(demo)
demo.setModel(model)
demo.show()
sys.exit(app.exec_())
as the title described, I need to set a hover effect on the hovered row. I guess such visual effect cannot be set only be QSS. therefore, how to do it in the python code.
And the code I provide above, the editorEvent
method will receive MouseMove Event and get the hovered row index, later the update
method will trigger the paint
method, however,
option.backgroundBrush = QBrush(QColor(Qt.red))
# option.palette.setBrush(option.palette.Base, QBrush(QColor(Qt.red)))
these code will not change the background color of the hovered row. I don't know how.
Solution
Setting the backgroundBrush
of the option is ineffective, because paint()
will create a copy of the option and initialize it with initStyleOption()
.
What you can do is to override initStyleOption()
instead and then set the background in case:
- the
state
isState_MouseOver
(as you already did); - any other "sibling" in the same row possibly contains the mouse cursor;
class DEG(QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
model = index.model()
col = index.column()
view = self.parent()
if option.state & QStyle.State_MouseOver:
option.backgroundBrush = QBrush(Qt.red)
else:
pos = view.viewport().mapFromGlobal(QCursor.pos())
for c in range(model.columnCount()):
if c != col:
r = view.visualRect(index.siblingAtColumn(c))
if r.adjusted(0, 0, 1, 1).contains(pos):
option.backgroundBrush = QBrush(Qt.red)
break
Note that it should not be necessary to override editorEvent()
, but, even if it was, you should call the update()
in any case, even if the movement does not affect a cell previously hovered.
In any case, you cannot use editorEvent()
alone for updating, because it does not track leave events, meaning that rows will not be updated if the mouse leaves moves to a blank area of the view.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.