Активации кнопки если происходят изменение в окне

Есть пользовательское окно (открытие - меню -> опции -> настройки -> пользовательские настройки), там есть 2 кнопки: Применить и Отмена.

Кнопка Применить находится в неактивном состояние. Так вот в чём суть, как её сделать активной, если например пользователь снял галку с виджета QCheckBox или сменил кнопку QRadioButton и т.д.?

Буду благодарен:

код:

from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
import sys


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        QtWidgets.QMainWindow.__init__(self);

        self.centralWidget = QtWidgets.QWidget() # создаём центральный виджет
        self.setCentralWidget(self.centralWidget)
        self.mainLayout = QtWidgets.QVBoxLayout(self.centralWidget)
        
        # settings
        self.setFixedSize(600, 640)
        self.setWindowTitle(" B U G ")

        # делаем сборку
        self.widget_main = self.createPage()
        self.mainLayout.addWidget(self.widget_main)
        self.createMenuBar()
        self.createToolBar()

        self.status_1.showMessage("Добро пожаловать", msecs = 4000)
        self.setStatusBar(self.status_1)

        
    def createPage(self):
        """создание страницы в основном окне """

        self.widget_page = QtWidgets.QWidget()

        # создание обьектов
        self.button_1 = QtWidgets.QPushButton("Перейти к поиску телефонных\
                                            \nномеров и электронных почт")
        self.formbox = QtWidgets.QGridLayout()

        # добавление в box и в окно
        self.formbox.addWidget(self.button_1)
        self.formbox.setSpacing(20)
        self.widget_page.setLayout(self.formbox)

        return self.widget_page


    def createMenuBar(self):

        # создание панели-меню и строки состоянии
        self.menu = QtWidgets.QMenuBar()
        self.status_1 = QtWidgets.QStatusBar()

        # создание категорий меню и функционал в ней
        self.menu_options = QtWidgets.QMenu("Опции")

        # просто настройки
        self.sub_menu_options = QtWidgets.QMenu("Настройки")
        self.user_settings = QtWidgets.QAction("Пользовательские настройки")
        self.sub_menu_options.addAction(self.user_settings)
        self.menu_options.addMenu(self.sub_menu_options)

        # добавляем отдельное меню в главное меню
        self.menu.addMenu(self.menu_options)

        # датчики
        self.user_settings.triggered.connect(self.clickedActionUser)

        # добавляем в окно
        self.setMenuBar(self.menu)


    def createToolBar(self):
        self.toolBar = QtWidgets.QToolBar()

        self.toolButton_back = QtWidgets.QAction("Вернуться назад")
        self.toolButton_run_file = QtWidgets.QAction("Открыть файл")
        self.toolButton_run_file.setEnabled(False)
        
        self.toolBar.addAction(self.toolButton_back)
        self.toolBar.addAction(self.toolButton_run_file)

        self.addToolBar(self.toolBar)


    def clickedActionUser(self):
        self.My_WindowSettings = WindowSettings()
        self.My_WindowSettings.show()



class WindowSettings(QtWidgets.QWidget):
    """Класс реализующий пользовательские настройки
        в виде выводящего окна """

    def __init__(self, parent = None):
        QtWidgets.QWidget.__init__(self, parent)
        self.parent = parent

        # settings
        self.setFixedSize(480, 550)
        self.setWindowTitle("Пользовательские настройки")
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.setWindowModality(QtCore.Qt.ApplicationModal)

        # делаем сборку
        self.createPage()


    def createPage(self):
        self.gridBox = QtWidgets.QGridLayout()
        self.hBox = QtWidgets.QHBoxLayout()

        self.tabWidget = QtWidgets.QTabWidget()
        self.button_save = QtWidgets.QPushButton("Применить")
        self.button_save.setEnabled(False)
        self.button_exit = QtWidgets.QPushButton("Отмена")
    
        self.hBox.addWidget(self.button_exit)
        self.hBox.addWidget(self.button_save)

        self.gridBox.addWidget(self.tabWidget, 0, 0)
        self.gridBox.addItem(self.hBox, 1, 0, alignment = QtCore.Qt.AlignRight)
        self.setLayout(self.gridBox)

        # сборка tab-виджетов
        self.createTabWidget_Search()


    def createTabWidget_Search(self):
        self.tabWidget_1 = QtWidgets.QWidget()
        self.formBox_1 = QtWidgets.QFormLayout()
        self.formBox_1.setVerticalSpacing(17)
        self.formBox_1.setFieldGrowthPolicy(QtWidgets.QFormLayout.FieldsStayAtSizeHint)

        # настройка формата файла
        self.groupBoxFormatFile = QtWidgets.QGroupBox("Формат файла для сохранения данных")
        self.groupBoxFormatFile.setFlat(True)
        
        self.hBoxFormat = QtWidgets.QHBoxLayout()

        self.checkFileBoxTxt = QtWidgets.QCheckBox("txt")
        self.checkFileBoxTxt.setChecked(True)
        self.checkFileBoxCsv = QtWidgets.QCheckBox("csv")

        self.hBoxFormat.addWidget(self.checkFileBoxTxt)
        self.hBoxFormat.addWidget(self.checkFileBoxCsv)

        self.groupBoxFormatFile.setLayout(self.hBoxFormat)
        self.formBox_1.addWidget(self.groupBoxFormatFile)

        # настройки запуска файла после сохранение
        self.groupBoxRunFile = QtWidgets.QGroupBox("Запуск файла после сохранения")
        self.groupBoxRunFile.setFlat(True)

        self.hBoxRun = QtWidgets.QHBoxLayout()

        self.radioRunFile_Yes = QtWidgets.QRadioButton("Да")
        self.radioRunFile_No = QtWidgets.QRadioButton("Нет")
        self.radioRunFile_No.setChecked(True)

        self.hBoxRun.addWidget(self.radioRunFile_Yes)
        self.hBoxRun.addWidget(self.radioRunFile_No)

        self.groupBoxRunFile.setLayout(self.hBoxRun)
        self.formBox_1.addWidget(self.groupBoxRunFile)


        self.tabWidget_1.setLayout(self.formBox_1)
        self.tabWidget.addTab(self.tabWidget_1, "настройки поиска")




