Home > Enterprise >  Feature stopped working after changing data in the dictionary Python/PyQt5
Feature stopped working after changing data in the dictionary Python/PyQt5

Time:12-10

I have everything sorted out with this little program of mine, however after I have inserted actual data i will be using into the dictionary, the button.setEnable(False) stopped working. Any ideas why?

code:

self.countBtn = QPushButton("Do something", self)
self.countBtn.clicked.connect(self.onButtonClick)

def onButtonClick(self):
        self.serversChecked = Worker()
        self.textOutput.clear()
        self.serversChecked.amount_of_servers.connect(self.setupUi)
        self.serversChecked.progress.connect(self.countCheckedServers)
        self.serversChecked.offline_servers.connect(self.toScreen)
        self.serversChecked.pbar_step.connect(self.pbar_step)
        self.serversChecked.amount_of_servers.connect(self.maxPbar)
        self.serversChecked.start()
        self.countBtn.setEnabled(False)
        self.serversChecked.finished.connect(
            lambda: self.countBtn.setEnabled(True)
        )

This is all code i believe to be relevant, if more is needed, i can provide that.

Any ideas are welcome, as I am puzzled...

EDIT: as reqeusted, rest of code:

import sys, os, subprocess

from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPlainTextEdit,
    QPushButton,
    QVBoxLayout,
    QWidget,
    QProgressBar
)

class Worker(QThread):
    finished = pyqtSignal(str)
    progress = pyqtSignal(int)
    offline_servers = pyqtSignal(str)
    amount_of_servers = pyqtSignal(int)
    pbar_step = pyqtSignal(float)
    start_long_task = pyqtSignal(int)

    ips = {
        '001' : '142.250.178.14', '002' : '104.18.2.89', '003' : '10.251.63.23'
    }
    amount_of_servers_int = len(ips)

    def run(self):
        self.start_long_task.emit(1)
        amount_of_servers_int = len(self.ips)
        self.amount_of_servers.emit(amount_of_servers_int)

        with open(os.devnull, 'w') as DEVNULL:
            server = 0
            pbar_progress = 0
            for x, y in self.ips.items():
                try:
                    subprocess.check_call(
                    ['ping', '-n', '1', y],
                    stdout=DEVNULL,  # suppress output
                    stderr=DEVNULL
                    )
                except subprocess.CalledProcessError:
                    nextServer = (working output here)
                    self.offline_servers.emit(nextServer)
                server = server   1
                pbar_progress = pbar_progress   1
                self.pbar_step.emit(pbar_progress)
                self.progress.emit(server)
        self.finished.emit('') 

class Window(QMainWindow):  

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi()
        
    def setupUi(self):
        self.setWindowTitle("")
        self.resize(300, 400)
        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)
        
        self.textOutput = QPlainTextEdit(self)
        self.textOutput.setReadOnly(True)
        self.textOutput.resize(280, 300)
        self.textOutput.move(10, 5)

        self.serversCheckedtoScreen = QLabel("Checked: ", self)
        self.serversCheckedtoScreen.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        
        self.pbar = QProgressBar(self, objectName="progressBar")  
        self.pbar.setGeometry(200, 80, 280, 20)
        self.pbar.setValue(0)
        self.pbar.setMinimum(0)
        
        self.countBtn = QPushButton("Check Servers", self)
        self.countBtn.clicked.connect(self.onButtonClick)
        # Set the layout
        layout = QVBoxLayout()
        layout.addWidget(self.textOutput)
        layout.addWidget(self.serversCheckedtoScreen)
        layout.addWidget(self.pbar)
        layout.addWidget(self.countBtn)

        self.pbar.setStyleSheet("""
        QWidget {
            text-align: center;
            }
        """)
        self.centralWidget.setLayout(layout)

    def onButtonClick(self):
        self.serversChecked = Worker()
        self.textOutput.clear()
################This is the issue as pointed out by @musicamante ##########
        **self.serversChecked.amount_of_servers.connect(self.setupUi)**
################This piece of code shouldnt even be here, code blindness is a thing #####
        self.serversChecked.progress.connect(self.countCheckedServers)
        self.serversChecked.offline_servers.connect(self.toScreen)
        self.serversChecked.pbar_step.connect(self.pbar_step)
        self.serversChecked.amount_of_servers.connect(self.maxPbar)
        self.serversChecked.start_long_task.connect(self.disableButton)
        self.serversChecked.start()

        self.countBtn.setEnabled(False) ##### WHY IT DOESNT WORK

        self.serversChecked.finished.connect(
            lambda: self.countBtn.setEnabled(True)
        )

    def countCheckedServers(self, value):
        max = self.serversChecked.amount_of_servers_int
        self.serversCheckedtoScreen.setText(f"Servers Checked: {value} / "   str(max))

    def toScreen(self, value):
        self.textOutput.appendPlainText(value)
    
    def pbar_step(self, value):
        self.pbar.setValue(int(value))

    def maxPbar(self,value):
        self.pbar.setMaximum(value)
    
    def disableButton(self, n): # added extra function to check but makes no difference
        if n == 1:
            self.countBtn.setDisabled(True)

app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

CodePudding user response:

As correctly pointed out by @musicamante in the comments, I have left a line of code under

def onButtonClick(self):
        self.serversChecked = Worker()
        self.textOutput.clear()

After removing

self.serversChecked.amount_of_servers.connect(self.setupUi)

As per his advise the problem has been solved. I have asked him to create an asnwer so I can credit him and I hope he does so soon. As such i am not marking as complete yet.

Copy of his original comment in the meantime:

You're calling self.setupUi everytime the worker is started, so you're creating a new UI. That signal is not emitted instantly, but asynchronously. So, the button is disabled, but right after that the thread is actually started, which creates a new UI, with an enabled button. Remove self.serversChecked.amount_of_servers.connect(self.setupUi).

Sadly, code blindness is a thing, however, there are some remarkable people willing to help. Again, Thank you @musicamante

  • Related