Caeta
Caeta

Reputation: 461

How avoid change tab in QTabWidget | PyQt5

I'm trying to implement a tab with the name "+" in which if I click on it opens a ApplicationModal window for configurate the content in that tab. I want to avoid the change of tab when i click in it until press "Accept" in the ApplicationModal window. How can I block this change? I don't know if I explain me.

enter image description here

This it's de code

tabs.py for the MainWindow

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(628, 504)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setGeometry(QtCore.QRect(36, 34, 541, 396))
        self.tabWidget.setObjectName("tabWidget")
        self.tab1 = QtWidgets.QWidget()
        self.tab1.setObjectName("tab1")
        self.tabWidget.addTab(self.tab1, "")
        self.tab2 = QtWidgets.QWidget()
        self.tab2.setObjectName("tab2")
        self.tabWidget.addTab(self.tab2, "")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 628, 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)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab1), _translate("MainWindow", "Tab 1"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab2), _translate("MainWindow", "+"))

win0.py for the ApplicationModal window

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Win0(object):
    def setupUi(self, Win0):
        Win0.setObjectName("Win0")
        Win0.setWindowModality(QtCore.Qt.ApplicationModal)
        Win0.resize(255, 203)
        self.centralwidget = QtWidgets.QWidget(Win0)
        self.centralwidget.setObjectName("centralwidget")
        self.comboBox = QtWidgets.QComboBox(self.centralwidget)
        self.comboBox.setGeometry(QtCore.QRect(17, 9, 154, 22))
        self.comboBox.setObjectName("comboBox")
        self.accpet_button = QtWidgets.QPushButton(self.centralwidget)
        self.accpet_button.setGeometry(QtCore.QRect(43, 130, 75, 23))
        self.accpet_button.setObjectName("accpet_button")
        self.cancel_button = QtWidgets.QPushButton(self.centralwidget)
        self.cancel_button.setGeometry(QtCore.QRect(135, 131, 75, 23))
        self.cancel_button.setObjectName("cancel_button")
        Win0.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(Win0)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 255, 21))
        self.menubar.setObjectName("menubar")
        Win0.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(Win0)
        self.statusbar.setObjectName("statusbar")
        Win0.setStatusBar(self.statusbar)

        self.retranslateUi(Win0)
        QtCore.QMetaObject.connectSlotsByName(Win0)

    def retranslateUi(self, Win0):
        _translate = QtCore.QCoreApplication.translate
        Win0.setWindowTitle(_translate("Win0", "New Window"))
        self.accpet_button.setText(_translate("Win0", "Accept"))
        self.cancel_button.setText(_translate("Win0", "Cancel"))

And the main.py for develop the functionality

from tabs import Ui_MainWindow
from win0 import Ui_Win0
from PyQt5 import QtCore, QtGui, QtWidgets

class Win0(Ui_Win0):
    win0 = None
    def __init__(self, win):
        self.win0 = win
        super().__init__()
        self.setupUi(self.win0)

class Main(Ui_MainWindow):
    win0 = None
    win1 = None
    def __init__(self, win):
        self.win = win
        super().__init__()
        self.setupUi(self.win)
        self.tabWidget.tabBarClicked.connect(self.tabClick)

    def tabClick(self, event):
        if event == 1:
            print("New tab")
            self.win1 = QtWidgets.QMainWindow()
            new_window = Win0(self.win1)
            self.win1.show()

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

Upvotes: 0

Views: 487

Answers (1)

musicamante
musicamante

Reputation: 48231

If you want a window that blocks the others until it's closed, you're looking for a modal dialog.

A modal window creates a mode that disables the main window but keeps it visible, with the modal window as a child window in front of it. Users must interact with the modal window before they can return to the parent application. This avoids interrupting the workflow on the main window.

[From the wikipedia article about modal windows]

It is relatively easy to achieve that in Qt, by using a QDialog.

Designer already provides two basic templates with basic Ok/Cancel buttons when you create a new form, so create a new dialog with buttons on right or bottom (this will automatically connect the button box with the dialog's accept/reject slots), add the combobox, save and convert the file with pyuic (in the following example, I exported the file as dialog.py and used the default Ui_Dialog).

Then the implementation is very easy. The important thing is to add the parent argument to the QDialog instance: this ensures that the dialog uses the parent as a reference for the "window modality", so that that parent is blocked until the dialog is closed by accepting or rejecting it (rejection is usually done by clicking on a RejectRole button like Cancel or by closing the dialog in any way, including pressing Esc).

Do note that I changed your approach by using multiple inheritance in order to make things easier (see the guidelines on using Designer about this approach, which is usually the better and most suggested method when using pyuic generated files).

from tabs import Ui_MainWindow
from dialog import Ui_Dialog
from PyQt5 import QtCore, QtGui, QtWidgets

class SelectDialog(QtWidgets.QDialog, Ui_Dialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)


class Main(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.tabWidget.tabBarClicked.connect(self.tabClick)

    def tabClick(self, tab):
        if tab == 1:
            dialog = SelectDialog(self)
            if dialog.exec_():
                print(dialog.comboBox.currentIndex())


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = Main()
    mainWindow.show()
    sys.exit(app.exec_())

Upvotes: 1

Related Questions