Issue
I'd like the user to select a directory that contains files for analysis. I only want to let the user select a directory, not the files within. I am using:
QFileDialog.getExistingDirectory
This shows just the directory (no files are listed, even though they are present). This may be correct behavior, but seeing the files within may be helpful for the user. Ideally, the files within are visible but not selectable
I could use
QFileDialog.getOpenFileName
and select the parent directory of a file they choose. This approach is not perfect as they are selecting a file and not a directory of files.
Wondering if there are any thoughts or suggestions?
Solution
QFileDialog static methods don't allow this kind of approach, and, most importantly, Qt always try to use the native file dialog the underlying operating system provides, for which there's no available access/control.
The solution is to use a custom made QFileDialog instance, ensure that it does not use the native dialog, and set the relative options.
Since you also want to show any non-directory items as disabled, we also need to apply a custom proxy model to the dialog. Note that this step is not really required, as using setFileMode(dialog.Directory)
already ensures that the selected item is actually a directory, otherwise it doesn't allow to open the currently selected item.
from PyQt5 import QtCore, QtWidgets
class DirProxyModel(QtCore.QSortFilterProxyModel):
def __init__(self, fsModel):
super().__init__()
self.fsModel = fsModel
self.setSourceModel(fsModel)
def lessThan(self, left, right):
# QFileSystemModel populates its entries with some delay, which results
# in the proxy model not able to do the proper sorting (usually showing
# directories first) since the proxy does not always "catch up" with the
# source sorting; so, this has to be manually overridden by
# force-checking the entry type of the index.
leftIsDir = self.fsModel.fileInfo(left).isDir()
if leftIsDir != self.fsModel.fileInfo(right).isDir():
return leftIsDir
return super().lessThan(left, right)
def flags(self, index):
flags = super().flags(index)
# map the index to the source and check if it's a directory or not
if not self.fsModel.fileInfo(self.mapToSource(index)).isDir():
# if it is a directory, remove the enabled flag
flags &= ~QtCore.Qt.ItemIsEnabled
return flags
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QHBoxLayout(self)
self.lineEdit = QtWidgets.QLineEdit()
layout.addWidget(self.lineEdit)
self.selectBtn = QtWidgets.QToolButton(text='...')
layout.addWidget(self.selectBtn)
self.selectBtn.clicked.connect(self.selectDirectory)
def selectDirectory(self):
dialog = QtWidgets.QFileDialog(self, windowTitle='Select directory')
dialog.setDirectory(self.lineEdit.text() or __file__)
dialog.setFileMode(dialog.Directory)
dialog.setOptions(dialog.DontUseNativeDialog)
# find the underlying model and set our own proxy model for it
for view in self.findChildren(QtWidgets.QAbstractItemView):
if isinstance(view.model(), QtWidgets.QFileSystemModel):
proxyModel = DirProxyModel(view.model())
dialog.setProxyModel(proxyModel)
break
# try to hide the file filter combo
fileTypeCombo = dialog.findChild(QtWidgets.QComboBox, 'fileTypeCombo')
if fileTypeCombo:
fileTypeCombo.setVisible(False)
dialog.setLabelText(dialog.FileType, '')
if dialog.exec_():
self.lineEdit.setText(dialog.selectedFiles()[0])
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.show()
sys.exit(app.exec_())
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.