pythonpython-3.xpyqtpyqt5qwizardpage

Disable default focus on a QWizardPage's next button and let a custom QPushButton be triggered by 'enter' instead


I'm working on a QWizardPage where the user can search for packages to install. Therefore I provided a search button (a QPushButton) and a QLineEdit (as the search button's buddy()).

My problem is, that the wizard's next button has focus all the time. But for this specific page I want the QLineEdit to have focus by default, and that return or enter triggers the search button instead.

I already tried setDefault(True) and setFocus() on the QLineEdit, but that doesn't work. I read through the documentation but couldn't find a way to access QWizardPage's next button in PyQt5. I thought maybe there's something like autofocus(False) for disabling it on a specific wizard page.

How can I set focus on a QLineEdit inside a QWizardPage and let return or enter trigger a custom QPushButton?


Code to reproduce:

# -*- coding: utf-8 -*-
from PyQt5.QtGui import QIcon, QStandardItemModel, QStandardItem
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot, QObject, QTimer, QThread
from PyQt5.QtWidgets import (QApplication, QProgressBar, QGridLayout, QLabel,
                             QFileDialog, QHBoxLayout, QVBoxLayout, QDialog,
                             QWizard, QWizardPage, QToolButton, QComboBox,
                             QCheckBox, QLineEdit, QGroupBox, QTableView,
                             QAbstractItemView, QFrame, QPushButton)

# ...

#]===========================================================================[#
#] WIZARD [#=================================================================[#
#]===========================================================================[#

class VenvWizard(QWizard):
    """
    Wizard for creating and setting up a virtual environment.
    """
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Venv Wizard")
        self.resize(635, 480)
        self.move(528, 153)

        self.setStyleSheet(
            """
            QToolTip {
                background-color: rgb(47, 52, 63);
                border: rgb(47, 52, 63);
                color: rgb(210, 210, 210);
                padding: 2px;
                opacity: 325
            }

            QTableView {
                gridline-color: rgb(230, 230, 230)
            }

            QTableView::item {
                selection-background-color: rgb(120, 120, 130);
                selection-color: rgb(255, 255, 255)
            }
            """
        )

        self.addPage(InstallPackages())
        self.addPage(Summary())

        # ...


class InstallPackages(QWizardPage):
    """
    Install packages via `pip` into the created virtual environment.
    """
    def __init__(self):
        super().__init__()

        self.setTitle("Install Packages")
        self.setSubTitle(
            "Specify the packages you want to install into the "
            "virtual environment. Right-click on the item to "
            "mark it for installation and click next when ready."
        )

        #]===================================================================[#
        #] PAGE CONTENT [#===================================================[#
        #]===================================================================[#

        verticalLayout = QVBoxLayout()
        gridLayout = QGridLayout(self)

        pkgNameLabel = QLabel("Package name:")
        self.pkgNameLineEdit = QLineEdit()
        pkgNameLabel.setBuddy(self.pkgNameLineEdit)

        self.searchButton = QPushButton(
            "&Search",
            #clicked=self.list_packages
        )

        resultsTable = QTableView(
            selectionBehavior=QAbstractItemView.SelectRows,
            editTriggers=QAbstractItemView.NoEditTriggers,
            alternatingRowColors=True
        )

        # adjust vertical headers
        v_Header = resultsTable.verticalHeader()
        v_Header.setDefaultSectionSize(27.5)
        v_Header.hide()

        # adjust (horizontal) headers
        h_Header = resultsTable.horizontalHeader()
        h_Header.setDefaultAlignment(Qt.AlignLeft)
        h_Header.setDefaultSectionSize(150)
        h_Header.setStretchLastSection(True)

        # set table view model
        self.resultsModel = QStandardItemModel(0, 2, self)
        self.resultsModel.setHorizontalHeaderLabels(
            ["Name", "Version", "Description"]
        )
        resultsTable.setModel(self.resultsModel)

        gridLayout.addWidget(pkgNameLabel, 0, 0, 1, 1)
        gridLayout.addWidget(self.pkgNameLineEdit, 0, 1, 1, 1)
        gridLayout.addWidget(self.searchButton, 0, 2, 1, 1)
        gridLayout.addWidget(resultsTable, 1, 0, 1, 3)

        verticalLayout.addLayout(gridLayout)

        # ...


class Summary(QWizardPage):
    def __init__(self):
        super().__init__()

        self.setTitle("Summary")
        self.setSubTitle("..........................."
                         "...........................")

        #]===================================================================[#
        # TODO: create the summary page
        #]===================================================================[#

    def initializePage(self):
        pass



if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)

    wiz = VenvWizard()
    wiz.show()

    sys.exit(app.exec_())


Solution

  • You have to change the default property of the buttons a moment after being displayed, in this case you could use the initializePage() method of QWizardPage:

    # ...
    class InstallPackages(QWizardPage):
        # ...
        def initializePage(self):
            next_button = self.wizard().button(QWizard.NextButton)
            QTimer.singleShot(0, lambda: next_button.setDefault(False))
            QTimer.singleShot(0, lambda: self.searchButton.setDefault(True))
    # ...