When you use QFileDialog.getSaveFileName() in PyQt6, you can pass a default directory and file name as the third argument. This is great for pointing users to a specific folder, but there's a catch: once you hard-code a directory path, the dialog stops remembering where the user last saved a file.
In this tutorial, we'll look at how to get the best of both worlds — pre-filling a file name from your GUI and remembering the last-used directory between saves.
The Problem
Imagine you have a save dialog that always opens in D:\Data\ and pre-fills the file name from a QLineEdit in your interface:
fileName, _ = QFileDialog.getSaveFileName(
self,
"Save Measurement",
'D:\\Data\\' + self.ui.lineEditFileName.text(),
"(*.csv)",
options=options,
)
This works, but it always opens in D:\Data\ — even if the user navigated somewhere else during their last save. That's frustrating.
You might have noticed that if you pass an empty string "" as the third argument, QFileDialog automatically remembers the last directory. But then you lose the pre-filled file name. So you're stuck choosing between two useful behaviors.
The solution is to track the last-used directory yourself and combine it with the file name when opening the dialog.
Tracking the Last-Used Directory
The idea is straightforward:
- Store the current save folder in an instance variable, starting with your preferred default.
- Each time the user saves a file, update that variable with the directory they chose.
- When opening the dialog, combine the stored directory with the file name from your GUI.
Let's walk through each piece.
Set a Default Folder
In your window's __init__ method, create an instance variable to hold the active folder. Use a raw string or escape the backslashes on Windows paths:
self.active_folder = 'D:\\Data\\'
You could also use a raw string to avoid the double backslashes:
self.active_folder = r'D:\Data'
Or, for cross-platform friendliness, use os.path.join:
import os
self.active_folder = os.path.join('D:', os.sep, 'Data')
Build the Full Path When Saving
When you open the save dialog, combine self.active_folder with the file name from your QLineEdit using os.path.join():
import os
path = os.path.join(self.active_folder, self.ui.lineEditFileName.text())
fileName, _ = QFileDialog.getSaveFileName(
self,
"Save Measurement",
path,
"(*.csv)",
options=options,
)
This gives QFileDialog both a directory to open in and a pre-filled file name — exactly what we want.
Update the Folder After Saving
After the user picks a location and confirms the dialog, update self.active_folder with the directory from their chosen path. You should also check that they didn't cancel the dialog (which returns an empty string):
if fileName:
self.active_folder = os.path.dirname(fileName)
# ... proceed with saving the file
Now the next time the dialog opens, it will start in whatever folder the user last saved to.
Complete Working Example
Here's a full example that puts everything together. It has a QLineEdit for entering a file name and a "Save" button that opens the dialog:
import os
import sys
from PyQt6.QtWidgets import (
QApplication,
QFileDialog,
QHBoxLayout,
QLineEdit,
QMainWindow,
QPushButton,
QVBoxLayout,
QWidget,
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Save File Example")
# Default folder to open in — change this to suit your system.
self.active_folder = os.path.expanduser("~")
# Set up the UI.
self.file_name_input = QLineEdit()
self.file_name_input.setPlaceholderText("Enter a file name...")
self.file_name_input.setText("measurement")
save_button = QPushButton("Save As...")
save_button.clicked.connect(self.save_file)
input_layout = QHBoxLayout()
input_layout.addWidget(self.file_name_input)
input_layout.addWidget(save_button)
container = QWidget()
layout = QVBoxLayout()
layout.addLayout(input_layout)
container.setLayout(layout)
self.setCentralWidget(container)
def save_file(self):
# Combine the remembered folder with the file name from the input.
default_name = self.file_name_input.text()
path = os.path.join(self.active_folder, default_name)
file_name, _ = QFileDialog.getSaveFileName(
self,
"Save Measurement",
path,
"CSV Files (*.csv)",
)
if file_name:
# Update the active folder so next time we open here.
self.active_folder = os.path.dirname(file_name)
# This is where you'd actually write your file.
# For this example, we'll just create an empty file.
with open(file_name, "w") as f:
f.write("example,data\n")
print(f"Saved to: {file_name}")
print(f"Next dialog will open in: {self.active_folder}")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
Run this, type a file name, and click Save As.... The dialog opens in your home directory (or whatever you set as the default). Navigate to a different folder and save. Click Save As... again — the dialog now opens in the folder you just used, with the file name from the input field already filled in.
Persisting the Folder Between Sessions
The approach above remembers the folder for the lifetime of the application. If you want the folder to persist even after the user closes and reopens the app, you can use QSettings to store it:
from PyQt6.QtCore import QSettings
# In __init__, load the saved folder (or use a default):
settings = QSettings("MyCompany", "MyApp")
self.active_folder = settings.value("last_save_folder", os.path.expanduser("~"))
# After a successful save, store it:
if file_name:
self.active_folder = os.path.dirname(file_name)
settings = QSettings("MyCompany", "MyApp")
settings.setValue("last_save_folder", self.active_folder)
QSettings stores values in a platform-appropriate location (the Windows registry, a plist file on macOS, or a config file on Linux), so you don't need to manage config files yourself.
Summary
When you pass a hard-coded path to QFileDialog.getSaveFileName(), the dialog loses its ability to remember the last-used directory. By storing the folder yourself in an instance variable and combining it with os.path.join(), you get full control: a pre-filled file name and a dialog that opens where the user expects it to.
Create GUI Applications with Python & Qt6 by Martin Fitzpatrick
(PyQt6 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!