I'm trying to build a PyQt GUI application which is converting file formats. I have a ListView and it's connected to my QAbstractListModel.
My problem is, as a beginner to MVC design I understand my view emitting signals whenever I hover my cursor, focus app window, etc. and the ListView accessing to my model's data() method and then repeating the whole process of icon setting and other stuff.
Is there is a way to stop emitting signals for my listview except for my drop event?
Because I don't need to update my view for hover, focus signals, etc.
I tried to use blockSignals (True) for the view but it's also blocking my drop signal which is I don't want to block it. But I'm not sure if I implemented it correctly. I added blockSingals into the init method of my model.
Here is my model:
class FileModel(QtCore.QAbstractListModel):
def __init__(self, data = [], parent = None):
QtCore.QAbstractListModel.__init__(self, parent)
self._data = data
def rowCount(self, parent):
return len(self._data)
def data(self, index, role):
# Here I print the role to show you
# my view check my model for every signal
print(role)
if role == QtCore.Qt.DisplayRole:
row = index.row()
value = self._data[row]
return value
if role == QtCore.Qt.DecorationRole:
row = index.row()
path = self._data[row].replace("/", "\\")
image = self.get_icon(path, "small")
qtImage = ImageQt.ImageQt(image)
pixmap = QtGui.QPixmap.fromImage(qtImage)
icon = QtGui.QIcon(pixmap)
return icon
def insertRows(self, position, rows, items, parent):
self.beginInsertRows(QtCore.QModelIndex(),
position,
position + rows - 1)
for index in range(rows):
self._data.insert(position, items[index])
self.endInsertRows()
return True
def get_icon(self, PATH, size):
SHGFI_ICON = 0x000000100
SHGFI_ICONLOCATION = 0x000001000
if size == "small":
SHIL_SIZE= 0x00001
elif size == "large":
SHIL_SIZE= 0x00002
else:
raise TypeError("Invalid argument for 'size'. Must be equal to 'small' or 'large'")
ret, info = shell.SHGetFileInfo(PATH, 0, SHGFI_ICONLOCATION | SHGFI_ICON | SHIL_SIZE)
hIcon, iIcon, dwAttr, name, typeName = info
ico_x = win32api.GetSystemMetrics(win32con.SM_CXICON)
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0, 0), hIcon)
win32gui.DestroyIcon(hIcon)
bmpinfo = hbmp.GetInfo()
bmpstr = hbmp.GetBitmapBits(True)
img = Image.frombuffer(
"RGBA",
(bmpinfo["bmWidth"], bmpinfo["bmHeight"]),
bmpstr, "raw", "BGRA", 0, 1
)
if size == "small":
img = img.resize((20, 20), Image.ANTIALIAS)
return img
Here is my ui:
class Ui_Window(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.listView = FileView(MainWindow)
self.listView.setGeometry(QtCore.QRect(35, 21, 721, 521))
self.listView.setObjectName("listView")
self.listView.setViewMode(QtWidgets.QListWidget.ListMode)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
class FileView(Ui_Window, QListView):
def __init__(self,parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.setDragDropMode(QAbstractItemView.DragDrop)
self.items = []
self.model = FileModel(self.items)
self.setModel(self.model)
def setupUi(self, Form):
super().setupUi(Form)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
if url.isLocalFile():
links.append(str(url.toLocalFile()))
else:
links.append(str(url.toString()))
self.model.insertRows(0, len(links), links, QtCore.QModelIndex())
else:
event.ignore()
My application nothing dropped yet:
Here I dropped a file and hovered my mouse on the file couple of times:
As you can see from the second image whenever I click or hover etc. my data function is being run by the view.


Every time view repaints iteself (for example when you scroll it), it fetches all necessary data from model, it's how things designed to work, I dont think it's good idea to interfere with this process. If you experiencing lags, you can optimize your model, for example - cache images for decoration role using
dict {path: QImage}(or event better{ext: QImage}) and only callget_iconif cache does not contain entry.