if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = MainWindow() 
    MainWindow.show()
    sys.exit(app.exec_())

Ответы (2 шт):

Автор решения: Alexander Chernin
class WindowSettings(QtWidgets.QWidget):
    def enableApplyButton(self):
        self.self.button_save.setEnable(True)

    def createTabWidget_Search(self):
        self.checkFileBoxTxt.stateChanged.connect(self.enableApplyButton)
        self.checkFileBoxCsv.stateChanged.connect(self.enableApplyButton)

        self.radioRunFile_Yes.toggled.connect(self.enableApplyButton)
        self.radioRunFile_No.toggled.connect(self.enableApplyButton)

Можно сгруппировать радио в QButtonGroup:

def createTabWidget_Search(self):
    self.buttonGroup = QButtonGroup()
    self.buttonGroup.addButton(self.radioRunFile_Yes)
    self.buttonGroup.addButton(self.radioRunFile_No)

    self.buttonGroup.buttonToggled.connect(self.enableApplyButton)
→ Ссылка
Автор решения: S. Nick

[signal]void QCheckBox::stateChanged(int state)

Этот сигнал испускается всякий раз, когда состояние флажка изменяется, то есть всякий раз, когда пользователь проверяет или снимает его.

[signal]void QAbstractButton::toggled(bool checked)

Этот сигнал испускается всякий раз, когда проверяемая кнопка меняет свое состояние. флажок true, если кнопка отмечена, или false, если кнопка не отмечена.


и делайте проверки какие вам надо.

from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
import sys


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        QtWidgets.QMainWindow.__init__(self);

        self.centralWidget = QtWidgets.QWidget() # создаём центральный виджет
        self.setCentralWidget(self.centralWidget)
        self.mainLayout = QtWidgets.QVBoxLayout(self.centralWidget)
        
        # settings
        self.setFixedSize(600, 640)
        self.setWindowTitle(" B U G ")

        # делаем сборку
        self.widget_main = self.createPage()
        self.mainLayout.addWidget(self.widget_main)
        self.createMenuBar()
        self.createToolBar()

        self.status_1.showMessage("Добро пожаловать", msecs = 4000)
        self.setStatusBar(self.status_1)

        
    def createPage(self):
        """создание страницы в основном окне """

        self.widget_page = QtWidgets.QWidget()

        # создание обьектов
        self.button_1 = QtWidgets.QPushButton("Перейти к поиску телефонных\
                                            \nномеров и электронных почт")
        self.formbox = QtWidgets.QGridLayout()

        # добавление в box и в окно
        self.formbox.addWidget(self.button_1)
        self.formbox.setSpacing(20)
        self.widget_page.setLayout(self.formbox)

        return self.widget_page


    def createMenuBar(self):

        # создание панели-меню и строки состоянии
        self.menu = QtWidgets.QMenuBar()
        self.status_1 = QtWidgets.QStatusBar()

        # создание категорий меню и функционал в ней
        self.menu_options = QtWidgets.QMenu("Опции")

        # просто настройки
        self.sub_menu_options = QtWidgets.QMenu("Настройки")
        self.user_settings = QtWidgets.QAction("Пользовательские настройки")
        self.sub_menu_options.addAction(self.user_settings)
        self.menu_options.addMenu(self.sub_menu_options)

        # добавляем отдельное меню в главное меню
        self.menu.addMenu(self.menu_options)

        # датчики
        self.user_settings.triggered.connect(self.clickedActionUser)

        # добавляем в окно
        self.setMenuBar(self.menu)


    def createToolBar(self):
        self.toolBar = QtWidgets.QToolBar()

        self.toolButton_back = QtWidgets.QAction("Вернуться назад")
        self.toolButton_run_file = QtWidgets.QAction("Открыть файл")
        self.toolButton_run_file.setEnabled(False)
        
        self.toolBar.addAction(self.toolButton_back)
        self.toolBar.addAction(self.toolButton_run_file)

        self.addToolBar(self.toolBar)


    def clickedActionUser(self):
        self.My_WindowSettings = WindowSettings()
        self.My_WindowSettings.show()



