Issue
I'm creating an application which plots data in files. The first file plotted defines the origin to which all other data is transformed relative to. AFAICT, the QFileDialog always returns files in alphabetical order, regardless of selection order.
Is there a way to return the data ordered by selection?
To illustrate, create a folder with files named something A, B, C or 1, 2, 3. Regardless of the manner they're selected or appear in File Name line edit, the list of paths returned is in alphabetical order.
import os
import sys
from PyQt5 import QtCore, QtWidgets
MYDIR = (os.environ['USERPROFILE'] + '/Desktop/numbered').replace("\\", "/")
def on_button_pressed():
paths, _ = QtWidgets.QFileDialog.getOpenFileNames(
directory = MYDIR,
caption='Open',
filter=(
'All (*.*)'
))
for i, path in enumerate(paths):
print(i, path, flush=True)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
button = QtWidgets.QPushButton("Open")
button.pressed.connect(on_button_pressed)
button.show()
sys.exit(app.exec_())
EDIT An implementation of @musicamate's response which may hang:
import os
import sys
from PyQt5 import QtCore, QtWidgets
MYDIR = (os.environ['USERPROFILE'] + '/Desktop/numbered').replace("\\", "/")
class SelectionOrderFileDialog(QtWidgets.QFileDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setOption(QtWidgets.QFileDialog.DontUseNativeDialog)
self.setFileMode(QtWidgets.QFileDialog.ExistingFiles)
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint)
list_view = self.findChild(QtWidgets.QListView, 'listView')
self.selection_model = list_view.selectionModel()
self.selection_model.selectionChanged.connect(self.check_selection)
self.current_selection = []
def check_selection(self):
active_selection = []
for index in self.selection_model.selectedRows():
path = index.data(QtWidgets.QFileSystemModel.FilePathRole)
active_selection.append(path)
updated_current_selection = []
for path in self.current_selection:
if path in active_selection:
updated_current_selection.append(path)
active_selection.remove(path)
updated_current_selection.extend(active_selection)
self.current_selection[:] = updated_current_selection
print(self.current_selection, flush=True)
def on_button_pressed():
# Works fine when called as...
# dialog = SelectionOrderFileDialog()
# Causes hangs on Open
dialog = SelectionOrderFileDialog(
directory = MYDIR,
caption='Open',
filter=(
'text (*.txt)'
';;python (*.py)'
';;All (*.*)'
))
dialog.exec_()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
button = QtWidgets.QPushButton("Open")
button.resize(300, 25)
button.pressed.connect(on_button_pressed)
button.show()
sys.exit(app.exec_())
Solution
Such level of control cannot be achieved by using static methods, but it can be done by using an instance of QFileDialog.
The only requirement is to avoid the native dialog, so that we can access one of the file views (a non-native QFileDialog has a list view and a tree view), and then connect to the selectionChanged
signal of its selection model.
Then, everytime the signal is emitted, we check with the current ordered selection, remove paths that already exist and build a new list by extending with the new elements.
def showDialog(self):
def checkSelection():
selection = []
for index in selectionModel.selectedRows():
path = index.data(QtWidgets.QFileSystemModel.FilePathRole)
selection.append(path)
newOrderedPaths = []
for path in orderedPaths:
if path in selection:
newOrderedPaths.append(path)
selection.remove(path)
newOrderedPaths.extend(selection)
orderedPaths[:] = newOrderedPaths
dialog = QtWidgets.QFileDialog(self)
dialog.setOption(dialog.DontUseNativeDialog)
dialog.setFileMode(dialog.ExistingFiles)
listView = dialog.findChild(QtWidgets.QListView, 'listView')
selectionModel = listView.selectionModel()
selectionModel.selectionChanged.connect(checkSelection)
orderedPaths = []
dialog.exec_()
print(orderedPaths)
Obviously, the same can be done using a subclass.
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.