Search code examples
pythonpython-3.xpyqt5nonetypeqlistview

Why QListView gives me a NoneType while trying to retrive text?


I'm writing a simple file searcher in PyQt5 (full code down here).

# -*- coding: utf-8 -*-

import sys, os, platform, fnmatch
from PyQt5 import QtCore, QtGui, QtWidgets

sep = os.sep
Ot = platform.system()
file_name = os.path.basename(__file__)
file_path = __file__.replace(file_name, '')

def find(ext, path):
    result = []
    for root, dirs, files in os.walk(path):
        for name in files:
            if fnmatch.fnmatch(name, ext):
                result.append(os.path.join(root, name))
    _ = dirs # For PyLint
    return result

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(804, 554)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("C:/Users/Luger/Pictures/ico/search.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.folderButton = QtWidgets.QPushButton(self.centralwidget)
        font = QtGui.QFont()
        font.setPointSize(9)
        self.folderButton.setFont(font)
        self.folderButton.setObjectName("folderButton")
        self.horizontalLayout.addWidget(self.folderButton)
        self.extensionLineEdit = QtWidgets.QLineEdit(self.centralwidget)
        font = QtGui.QFont()
        font.setPointSize(9)
        self.extensionLineEdit.setFont(font)
        self.extensionLineEdit.setMaxLength(25)
        self.extensionLineEdit.setAlignment(QtCore.Qt.AlignCenter)
        self.extensionLineEdit.setObjectName("extensionLineEdit")
        self.horizontalLayout.addWidget(self.extensionLineEdit)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.searchButton = QtWidgets.QPushButton(self.centralwidget)
        self.searchButton.setObjectName("searchButton")
        self.verticalLayout.addWidget(self.searchButton)
        self.verticalLayout_2.addLayout(self.verticalLayout)
        self.listView = QtWidgets.QListView(self.centralwidget)
        self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.listView.setIconSize(QtCore.QSize(16, 16))
        self.listView.setObjectName("listView")
        self.entry = QtGui.QStandardItemModel()
        self.listView.setModel(self.entry)
        self.verticalLayout_2.addWidget(self.listView)
        self.horizontalLayout_2.addLayout(self.verticalLayout_2)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 804, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        self.folderButton.clicked.connect(self.fileChooserFunct)
        self.searchButton.clicked.connect(self.searchButtonFunct)
        self.listView.clicked[QtCore.QModelIndex].connect(self.on_clicked)

    def fileChooserFunct(self):
        _translate = QtCore.QCoreApplication.translate
        self.dir_to_scan = QtWidgets.QFileDialog.getExistingDirectory(None, 'Select A folder:', f'{file_path[0]}:{sep}', QtWidgets.QFileDialog.ShowDirsOnly)
        self.folderButton.setText(_translate("MainWindow", f" Selected: {self.dir_to_scan} "))
        self.folderButton.adjustSize()
        if Ot == 'Windows': self.dir_to_scan = self.dir_to_scan.replace('/', '\\')

    def searchButtonFunct(self):
        _translate = QtCore.QCoreApplication.translate
        self.searchButton.setText(_translate("MainWindow", "Searching, please wait..."))
        MainWindow.setWindowTitle(_translate("MainWindow", "File Searcher - Searching"))
        self.searchButton.adjustSize()
        self.userExtension = self.extensionLineEdit.text()
        result = find(f'*.{self.userExtension}', self.dir_to_scan)

        model = QtGui.QStandardItemModel()
        self.listView.setModel(model)

        for i in result:
            item = QtGui.QStandardItem(i)
            model.appendRow(item)

        self.searchButton.setText(_translate("MainWindow", "Search"))
        MainWindow.setWindowTitle(_translate("MainWindow", "File Searcher"))
        self.searchButton.adjustSize()

    def on_clicked(self, index):
        item = self.entry.itemFromIndex(index)
        print(f"itemText='{item.text()}'")


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "File Searcher"))
        self.folderButton.setText(_translate("MainWindow", " Select a folder "))
        self.extensionLineEdit.setPlaceholderText(_translate("MainWindow", "Extension of the file"))
        self.searchButton.setText(_translate("MainWindow", "Search"))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('Fusion')
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Based on a user answer I added this MRE (I hope it's correct)

        self.listView = QtWidgets.QListView(self.centralwidget) #create the widget
        self.listView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) #paths cannot be modified by the user
        self.listView.setObjectName("listView") # Set his name
        self.entry = QtGui.QStandardItemModel() #Those two I don't really know what are for
        self.listView.setModel(self.entry)

        self.listView.clicked[QtCore.QModelIndex].connect(self.on_clicked) #User clicked something in QListView, calling on_clicked


    def on_clicked(self, index):
        item = self.entry.itemFromIndex(index)
        print(f"itemText='{item.text()}'") #Error is given here

I used QtDesigner and converted the UI file using pyuic5.exe, modified a bit and now I'm stuck at retriving the user' selected object in the QListView.

I used a bit of the code of S.Nick in this answer. Even using his code and using the same variables' names, when i click an object i get AttributeError: 'NoneType' object has no attribute 'text'(His code worked without any problems).

The error is given here

    def on_clicked(self, index):
        item = self.entry.itemFromIndex(index)
        print(f"itemText='{item.text()}'")

I have started searching a solution 2 days ago and I viewed most stackoverflow's answers, sites, examples, videos (even 1 hour of two dudes speaking in russian) but still I'm blocked here.
Does anyone know how to fix this? Thanks


Solution

  • The problem is that in the searchButtonFunct method you are creating a new model to the QListView so that the QModelIndex belong to that new model, so using self.entry.itemFromIndex() with QModelIndex that does not belong to that model will return None.

    The solution is to use the same model:

    def searchButtonFunct(self):
        self.entry.clear()
        _translate = QtCore.QCoreApplication.translate
        self.searchButton.setText(_translate("MainWindow", "Searching, please wait..."))
        MainWindow.setWindowTitle(_translate("MainWindow", "File Searcher - Searching"))
        self.searchButton.adjustSize()
        self.userExtension = self.extensionLineEdit.text()
        result = find(f"*.{self.userExtension}", self.dir_to_scan)
    
        for i in result:
            item = QtGui.QStandardItem(i)
            self.entry.appendRow(item)
    
        self.searchButton.setText(_translate("MainWindow", "Search"))
        MainWindow.setWindowTitle(_translate("MainWindow", "File Searcher"))
        self.searchButton.adjustSize()