Выбор файла или папки QTWidgets
Как я могу поставить на кнопку действие выбора либо файла, либо папки.
Есть варианты:
QtWidgets.QFileDialog.getExistingDirectory и QtWidgets.QFileDialog.getOpenFileName()
А как сделать, чтобы можно было выбрать или папку, или файл?
И еще хотелось бы узнать, можно ли при использовании QtWidgets.QFileDialog.getOpenFileName() сделать, чтобы показывало только файлы определенного расширения
front.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'front.ui'
#
# Created by: PyQt5 UI code generator 5.14.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(300, 400)
MainWindow.setMinimumSize(QtCore.QSize(300, 400))
MainWindow.setMaximumSize(QtCore.QSize(300, 400))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.btnBrowse = QtWidgets.QPushButton(self.centralwidget)
self.btnBrowse.setGeometry(QtCore.QRect(0, 0, 131, 23))
self.btnBrowse.setObjectName("btnBrowse")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 20, 131, 151))
self.listWidget.setObjectName("listWidget")
self.btnArch = QtWidgets.QPushButton(self.centralwidget)
self.btnArch.setGeometry(QtCore.QRect(110, 180, 81, 23))
self.btnArch.setObjectName("btnArch")
self.extractButton = QtWidgets.QPushButton(self.centralwidget)
self.extractButton.setGeometry(QtCore.QRect(180, 0, 81, 23))
self.extractButton.setObjectName("extractButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 300, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.btnBrowse.setText(_translate("MainWindow", "Выбрать папку"))
self.btnArch.setText(_translate("MainWindow", "Архивировать"))
self.extractButton.setText(_translate("MainWindow", "Извлечь"))
main.py
import front
import sys, os, zipfile, traceback
from PyQt5 import QtWidgets
class ExampleApp(QtWidgets.QMainWindow, front.Ui_MainWindow):
directory = ''
def __init__(self):
# Это здесь нужно для доступа к переменным, методам
# и т.д. в файле design.py
super().__init__()
self.setupUi(self) # Это нужно для инициализации дизайна
self.btnBrowse.clicked.connect(self.browse_folder)
self.btnArch.clicked.connect(self.arch_folder)
self.extractButton.clicked.connect(self.extract)
def browse_folder(self):
self.listWidget.clear() # На случай, если в списке уже есть элементы
self.directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Выберите папку")
if self.directory: # не продолжать выполнение, если пользователь не выбрал директорию
for file_name in os.listdir(self.directory): # для каждого файла в директории
self.listWidget.addItem(file_name) # добавить файл в listWidget
return self.directory
def arch_folder(self):
archive = zipfile.ZipFile('test.zip', 'w')
dirfiles = os.listdir(self.directory)
for file in dirfiles:
try:
archive.write(self.directory+"/"+file, compress_type=zipfile.ZIP_DEFLATED)
except:
print(traceback.format_exc())
archive.close()
def extract(self):
self.archive = QtWidgets.QFileDialog.getOpenFileName(self, "Выберите архив")
zip_arch = zipfile.ZipFile(self.archive[0], 'r')
for files in zip_arch.namelist():
zip_arch.extract(files)
zip_arch.close()
def main():
app = QtWidgets.QApplication(sys.argv) # Новый экземпляр QApplication
window = ExampleApp() # Создаём объект класса ExampleApp
window.show() # Показываем окно
app.exec_() # и запускаем приложение
if __name__ == '__main__': # Если запускаем файл напрямую, а не импортируем
main() # то запускаем функцию main()
Ответы (3 шт):
Попробуйте так:
import sys
import os
import zipfile
import traceback
from PyQt5 import QtCore, QtGui, QtWidgets
#import front
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(300, 400)
MainWindow.setMinimumSize(QtCore.QSize(500, 400))
# MainWindow.setMaximumSize(QtCore.QSize(300, 400))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.btnBrowse = QtWidgets.QPushButton(self.centralwidget)
self.btnBrowse.setGeometry(QtCore.QRect(0, 0, 131, 23))
self.btnBrowse.setObjectName("btnBrowse")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 20, 331, 151))
self.listWidget.setObjectName("listWidget")
self.btnArch = QtWidgets.QPushButton(self.centralwidget)
self.btnArch.setGeometry(QtCore.QRect(110, 180, 81, 23))
self.btnArch.setObjectName("btnArch")
self.extractButton = QtWidgets.QPushButton(self.centralwidget)
self.extractButton.setGeometry(QtCore.QRect(380, 0, 81, 23))
self.extractButton.setObjectName("extractButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 300, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.btnBrowse.setText(_translate("MainWindow", "Выбрать ..."))
self.btnArch.setText(_translate("MainWindow", "Архивировать"))
self.extractButton.setText(_translate("MainWindow", "Извлечь"))
class Dialog(QtWidgets.QDialog): # +++
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
label = QtWidgets.QLabel("Сделайте выбор:")
self.rbDir = QtWidgets.QRadioButton('directory', self)
self.rbPath = QtWidgets.QRadioButton('pathFile', self)
btnOk = QtWidgets.QPushButton("Ok", clicked=self.hide)
layout = QtWidgets.QGridLayout(self)
layout.addWidget(label, 0, 0, 1, 3)
layout.addWidget(self.rbDir, 1, 1, 1, 1)
layout.addWidget(self.rbPath, 2, 1, 1, 1)
layout.addWidget(btnOk, 3, 2, 1, 1)
#class ExampleApp(QtWidgets.QMainWindow, front.Ui_MainWindow):
class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow):
directory = ''
pathFile = '' # +++
def __init__(self):
# Это здесь нужно для доступа к переменным, методам
# и т.д. в файле design.py
super().__init__()
self.setupUi(self) # Это нужно для инициализации дизайна
self.btnBrowse.clicked.connect(self.browse_folder)
self.btnArch.clicked.connect(self.arch_folder)
self.extractButton.clicked.connect(self.extract)
self.dialog = Dialog() # +++
# ++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
def browse_folder(self):
self.directory, self.pathFile = '', ''
self.dialog.exec_()
if self.dialog.rbDir.isChecked():
print(f'dialog')
self.listWidget.clear() # На случай, если в списке уже есть элементы
self.directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Выберите папку")
if self.directory: # не продолжать выполнение, если пользователь не выбрал директорию
for file_name in os.listdir(self.directory): # для каждого файла в директории
self.listWidget.addItem(file_name) # добавить файл в listWidget
elif self.dialog.rbPath.isChecked():
print(f'rbPath')
self.pathFile, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
'Open File', './',
'Files (*.py *.txt *.log)')
if self.pathFile:
self.listWidget.addItem(self.pathFile) # добавить файл в listWidget
else:
print(f'no')
msg = QtWidgets.QMessageBox.information(self, 'Message', 'Вы ничего не выбрали.')
# ++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
def arch_folder(self):
print(f'def arch_folder(self): directory = `{self.directory}`')
print(f'def arch_folder(self): pathFile = `{self.pathFile}`')
'''
archive = zipfile.ZipFile('test.zip', 'w')
dirfiles = os.listdir(self.directory)
for file in dirfiles:
try:
archive.write(self.directory+"/"+file, compress_type=zipfile.ZIP_DEFLATED)
except:
print(traceback.format_exc())
archive.close()
'''
def extract(self):
print(f'def extract(self): directory = `{self.directory}`')
print(f'def extract(self): pathFile = `{self.pathFile}`')
'''
self.archive = QtWidgets.QFileDialog.getOpenFileName(self, "Выберите архив")
zip_arch = zipfile.ZipFile(self.archive[0], 'r')
for files in zip_arch.namelist():
zip_arch.extract(files)
zip_arch.close()
'''
def main():
app = QtWidgets.QApplication(sys.argv) # Новый экземпляр QApplication
window = ExampleApp() # Создаём объект класса ExampleApp
window.show() # Показываем окно
app.exec_() # и запускаем приложение
if __name__ == '__main__': # Если запускаем файл напрямую, а не импортируем
main() # то запускаем функцию main()
Чтобы я нажимал на условное "выбрать" открывалось сразу окно выбора файла, но в нем я мог выбрать, как файл, так и папку. Это возможно ?
QFileDialog не позволяет этого изначально.
Единственное решение - создать свой собственный getOpenFilesAndDirs.
Обратите внимание, что для достижения этого вы не можете использовать собственные диалоги вашей ОС, так как Qt почти не контролирует их,
это причина флага dialog.DontUseNativeDialog, который является обязательным.
Следующий код работает так же, как и статические методы, и возвращает выбранные элементы (или ни одного, если диалог отменен).
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(300, 400)
MainWindow.setMinimumSize(QtCore.QSize(500, 400))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.btnBrowse = QtWidgets.QPushButton(self.centralwidget)
self.btnBrowse.setGeometry(QtCore.QRect(0, 0, 131, 23))
self.btnBrowse.setObjectName("btnBrowse")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 20, 331, 151))
self.listWidget.setObjectName("listWidget")
self.btnArch = QtWidgets.QPushButton(self.centralwidget)
self.btnArch.setGeometry(QtCore.QRect(110, 180, 81, 23))
self.btnArch.setObjectName("btnArch")
self.extractButton = QtWidgets.QPushButton(self.centralwidget)
self.extractButton.setGeometry(QtCore.QRect(380, 0, 81, 23))
self.extractButton.setObjectName("extractButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 300, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.btnBrowse.setText(_translate("MainWindow", "Выбрать ..."))
self.btnArch.setText(_translate("MainWindow", "Архивировать"))
self.extractButton.setText(_translate("MainWindow", "Извлечь"))
def getOpenFilesAndDirs(parent=None, caption='', directory='',
filter='', initialFilter='', options=None):
def updateText():
# обновить содержимое виджета редактирования строки выбранными файлами
selected = []
for index in view.selectionModel().selectedRows():
selected.append('"{}"'.format(index.data()))
lineEdit.setText(' '.join(selected))
dialog = QtWidgets.QFileDialog(parent, windowTitle=caption)
dialog.setFileMode(dialog.ExistingFiles)
if options:
dialog.setOptions(options)
dialog.setOption(dialog.DontUseNativeDialog, True) # !!!
if directory:
dialog.setDirectory(directory)
if filter:
dialog.setNameFilter(filter)
if initialFilter:
dialog.selectNameFilter(initialFilter)
# по умолчанию, если каталог открыт в режиме списка файлов,
# QFileDialog.accept() показывает содержимое этого каталога,
# но нам нужно иметь возможность "открывать" и каталоги, как мы можем делать с файлами,
# поэтому мы просто переопределяем `accept()` с реализацией QDialog по умолчанию,
# которая просто вернет `dialog.selectedFiles()`
dialog.accept = lambda: QtWidgets.QDialog.accept(dialog)
# в неродном диалоге есть много представлений элементов,
# но те, которые отображают фактическое содержимое, создаются внутри QStackedWidget;
# это QTreeView и QListView, и дерево используется только тогда,
# когда viewMode установлен на QFileDialog.Details, что не в этом случае.
stackedWidget = dialog.findChild(QtWidgets.QStackedWidget)
view = stackedWidget.findChild(QtWidgets.QListView)
view.selectionModel().selectionChanged.connect(updateText)
lineEdit = dialog.findChild(QtWidgets.QLineEdit)
# очищаем содержимое строки редактирования всякий раз, когда изменяется текущий каталог
dialog.directoryEntered.connect(lambda: lineEdit.setText(''))
dialog.exec_()
return dialog.selectedFiles()
class ExampleApp(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.btnBrowse.clicked.connect(self.browse_folder)
self.btnArch.clicked.connect(self.arch_folder)
self.extractButton.clicked.connect(self.extract)
def browse_folder(self):
selected_files = getOpenFilesAndDirs()
print(selected_files)
if selected_files:
self.listWidget.addItems(selected_files)
else:
msg = QtWidgets.QMessageBox.information(self, 'Message', 'Вы ничего не выбрали.')
def arch_folder(self):
print(f'Выполнить Архивирование: ...')
def extract(self):
print(f'Что-то Извлечь: ...')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = ExampleApp()
window.show()
sys.exit(app.exec_())
Отвечу только на часть вопроса. У метода QtWidgets.QFileDialog.getOpenFileName() есть именованный параметр filter, который отвечает за то, чтобы пользователю показывали файлы только нужных расширений. Например, в этом диалоге:
QFileDialog.getOpenFileName(self, 'Выбрать картинку', '', filter='Картинка
(*.jpg);;Картинка (*.png);;Все файлы (*)')[0]
Пользователь сможет увидеть:
- Или только файлы с расширением .jpg
- Или только файлы с расширением .png
- Или файлы всех расширений
Выбрать любой из этих вариантов пользователь сможет в выпадающем списке, расположенном в правом нижнем углу (По крайней мере в ОС Windows)
Если нужно, чтобы сразу были видны файлы не одного, а нескольких расширений, то при описании фильтра необходимо в скобках через пробел указывать несколько расширений в следующем формате: (*.(расширение))
Пример:
QFileDialog.getOpenFileName(self, 'Выбрать картинку', '', filter='Картинка
(*.jpg *.png *.jpeg))[0]



