简体   繁体   中英

Add a proper FileDialog with Browse PushButton in PyQt5

I wrote the following code in order to do some calculations. I want to add a Widget like the small picture such that when I click on pushbutton I can browse a CSV file and that path is shown in a LineEdite. I need to have this Widger in the Experiment Info QGroupBox below the checkBox. But I do not know how to add all these 3 Widget in one row in this group box.

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, QMenu, QApplication
from PyQt5 import QtGui, QtCore
from PyQt5 import QtWidgets

class Application(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('File')
        run = menubar.addMenu('Run')
        exit = menubar.addMenu('Exit')

        impMenu = QMenu('Import', self)
        impAct = QAction('Import mail', self)
        impMenu.addAction(impAct)

        newAct = QAction('New', self)

        fileMenu.addAction(newAct)
        fileMenu.addMenu(impMenu)

        # ------------- Layout ---------------------------
        wid =QtWidgets.QWidget(self)
        self.setCentralWidget(wid)
        mainLayout = QtWidgets.QVBoxLayout()

        config_box = QtWidgets.QGroupBox("Configuration")
        info_box = QtWidgets.QGroupBox("Info Box")

        # ------------- Config Box Layut -----------------
        Config_Box_Layout = QtWidgets.QGridLayout()


        case_box = QtWidgets.QGroupBox("case")

        operations_box = QtWidgets.QGroupBox("Operations")

        Config_Box_Layout.addWidget(case_box, 0, 0)
        Config_Box_Layout.addWidget(operations_box, 0, 1)

        # ----------- Operations-----------------------
        operation_layout = QtWidgets.QVBoxLayout()

        op1 = QtWidgets.QCheckBox('Add')
        op2= QtWidgets.QCheckBox('Multiplication')

        operation_layout.addWidget(op1)
        operation_layout.addWidget(op2)
        # ----------- cases -----------------------
        case_layout = QtWidgets.QVBoxLayout()
        _1 = QtWidgets.QRadioButton("1")
        _2 = QtWidgets.QRadioButton("2")
        _3 = QtWidgets.QRadioButton("3")

        case_layout.addWidget(_1)
        case_layout.addWidget(_2)
        case_layout.addWidget(_3)


        # --------- Info Box LayOut -----------------------
        Info_box_layout = QtWidgets.QVBoxLayout()

        exp_input_grou = QtWidgets.QGroupBox('Experiment Info')
        exp_input_layout = QtWidgets.QVBoxLayout()

        version_input = QtWidgets.QComboBox()
        version_input.addItem("Algo Version")
        version_input.addItem("V53")
        version_input.addItem("V52")
        version_input.addItem("V4")
        version_input.addItem("V3")

        nested_folder = QtWidgets.QCheckBox('Nested Data Path')

        dialog_file = QtWidgets.QFileDialog()

        pushB_ = QtWidgets.QPushButton('Browse')

        exp_input_layout.addWidget(version_input)
        exp_input_layout.addWidget(nested_folder)
        exp_input_layout.addWidget(pushB_)
        exp_input_layout.addWidget(dialog_file)


        exp_report = QtWidgets.QTextEdit()
        progres_bar = QtWidgets.QProgressBar()


        Info_box_layout.addWidget(exp_input_grou)
        Info_box_layout.addWidget(exp_report)
        Info_box_layout.addWidget(progres_bar)

        gt_path = QtWidgets.QLineEdit()
        gt_path.setFixedWidth(100)
        # -------- Adding Layouts ------------------------
        mainLayout.addWidget(config_box)
        config_box.setLayout(Config_Box_Layout)
        case_box.setLayout(case_layout)
        operations_box.setLayout(operation_layout)
        info_box.setLayout(Info_box_layout)
        exp_input_grou.setLayout(exp_input_layout)

        mainLayout.addWidget(info_box)
        wid.setLayout(mainLayout)

        self.setGeometry(300, 300, 300, 700)
        self.setWindowTitle('Example')
        app_icon = QtGui.QIcon()
        app_icon.addFile('pic.jpg', QtCore.QSize(256, 256))
        self.setWindowIcon(app_icon)
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Application()
    sys.exit(app.exec_())

在此处输入图片说明 在此处输入图片说明

If you want to add widgets horizontally in a vertical layout, you have to add an horizontal layout to it. This technique is generally referred to as "nested layouts".

Then, you don't have to create a file dialog instance within the init (otherwise it will be probably shown along with the main window), and you don't have to use the QFileDialog() constructor for your needs, since QDialog already provides static methods that easily allow you to open a standard dialog and get the selected file(s) or directory.


class Application(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        # ...

        # --------- Info Box LayOut -----------------------
        Info_box_layout = QtWidgets.QVBoxLayout()

        exp_input_grou = QtWidgets.QGroupBox('Experiment Info')
        exp_input_layout = QtWidgets.QVBoxLayout()

        version_input = QtWidgets.QComboBox()
        version_input.addItem("Algo Version")
        version_input.addItem("V53")
        version_input.addItem("V52")
        version_input.addItem("V4")
        version_input.addItem("V3")

        nested_folder = QtWidgets.QCheckBox('Nested Data Path')

        # This should not be here!!!
        # dialog_file = QtWidgets.QFileDialog()

        exp_input_layout.addWidget(version_input)
        exp_input_layout.addWidget(nested_folder)

        

        # ...

    def browse_path(self):
        path, filter = QtWidgets.QFileDialog.getOpenFileName(self, 'Select file', 
            '', 'CSV files (*.csv);;All files (*)')
        if path:
            self.gt_path.setText(path)

QGridLayout is also a valid alternative, but it doesn't work fine with everything, as its sizes are always dependent on the size of widgets each row or column contains. Your case is very simple, so it can be used without problems:

    def initUI(self):
        # ...

        # --------- Info Box LayOut -----------------------
        Info_box_layout = QtWidgets.QVBoxLayout()

        exp_input_grou = QtWidgets.QGroupBox('Experiment Info')
        exp_input_layout = QtWidgets.QGridLayout()

        version_input = QtWidgets.QComboBox()
        version_input.addItem("Algo Version")
        version_input.addItem("V53")
        version_input.addItem("V52")
        version_input.addItem("V4")
        version_input.addItem("V3")

        nested_folder = QtWidgets.QCheckBox('Nested Data Path')

        self.gt_path = QtWidgets.QLineEdit()
        pushB_ = QtWidgets.QPushButton('Browse')
        pushB_.clicked.connect(self.browse_path)

        # add the combobox to the first row, first column, but set its column
        # span to 2, meaning that it occupies two "columns"
        exp_input_layout.addWidget(version_input, 0, 0, 1, 2)
        # the same for the checkbox, but on the second row
        exp_input_layout.addWidget(nested_folder, 1, 0, 1, 2)
        # add the line edit, third row, first column; if you don't specify the
        # span, the widget will only occupy one "cell" of the grid layout
        exp_input_layout.addWidget(self.gt_path, 2, 0)
        # and the button, same row, second column
        exp_input_layout.addWidget(pushB_, 2, 1)

        # ...

The below code will do what you want, you just need to implement it into your code:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(387, 224)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")

        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit.setReadOnly(True)

        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")

        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.open_file)

        self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
        self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
        self.gridLayout.addWidget(self.pushButton, 0, 2, 1, 1)

        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 387, 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.label.setText(_translate("MainWindow", "Select output file"))
        self.pushButton.setText(_translate("MainWindow", "..."))

    def open_file(self):
        self.file_name = QtWidgets.QFileDialog.getOpenFileName(None, "Open", "", "CSV Files (*.csv)")
        if self.file_name[0] != '':
            self.lineEdit.setText(self.file_name[0])


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Output:

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM