有没有办法停止为 PyQt ListView 发出信号?

问题描述

我正在尝试构建一个正在转换文件格式的 PyQt GUI 应用程序。我有一个 ListView,它连接到我的 QAbstractListModel。

我的问题是,作为 MVC 设计的初学者,我理解每当我悬停光标、聚焦应用程序窗口等时,我的视图都会发出信号,并且 ListView 访问我的模型的 data() 方法,然后重复图标的整个过程设置和其他东西。

除了 drop 事件之外,有没有办法停止为我的列表视图发出信号?

因为我不需要为悬停、焦点信号等更新我的视图。

我尝试将 blockSignals (True) 用于视图,但它也阻止了我不想阻止的丢弃信号。但我不确定我是否正确实施了它。我在模型的 init 方法添加了 blockSingals。

这是我的模型:

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 + 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,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",1  
        )  

        if size == "small":  
            img = img.resize((20,20),Image.ANTIALIAS)  

        return img

这是我的用户界面:

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

正如您从第二张图片中看到的,每当我单击或悬停等时,我的数据函数都由视图运行。

解决方法

每次视图重新绘制自身时(例如,当您滚动它时),它会从模型中获取所有必要的数据,这就是设计的工作方式,我认为干扰这个过程不是一个好主意。如果遇到延迟,您可以优化模型,例如 - 使用 dict {path: QImage}(或更好的事件 {ext: QImage})缓存装饰角色的图像,如果缓存不包含条目,则仅调用 get_icon