Issue
How can i emit a signal when a qlistview item's checkbox is changed? Ideally the emitted signal would have some sort of pointer to the item that changed so i could act accordingly in PySide.
import os
import sys
import json
from PySide import QtGui, QtCore
class MegaMergeWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
super(MegaMergeWindow, self).__init__(*args, **kwargs)
self.TITLE = 'Mega Merge'
self.VERSION = '1.0.0'
self.setWindowTitle(self.TITLE + ' | ' + self.VERSION)
self.resize(350,500)
# vars
self.user_folder = os.path.join(os.getenv('LOCALAPPDATA'), 'MegaMerge')
# controls
self.ui_files = QtGui.QListView()
self.ui_files.setModel(QtGui.QStandardItemModel())
self.ui_files.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.ui_merge = QtGui.QPushButton('Merge')
main_layout = QtGui.QVBoxLayout()
main_layout.addWidget(self.ui_files)
main_layout.addWidget(self.ui_merge)
main_widget = QtGui.QWidget()
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
# signals
self.ui_merge.clicked.connect(self.merge_clicked)
self.populate_files()
def populate_files(self, files=[], clear=False):
model = self.ui_files.model()
if clear:
model.clear()
files = ['Doug','Kevin','Amy','Melissa','John']
for f in files:
name = os.path.basename(f)
item = QtGui.QStandardItem(name)
item.setData(f, role=QtCore.Qt.UserRole)
item.setCheckable(True)
item.setCheckState(QtCore.Qt.Checked)
model.appendRow(item)
model.sort(0, QtCore.Qt.AscendingOrder)
def collect_paths(self):
files = []
model = self.ui_files.model()
for index in range(model.rowCount()):
item = model.item(index)
if item.checkState() == QtCore.Qt.Checked:
files.append(item.text())
return files
def merge_files(self, files=[]):
print files
def merge_clicked(self):
files = self.collect_paths()
print files
def main():
app = QtGui.QApplication(sys.argv)
ex = MegaMergeWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Solution
In Qt4 there is no signal indicating that if QCheckBox
is checked or not QAbstractItemView
, just in Qt5 the dataChanged
signal was modified to send the role that was modified and therefore distinguish if the checked was changed or not.
In Qt4 there are several alternatives to create that signal, one way is to use a delegate to track the change of that role as I show below:
class StyledItemDelegate(QtGui.QStyledItemDelegate):
checked = QtCore.Signal(QtCore.QModelIndex, int)
def editorEvent(self, event, model, option, index):
if model.flags(index) & QtCore.Qt.ItemIsUserCheckable:
# before the change
last_value = index.data(QtCore.Qt.CheckStateRole)
value = QtGui.QStyledItemDelegate.editorEvent(self, event, model, option, index)
if model.flags(index) & QtCore.Qt.ItemIsUserCheckable:
# after the change
new_value = index.data(QtCore.Qt.CheckStateRole)
if last_value != new_value:
self.checked.emit(index, new_value)
return value
class MegaMergeWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
[...]
# controls
self.ui_files = QtGui.QListView()
self.ui_files.setModel(QtGui.QStandardItemModel())
self.ui_files.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
delegate = StyledItemDelegate()
delegate.checked.connect(self.on_checked)
self.ui_files.setItemDelegate(delegate)
[...]
def on_checked(self, index, state):
text = "Checked" if state == QtCore.Qt.Checked else "UnChecked"
item = self.ui_files.model().itemFromIndex(index)
print(item, item.data())
print(index, index.data())
print(state)
print(text)
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.