3

I noticed today that a Python script running in my PyCharm 2020.2 IDE on Windows 10, when I click on the X to quit, the main window disappears but PyCharm still shows its icon for a running script. After explicitly terminating the script in PyCharm the following error message appears.

Process finished with exit code -1

When the script in my PyCarm IDE is executed on Linux (Ubuntu), PyCharm does not show an icon for a running script after clicking on the X to exit the main window.

Why is this so?

Code

import sys
from datetime import datetime
import pythoncom

import wmi

from PyQt5. QtCore import QObject, QRunnable, QThreadPool, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QHeaderView


class KeyboardDetectorSignals(QObject):
    keyboard_changed = pyqtSignal(str)


class KeyboardDetector(QRunnable):

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

        self.signals = KeyboardDetectorSignals()

    def run(self):
        pythoncom.CoInitialize()
        device_connected_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_Keyboard\'"
        device_disconnected_wql = "SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_Keyboard\'"

        c = wmi.WMI()
        connected_watcher = c.watch_for(raw_wql=device_connected_wql)
        disconnected_watcher = c.watch_for(raw_wql=device_disconnected_wql)

        while True:
            try:
                connected = connected_watcher(timeout_ms=10)
            except wmi.x_wmi_timed_out:
                pass
            else:
                if connected:
                    self.signals.keyboard_changed.emit("Keyboard connected.")

            try:
                disconnected = disconnected_watcher(timeout_ms=10)
            except wmi.x_wmi_timed_out:
                pass
            else:
                if disconnected:
                    self.signals.keyboard_changed.emit("Keyboard disconnected.")


class MainWindow(QMainWindow):

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

        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle("Keyboard Logger")

        self.log_table = QTableWidget()
        self.log_table.setColumnCount(2)
        self.log_table.setShowGrid(True)
        self.log_table.setHorizontalHeaderLabels(["Time", "Event"])
        self.log_table.horizontalHeader().setStretchLastSection(True)
        self.log_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.setCentralWidget(self.log_table)
        self.show()

        self.threadpool = QThreadPool()
        keyboard_detector = KeyboardDetector()
        keyboard_detector.signals.keyboard_changed.connect(self.add_row)
        self.threadpool.start(keyboard_detector)

    def add_row(self, event: str):
        now = datetime.now()
        datetime_string = now.strftime("%Y-%m-%d %H:%M:%S")

        row_count = self.log_table.rowCount()
        self.log_table.insertRow(row_count)
        self.log_table.setItem(row_count, 0, QTableWidgetItem(datetime_string))
        self.log_table.setItem(row_count, 1, QTableWidgetItem(event))


def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
Asaf Amnony
  • 205
  • 1
  • 9
Atalanttore
  • 349
  • 5
  • 22
  • 2
    What happens when you run the script from the command prompt/terminal? Is the script still running after you close the QT Window? – Asaf Amnony Sep 22 '20 at 09:55
  • 1
    After closing the Qt window, the script continues running in the background. The command prompt/terminal also does not accept new commands after the window is closed. – Atalanttore Sep 23 '20 at 12:23

3 Answers3

2

Note that Process finished with exit code -1 isn't an error it just means your program was terminated.

  • exit code (0) means an exit without an errors or issues. exit code (1) means there was some issue / problem which caused the program to exit. The effect of each of these codes can vary between operating systems, but with Python should be fairly consistent. – Jatin Mehrotra Sep 18 '20 at 05:11
  • From what I know Python give an exit code of 0 when it runs successfully otherwise it gives an exit code of 1. While other programs which give an exit code of 0 when successful or anything other than 0 if not successful –  Sep 18 '20 at 05:36
1

I not sure but at the end of the code you can try write exit(1)

Manu Sampablo
  • 350
  • 5
  • 17
  • The script with `exit(1)` at the end unfortunately continues to run in the background after closing the Qt window. – Atalanttore Sep 25 '20 at 11:47
0

The friendly reddit user lolslim has finally solved this problem.

He changed the code as follows:

import sys
from datetime import datetime
import pythoncom

import wmi

from PyQt5. QtCore import QObject, QRunnable, QThreadPool, pyqtSignal
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QHeaderView


class KeyboardDetectorSignals(QObject):
    keyboard_changed = pyqtSignal(str)


class KeyboardDetector(QRunnable):

    def __init__(self):
        super().__init__()
        self._stop = False
        self.signals = KeyboardDetectorSignals()


    def stop(self):
        self._stop = True


    def run(self):
        pythoncom.CoInitialize()
        device_connected_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_Keyboard\'"
        device_disconnected_wql = "SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA \'Win32_Keyboard\'"

        c = wmi.WMI()
        connected_watcher = c.watch_for(raw_wql=device_connected_wql)
        disconnected_watcher = c.watch_for(raw_wql=device_disconnected_wql)

        while not self._stop:
            try:
                connected = connected_watcher(timeout_ms=10)
            except wmi.x_wmi_timed_out:
                pass
            else:
                if connected:
                    self.signals.keyboard_changed.emit("Keyboard connected.")

            try:
                disconnected = disconnected_watcher(timeout_ms=10)
            except wmi.x_wmi_timed_out:
                pass
            else:
                if disconnected:
                    self.signals.keyboard_changed.emit("Keyboard disconnected.")


class MainWindow(QMainWindow):

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

        self.setGeometry(100, 100, 500, 500)
        self.setWindowTitle("Keyboard Logger")

        self.log_table = QTableWidget()
        self.log_table.setColumnCount(2)
        self.log_table.setShowGrid(True)
        self.log_table.setHorizontalHeaderLabels(["Time", "Event"])
        self.log_table.horizontalHeader().setStretchLastSection(True)
        self.log_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.setCentralWidget(self.log_table)
        self.show()

        self.threadpool = QThreadPool()
        self.keyboard_detector = KeyboardDetector()
        self.keyboard_detector.signals.keyboard_changed.connect(self.add_row)
        self.threadpool.start(self.keyboard_detector)


    def add_row(self, event: str):
        now = datetime.now()
        datetime_string = now.strftime("%Y-%m-%d %H:%M:%S")

        row_count = self.log_table.rowCount()
        self.log_table.insertRow(row_count)
        self.log_table.setItem(row_count, 0, QTableWidgetItem(datetime_string))
        self.log_table.setItem(row_count, 1, QTableWidgetItem(event))


    def closeEvent(self,event):
        self.keyboard_detector.stop()


def main():
    app = QApplication(sys.argv)
    window = MainWindow()
    app.exec()


if __name__ == '__main__':
    main()
Atalanttore
  • 349
  • 5
  • 22