Issue
When I run my tool and double-click and item it prints the name to the console, in this case, it prints 'comments'. However if I type in the search bar, which filters out the list and then double-click that image again, it returns me the wrong name. I'm not sure where I'm going wrong here. Below is the code, for the entire app.
To test just change the folder path at the end of the code to a local folder on your computer containing some jpg. I find that it's a very simple application with a just a search filter on the listview. I'm confused on why it would return on the wrong item. I'm guessing it has to do with how I retrieve the selection.
On my QAbstractListModel I have a method which I pass a selection
def getSelectedItems(self, selection):
objs = []
for i, index in enumerate(selection):
item = self.getItem(index)
objs.append(item)
return objs
FULL CODE
import sys
import os
from PySide import QtGui, QtCore
from PySide import QtGui as QtWidgets
class AssetItem(object):
def __init__(self, filepath):
self._name = ''
self._filepath = ''
self.filepath = filepath
@property
def filepath(self):
return self._filepath
@filepath.setter
def filepath(self, value):
self._filepath = value
self._name, self._extension = os.path.splitext(os.path.basename(self.filepath))
@property
def name(self):
return self._name
class AssetModel(QtCore.QAbstractListModel):
NameRole = QtCore.Qt.UserRole + 1
def __init__(self, *args, **kwargs):
QtCore.QAbstractListModel.__init__(self, *args, **kwargs)
self._items = []
def rowCount(self, index=QtCore.QModelIndex()):
return len(self._items)
def addItem(self, assetItem):
self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
self._items.append(assetItem)
self.endInsertRows()
def getItem(self, index):
row = index.row()
if index.isValid() and 0 <= row < self.rowCount():
return self._items[row]
def getSelectedItems(self, selection):
objs = []
for i, index in enumerate(selection):
item = self.getItem(index)
objs.append(item)
return objs
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
if 0 <= index.row() < self.rowCount():
item = self._items[index.row()]
if role == AssetModel.NameRole:
return item.name
elif role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignCenter
elif role == QtCore.Qt.ToolTipRole:
return item.name
elif role == QtCore.Qt.DisplayRole:
return item.name
class SortedModel(QtGui.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(SortedModel, self).__init__(*args, **kwargs)
self._patterns = {}
def set_pattern(self, role, value):
self._patterns[role] = value
def filterAcceptsRow(self, sourceRow, sourceParent):
sm = self.sourceModel()
ix = sm.index(sourceRow)
if ix.isValid():
val = True
for role, fvalue in self._patterns.items():
value = ix.data(role)
val = val and self.filter(value, fvalue, role)
return val
return False
@staticmethod
def filter(value, fvalue, role):
'''
fvalue: search value
value: properties value being tested
'''
if role == AssetModel.NameRole:
if fvalue == []:
return True
else:
# change all to any for expanded search
return all(any(x in y for y in value) for x in fvalue)
else:
return False
class ShopWidget(QtWidgets.QWidget):
def __init__(self,parent=None, path=None):
super(ShopWidget, self).__init__(parent)
self.TITLE = 'Shop'
self.VERSION = '1.0.0' # MAJOR.MINOR.PATCH
self.setWindowTitle(self.TITLE + ' | ' + self.VERSION)
self.resize(1000,700)
# properties
self.path = path
# controls
self.ui_search_bar = QtWidgets.QLineEdit()
self.ui_search_bar.setPlaceholderText('Search...')
self.ui_asset_list = QtWidgets.QListView()
self.ui_asset_list.setViewMode(QtWidgets.QListView.IconMode)
self.ui_asset_list.setResizeMode(QtWidgets.QListView.Adjust)
self.ui_asset_list.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.ui_asset_list.setIconSize(QtCore.QSize(256, 256))
self.ui_asset_list.setMovement(QtWidgets.QListView.Static)
self.ui_asset_list.setSpacing(10)
self.ui_asset_list.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.ui_asset_selection_model = self.ui_asset_list.selectionModel()
self.ui_asset_list.setIconSize(QtCore.QSize(128,128))
self.sorted_model = SortedModel()
self.sorted_model.setSourceModel(AssetModel())
self.ui_asset_list.setModel(self.sorted_model)
# layout
search_layout = QtWidgets.QHBoxLayout()
search_layout.addWidget(self.ui_search_bar)
main_layout = QtWidgets.QVBoxLayout()
main_layout.addLayout(search_layout)
main_layout.addWidget(self.ui_asset_list)
self.setLayout(main_layout)
# connections
self.ui_search_bar.textChanged.connect(self.search_value_changed)
self.ui_search_bar.keyPressEvent = self.search_bar_key_event
self.ui_asset_list.doubleClicked.connect(self.on_item_double_clicked)
# constructor
self.path = path
self.populate_asset_list()
# methods
def populate_asset_list(self):
extensions = ['.jpg']
directory = self.path
if not os.path.isdir(directory):
return
for root, subdirs, files in os.walk(directory):
for f in files:
filepath = os.path.join(root, f)
if not os.path.isfile(filepath):
continue
if not os.path.splitext(filepath)[-1] in extensions:
continue
self.ui_asset_list.model().sourceModel().addItem(AssetItem(filepath))
def search_bar_key_event(self, event):
if event.key() == QtCore.Qt.Key_Escape:
self.ui_search_bar.clear()
QtWidgets.QLineEdit.keyPressEvent(self.ui_search_bar, event)
def search_value_changed(self, text):
filters = filter(None, text.lower().split(' '))
model = self.ui_asset_list.model()
model.set_pattern(AssetModel.NameRole, filters)
model.invalidateFilter()
def import_assets(self):
selection = self.ui_asset_list.selectionModel().selectedRows()
assets = self.ui_asset_list.model().sourceModel().getSelectedItems(selection)
for x in assets:
print x.name
# actions
def on_item_double_clicked(self, index):
self.import_assets()
# Main
# -----------------------------------------------------------------------------
def main():
app = QtWidgets.QApplication(sys.argv)
ex = ShopWidget(path='C:/Users/jmartini/Desktop/Temp/images')
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Solution
When selecting the QModelIndex with the method selectionModel().selectedRows()
this returns the indexes with respect to the model that was established to the view, in your case the SortedModel
, but if you want to obtain an item you must have a QModelIndex
that belong to AssetModel
, that is, to the source model, for this you must use mapToSource
of the proxy model:
def import_assets(self):
selection = self.ui_asset_list.selectionModel().selectedRows()
selection_x = [self.ui_asset_list.model().mapToSource(index) for index in selection]
assets = self.ui_asset_list.model().sourceModel().getSelectedItems(selection_x)
for x in assets:
print(x.name)
Answered By - eyllanesc
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.