本文目录
- PyQt5桌面应用系列
- 介绍
- QFileDialog的静态接口
- QFileDialog的对象接口
- 示例
- 结论
- 后记
介绍
读入和写文件是一个GUI程序的常用操作。前者导入需要处理的数据,后者把数据输出到硬盘上后期使用。PyQt5提供了PyQt5.QtWidgets.QFileDialog
类来完成常用的文件打开、文件存储的功能。
这个类有两个接口形式。第一种形式采用静态函数,调用的方式就是QFileDialog.method()
,比如QFileDialog.getOpenFileName()
。第二种形式需要先创建一个QFileDialog
对象,然后调用对象的method()
方法,比如QFileDialog().getOpenFileName()
。
QFileDialog的静态接口
方便使用的静态函数包括下面的函数:
def getExistingDirectory(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getExistingDirectory(parent: typing.Optional[QWidget] = None, caption: str = '', directory: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = QFileDialog.ShowDirsOnly) -> str """
pass
def getExistingDirectoryUrl(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getExistingDirectoryUrl(parent: typing.Optional[QWidget] = None, caption: str = '', directory: QUrl = QUrl(), options: Union[QFileDialog.Options, QFileDialog.Option] = QFileDialog.ShowDirsOnly, supportedSchemes: Iterable[str] = []) -> QUrl """
pass
def getOpenFileName(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getOpenFileName(parent: typing.Optional[QWidget] = None, caption: str = '', directory: str = '', filter: str = '', initialFilter: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = 0) -> Tuple[str, str] """
pass
def getOpenFileNames(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getOpenFileNames(parent: typing.Optional[QWidget] = None, caption: str = '', directory: str = '', filter: str = '', initialFilter: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = 0) -> Tuple[List[str], str] """
pass
def getOpenFileUrl(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getOpenFileUrl(parent: typing.Optional[QWidget] = None, caption: str = '', directory: QUrl = QUrl(), filter: str = '', initialFilter: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = 0, supportedSchemes: Iterable[str] = []) -> Tuple[QUrl, str] """
pass
def getOpenFileUrls(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getOpenFileUrls(parent: typing.Optional[QWidget] = None, caption: str = '', directory: QUrl = QUrl(), filter: str = '', initialFilter: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = 0, supportedSchemes: Iterable[str] = []) -> Tuple[List[QUrl], str] """
pass
def getSaveFileName(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getSaveFileName(parent: typing.Optional[QWidget] = None, caption: str = '', directory: str = '', filter: str = '', initialFilter: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = 0) -> Tuple[str, str] """
pass
def getSaveFileUrl(self, parent, QWidget=None, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
""" getSaveFileUrl(parent: typing.Optional[QWidget] = None, caption: str = '', directory: QUrl = QUrl(), filter: str = '', initialFilter: str = '', options: Union[QFileDialog.Options, QFileDialog.Option] = 0, supportedSchemes: Iterable[str] = []) -> Tuple[QUrl, str] """
pass
可以很方便的打开目录、多文件、单文件,保存文件。函数的返回值第一就是文件的路径,第二个是文件的类型。如果采用Url的形式,则可以打开类似于PyQt5.QtCore.QUrl('file:///C:/Users/User/qchen/pyqt5/chart1.py')
的形式,这种方式应该还可以很方便的打开ftp等形式的文件。
QFileDialog的对象接口
采用对象的接口也非常直观。
- 创建一个
QFileDialog
对象; - 调用
QFileDialog
对象的setWindowTitle()
方法设置标题; - 调用
QFileDialog
对象的setDirectory()
方法设置默认打开的目录; - 调用
QFileDialog
对象的setNameFilter()
方法设置文件过滤器; - 调用
QFileDialog
对象的setFileMode()
方法设置文件模式; - 调用
QFileDialog
对象的setViewMode()
方法设置视图模式; - 调用
QFileDialog
对象的setOption()
方法设置对话框的选项; - 调用
QFileDialog
对象的open()
方法打开对话框; - 调用
QFileDialog
对象的selectedFiles()
方法获取选中的文件,或者调用QFileDialog
对象的selectedUrl()
方法获取选中的文件的Url。
示例
下面的示例代码演示了如何使用QFileDialog
类。
import sys
from functools import partial
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenuBar, QAction, QTextEdit, QFileDialog, QWidget, QStatusBar, \
QToolBar, QStyle
current_file: str = None
def open_file_func(parent: QWidget, content: QTextEdit, checked: bool):
try:
file, current_filter = QFileDialog.getOpenFileName(parent,
"Open File",
".",
"Text Files (*.txt);;Python Files (*.py);;Markdown Files ("
"*.md)")
with open(file, "r", encoding="utf-8") as fid:
content.setText(fid.read())
global current_file
current_file = file
if isinstance(parent, QMainWindow):
parent: QMainWindow
parent.statusBar().showMessage(f"Opened {file}")
parent.setWindowTitle(file)
except Exception as e:
content.setText(f"<b style='color:#FF0000'>{str(e)}</b>")
current_file = None
def save_file_func(parent: QWidget, content: QTextEdit, checked: bool):
try:
global current_file
if current_file is None:
save_as_file_func(parent, content, checked)
return
with open(current_file, "w", encoding="utf-8") as fid:
fid.write(content.toPlainText())
if isinstance(parent, QMainWindow):
parent: QMainWindow
parent.statusBar().showMessage(f"Saved {current_file}")
parent.setWindowTitle(current_file)
except Exception as e:
content.setText(f"<b style='color:#FF0000'>{str(e)}</b>")
current_file = None
def save_as_file_func(parent: QWidget, content: QTextEdit, checked: bool):
try:
file, current_filter = QFileDialog.getSaveFileName(parent,
"Open File",
".",
"Text Files (*.txt);;Python Files (*.py);;Markdown Files ("
"*.md)")
with open(file, "w", encoding="utf-8") as fid:
fid.write(content.toPlainText())
global current_file
current_file = file
if isinstance(parent, QMainWindow):
parent: QMainWindow
parent.statusBar().showMessage(f"Saved {file}")
parent.setWindowTitle(file)
except Exception as e:
content.setText(f"<b style='color:#FF0000'>{str(e)}</b>")
current_file = None
def file_edited(parent: QMainWindow):
parent: QMainWindow
if current_file == parent.windowTitle():
parent.setWindowTitle(f"{current_file}*")
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = QMainWindow()
content_edit = QTextEdit(mw)
menu = QMenuBar(mw)
sb = QStatusBar(mw)
tb = QToolBar(mw)
content_edit.textChanged.connect(partial(file_edited, mw))
mw.setMenuBar(menu)
mw.setCentralWidget(content_edit)
mw.setStatusBar(sb)
mw.addToolBar(tb)
file_menu = menu.addMenu("&File")
open_file = QAction("Open", mw)
open_file.setShortcut("Ctrl+O")
open_file.setIcon(mw.style().standardIcon(QStyle.SP_DialogOpenButton))
open_file.triggered.connect(partial(open_file_func, mw, content_edit))
save_as_file = QAction("Save as", mw)
save_as_file.setShortcut("Ctrl+Shift+S")
save_as_file.setIcon(QIcon("sa.png"))
save_as_file.triggered.connect(partial(save_as_file_func, mw, content_edit))
save_file = QAction("Save", mw)
save_file.setShortcut("Ctrl+S")
save_file.setIcon(mw.style().standardIcon(QStyle.SP_DialogSaveButton))
save_file.triggered.connect(partial(save_file_func, mw, content_edit))
exit_app = QAction("Exit", mw)
exit_app.setShortcut("Ctrl+Q")
exit_app.setIcon(mw.style().standardIcon(QStyle.SP_DialogCloseButton))
exit_app.triggered.connect(lambda checked: mw.close())
file_menu.addAction(open_file)
file_menu.addAction(save_file)
file_menu.addAction(save_as_file)
file_menu.addSeparator()
file_menu.addAction(exit_app)
tb.addAction(open_file)
tb.addAction(save_file)
tb.addAction(save_as_file)
tb.addAction(exit_app)
mw.setWindowTitle("File Open Dialog")
mw.resize(800, 600)
mw.setWindowIcon(QIcon("icon.png"))
mw.show()
sys.exit(app.exec_())
这个示例实现了一个非常简单的文本编辑器。打开文件、存储文件、另存文件都实现为QAction
,这个可以在菜单和工具栏上复用,还是非常方便的。
当文件被编辑时,标题中增加*,便于保存和另存。PyQt5很好很强大啊。当然如果需要一次打开多个文件,那么这里可能需要实现一个MDIArea,这个就不是本文的重点了。
这个程序用到functools.partial
,很好的帮助我们在设置QAction
的triggered
信号时传递参数。如果使用lambda,可能不便于捕捉参数的当地值。
程序的图标使用了部分PyQt5的标准图标,标准图标的名称用SP_xxxx
从QStyle
中获得。
程序本身的图标准备了两个图片文件。
结论
- QFileDialg是一个非常方便的文件选择对话框,可以用来打开文件、保存文件、选择文件夹等。
- QFileDialog的静态方法可以直接使用,也可以创建一个实例来使用。
- QFileDialog的静态方法返回的是一个元组,第一个元素是文件名,第二个元素是文件类型。
后记
当然,作为一个程序员,我对前面那个弱智玩意有很多不满意的地方,没办法,只好增加了代码语法高亮、行号、当前行高亮。
这亿点点细节就只有下次再写。