Adding a file selection dialog
In this chapter we will learn how to use default dialogs to allow the user to select the input and output files.
Selecting the input file
When the button next to the input file lineEdit is pressed, we want the program to show a file selection dialog for the user to select the input file.
The first step is to create a callback function:
def onInputFileButtonClicked(self):
pass
Then, we connect it to the clicked button event:
self.inputFileButton.clicked.connect(self.onInputFileButtonClicked)
Now, we can create a dialog inside the callback, to be presented to the user when the inputFileButton is pressed:
def onInputFileButtonClicked(self):
filename, filter = QtGui.QFileDialog.getOpenFileName(parent=self, caption='Open file', dir='.', filter='*.kicad_pcb')
As arguments, we pass the parent widget (the window), the caption that will appear on the dialog title bar, the current directory and a filter that restricts the supported files to be *.kicad_pcb files. Once the dialog is closed, the function will return the file path of the selected file, as well as the filter corresponding to that file.
If the user cancels the dialog, it will return an empty string. We have to check this in order to discard that input. Once we know the file path is not empty, we place it on the inputFileLineEdit:
def onInputFileButtonClicked(self):
filename, filter = QtGui.QFileDialog.getOpenFileName(parent=self, caption='Open file', dir='.', filter='Kicad PCB Files (*.kicad_pcb)')
if filename:
self.inputFileLineEdit.setText(filename)
Selecting the output file
When the user selects the button "Export", a dialog should appear that allows him to select an output file. For this, we will create again a callback function associated to the exportButton.
Inside this callback, we will use another default dialog to allow the selection of the output file:
def onExportButtonClicked(self):
filename, filter = QtGui.QFileDialog.getSaveFileName(parent=self, caption='Select output file', dir='.', filter='Kicad PCB Files (*.kicad_pcb)')
if filename:
print filename
We will add another check to make sure the file has the correct extension:
if filename:
if '.kicad_pcb' != filename[-10:]:
filename += '.kicad_pcb'
print filename
Bonus: overwrite confirmation dialog
The output file selection will provide us automatically a confirmation dialog if the selected file already exists. On the other hand, the save button, whose default behavior is to overwrite files, does not have such a nice dialog to prevent overwriting files by mistake.
We can add such a dialog with a QtGui.QMessageBox:
def onSaveButtonClicked(self):
reply = QtGui.QMessageBox.question(parent=self, title='Attention',
text='File will be overwritten.\nDo you still want to proceed?',
buttons=QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
defaultButton=QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
filename = self.inputFileLineEdit.text()
length = self.lengthSpinBox.value()
width = self.widthSpinBox.value()
line_width = self.lineWidthSpinBox.value()
rounded = self.cornersCheckBox.isChecked()
corners_radius = self.cornersSpinBox.value()
x = self.xSpinBox.value()
y = self.ySpinBox.value()
print "Values are: "
print "Filename: %s" % filename
print "Length: %.2f Width: %.2f" % (length, width)
print "Line width: %.2f" % line_width
if corners_radius:
print "Corner radius: %.2f" % corners_radius
print "x: %.2f y: %.2f" % (x, y)
Complete code
from PySide import QtCore,QtGui
from PySide import QtUiTools
import os, sys
def load_ui(file_name, where=None):
"""
Loads a .UI file into the corresponding Qt Python object
:param file_name: UI file path
:param where: Use this parameter to load the UI into an existing class (i.e. to override methods)
:return: loaded UI
"""
# Create a QtLoader
loader = QtUiTools.QUiLoader()
# Open the UI file
ui_file = QtCore.QFile(file_name)
ui_file.open(QtCore.QFile.ReadOnly)
# Load the contents of the file
ui = loader.load(ui_file, where)
# Close the file
ui_file.close()
return ui
class PCBOutlineCreator(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUI()
self.resetValues()
def setupUI(self):
# Load UI and set it as main layout
ui_file_path = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'PCBOutlineCreator.ui')
main_widget = load_ui(ui_file_path, self)
layout = QtGui.QVBoxLayout()
layout.addWidget(main_widget)
self.setLayout(layout)
# Get a reference to all required widgets
self.inputFileButton = self.findChild(QtGui.QToolButton, 'inputFileButton')
self.inputFileLineEdit = self.findChild(QtGui.QLineEdit, 'inputFileLineEdit')
self.exportButton = self.findChild(QtGui.QPushButton, 'exportButton')
self.saveButton = self.findChild(QtGui.QPushButton, 'saveButton')
self.lengthSpinBox = self.findChild(QtGui.QDoubleSpinBox, 'lengthSpinBox')
self.widthSpinBox = self.findChild(QtGui.QDoubleSpinBox, 'widthSpinBox')
self.lineWidthSpinBox = self.findChild(QtGui.QDoubleSpinBox, 'lineWidthSpinBox')
self.cornersSpinBox = self.findChild(QtGui.QDoubleSpinBox, 'cornersSpinBox')
self.cornersCheckBox = self.findChild(QtGui.QCheckBox, 'cornersCheckBox')
self.xSpinBox = self.findChild(QtGui.QDoubleSpinBox, 'xSpinBox')
self.ySpinBox = self.findChild(QtGui.QDoubleSpinBox, 'ySpinBox')
# Configure widget ranges:
max_float = sys.float_info.max
self.lengthSpinBox.setMinimum(0)
self.lengthSpinBox.setMaximum(max_float)
self.widthSpinBox.setMinimum(0)
self.widthSpinBox.setMaximum(max_float)
self.lineWidthSpinBox.setMinimum(0)
self.lineWidthSpinBox.setMaximum(max_float)
self.lineWidthSpinBox.setSingleStep(0.1)
self.cornersSpinBox.setMinimum(0)
self.cornersSpinBox.setMaximum(max_float)
self.xSpinBox.setMinimum(-max_float)
self.xSpinBox.setMaximum(max_float)
self.ySpinBox.setMinimum(-max_float)
self.ySpinBox.setMaximum(max_float)
# Connect slots/callbacks and signals
self.cornersSpinBox.setEnabled(False)
self.cornersCheckBox.stateChanged.connect(self.onCornersCheckBoxChangedState)
self.saveButton.clicked.connect(self.onSaveButtonClicked)
self.inputFileButton.clicked.connect(self.onInputFileButtonClicked)
self.exportButton.clicked.connect(self.onExportButtonClicked)
def resetValues(self):
self.lengthSpinBox.setValue(50)
self.widthSpinBox.setValue(50)
self.lineWidthSpinBox.setValue(0.2)
self.cornersCheckBox.setChecked(False)
self.cornersSpinBox.setValue(5)
self.xSpinBox.setValue(0)
self.ySpinBox.setValue(0)
def onCornersCheckBoxChangedState(self, checked):
self.cornersSpinBox.setEnabled(bool(checked))
def onSaveButtonClicked(self):
reply = QtGui.QMessageBox.question(parent=self, title='Attention',
text='File will be overwritten.\nDo you still want to proceed?',
buttons=QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
defaultButton=QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
filename = self.inputFileLineEdit.text()
length = self.lengthSpinBox.value()
width = self.widthSpinBox.value()
line_width = self.lineWidthSpinBox.value()
rounded = self.cornersCheckBox.isChecked()
corners_radius = self.cornersSpinBox.value()
x = self.xSpinBox.value()
y = self.ySpinBox.value()
print "Values are: "
print "Filename: %s" % filename
print "Length: %.2f Width: %.2f" % (length, width)
print "Line width: %.2f" % line_width
if corners_radius:
print "Corner radius: %.2f" % corners_radius
print "x: %.2f y: %.2f" % (x, y)
def onInputFileButtonClicked(self):
filename, filter = QtGui.QFileDialog.getOpenFileName(parent=self, caption='Open file', dir='.', filter='Kicad PCB Files (*.kicad_pcb)')
if filename:
self.inputFileLineEdit.setText(filename)
def onExportButtonClicked(self):
filename, filter = QtGui.QFileDialog.getSaveFileName(parent=self, caption='Select output file', dir='.', filter='Kicad PCB Files (*.kicad_pcb)')
if filename:
if '.kicad_pcb' != filename[-10:]:
filename += '.kicad_pcb'
print filename, filter
if __name__ == '__main__':
# Create Qt app
app = QtGui.QApplication(sys.argv)
# Create the widget and show it
gui = PCBOutlineCreator()
gui.show()
# Run the app
sys.exit(app.exec_())