class WindowSettings(QtWidgets.QWidget):
    """Класс реализующий пользовательские настройки
        в виде выводящего окна """

    def __init__(self, parent = None):
        QtWidgets.QWidget.__init__(self, parent)
        self.parent = parent

        # settings
        self.setFixedSize(480, 550)
        self.setWindowTitle("Пользовательские настройки")
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.setWindowModality(QtCore.Qt.ApplicationModal)

        # делаем сборку
        self.createPage()


    def createPage(self):
        self.gridBox = QtWidgets.QGridLayout()
        self.hBox = QtWidgets.QHBoxLayout()

        self.tabWidget = QtWidgets.QTabWidget()
        self.button_save = QtWidgets.QPushButton("Применить")
        self.button_save.setEnabled(False)
        self.button_exit = QtWidgets.QPushButton("Отмена")
    
        self.hBox.addWidget(self.button_exit)
        self.hBox.addWidget(self.button_save)

        self.gridBox.addWidget(self.tabWidget, 0, 0)
        self.gridBox.addItem(self.hBox, 1, 0, alignment = QtCore.Qt.AlignRight)
        self.setLayout(self.gridBox)

        # сборка tab-виджетов
        self.createTabWidget_Search()


    def createTabWidget_Search(self):
        self.tabWidget_1 = QtWidgets.QWidget()
        self.formBox_1 = QtWidgets.QFormLayout()
        self.formBox_1.setVerticalSpacing(17)
        self.formBox_1.setFieldGrowthPolicy(QtWidgets.QFormLayout.FieldsStayAtSizeHint)

        # настройка формата файла
        self.groupBoxFormatFile = QtWidgets.QGroupBox("Формат файла для сохранения данных")
        self.groupBoxFormatFile.setFlat(True)
        
        self.hBoxFormat = QtWidgets.QHBoxLayout()

        self.checkFileBoxTxt = QtWidgets.QCheckBox("txt")
###
        self.checkFileBoxTxt.setChecked(True)
        self.checkFileBoxTxt.stateChanged.connect(self.on_state_change_func)      # +++


#        self.checkFileBoxTxt.setChecked(True)
        self.checkFileBoxCsv = QtWidgets.QCheckBox("csv")

        self.hBoxFormat.addWidget(self.checkFileBoxTxt)
        self.hBoxFormat.addWidget(self.checkFileBoxCsv)

        self.groupBoxFormatFile.setLayout(self.hBoxFormat)
        self.formBox_1.addWidget(self.groupBoxFormatFile)

        # настройки запуска файла после сохранение
        self.groupBoxRunFile = QtWidgets.QGroupBox("Запуск файла после сохранения")
        self.groupBoxRunFile.setFlat(True)

        self.hBoxRun = QtWidgets.QHBoxLayout()

        self.radioRunFile_Yes = QtWidgets.QRadioButton("Да")
###
        self.radioRunFile_Yes.toggled.connect(self.on_off_bulb_func)                 # +++


        self.radioRunFile_No = QtWidgets.QRadioButton("Нет")
        self.radioRunFile_No.setChecked(True)

        self.hBoxRun.addWidget(self.radioRunFile_Yes)
        self.hBoxRun.addWidget(self.radioRunFile_No)

        self.groupBoxRunFile.setLayout(self.hBoxRun)
        self.formBox_1.addWidget(self.groupBoxRunFile)


        self.tabWidget_1.setLayout(self.formBox_1)
        self.tabWidget.addTab(self.tabWidget_1, "настройки поиска")
        
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    def on_state_change_func(self, state):
        #print(state)
        self.button_save_on()
        
    def on_off_bulb_func(self, state):
        #print(state)
        self.button_save_on()        

    def button_save_on(self):
       self.button_save.setEnabled(True)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = MainWindow() 
    MainWindow.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка