From 8b574f407fd494f2067f9e33742e2cbfecc747b9 Mon Sep 17 00:00:00 2001 From: Francesco Grazioso Date: Tue, 25 Feb 2025 15:42:14 +0100 Subject: [PATCH] Refactor GUI code and modularize components Splits the monolithic GUI logic into modular components, improving maintainability. Introduces `RunTab`, `ResultsTable`, and utility modules for better separation of concerns and reusability. Adjusts main entry point and refactors core functionalities to align with the new structure. --- gui/__init__.py | 0 gui/main_window.py | 39 ++++ gui/tabs/__init__.py | 0 gui/tabs/run_tab.py | 263 ++++++++++++++++++++++++ gui/utils/__init__.py | 0 gui/utils/site_manager.py | 18 ++ gui/utils/stream_redirect.py | 13 ++ gui/widgets/__init__.py | 0 gui/widgets/results_table.py | 62 ++++++ streaming_gui.py | 384 +---------------------------------- 10 files changed, 402 insertions(+), 377 deletions(-) create mode 100644 gui/__init__.py create mode 100644 gui/main_window.py create mode 100644 gui/tabs/__init__.py create mode 100644 gui/tabs/run_tab.py create mode 100644 gui/utils/__init__.py create mode 100644 gui/utils/site_manager.py create mode 100644 gui/utils/stream_redirect.py create mode 100644 gui/widgets/__init__.py create mode 100644 gui/widgets/results_table.py diff --git a/gui/__init__.py b/gui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gui/main_window.py b/gui/main_window.py new file mode 100644 index 0000000..5fb4c13 --- /dev/null +++ b/gui/main_window.py @@ -0,0 +1,39 @@ +from PyQt5.QtWidgets import QMainWindow, QWidget, QVBoxLayout +from PyQt5.QtCore import QProcess +import sys +from .tabs.run_tab import RunTab +from .utils.stream_redirect import Stream + + +class StreamingGUI(QMainWindow): + def __init__(self): + super().__init__() + self.process = None + self.init_ui() + self.setup_output_redirect() + + def init_ui(self): + self.setWindowTitle("StreamingCommunity GUI") + self.setGeometry(100, 100, 1000, 700) + + central_widget = QWidget() + main_layout = QVBoxLayout() + + self.run_tab = RunTab(self) + main_layout.addWidget(self.run_tab) + + central_widget.setLayout(main_layout) + self.setCentralWidget(central_widget) + + def setup_output_redirect(self): + self.stdout_stream = Stream() + self.stdout_stream.newText.connect(self.run_tab.update_output) + sys.stdout = self.stdout_stream + + def closeEvent(self, event): + if self.process and self.process.state() == QProcess.Running: + self.process.terminate() + if not self.process.waitForFinished(1000): + self.process.kill() + sys.stdout = sys.__stdout__ + event.accept() diff --git a/gui/tabs/__init__.py b/gui/tabs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gui/tabs/run_tab.py b/gui/tabs/run_tab.py new file mode 100644 index 0000000..39ec4e5 --- /dev/null +++ b/gui/tabs/run_tab.py @@ -0,0 +1,263 @@ +from PyQt5.QtWidgets import ( + QWidget, + QVBoxLayout, + QHBoxLayout, + QTabWidget, + QGroupBox, + QFormLayout, + QLineEdit, + QComboBox, + QPushButton, + QCheckBox, + QLabel, + QTextEdit, +) +from PyQt5.QtCore import Qt, QProcess +from ..widgets.results_table import ResultsTable +from ..utils.site_manager import sites +import sys + + +class RunTab(QTabWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.parent = parent + self.process = None + self.current_context = None + self.selected_season = None + self.init_ui() + + def init_ui(self): + run_tab = QWidget() + run_layout = QVBoxLayout() + + # Add search group + run_layout.addWidget(self.create_search_group()) + + # Add control buttons + run_layout.addLayout(self.create_control_layout()) + + # Add status label + self.status_label = QLabel("Richiesta in corso...") + self.status_label.setAlignment(Qt.AlignCenter) + self.status_label.hide() + run_layout.addWidget(self.status_label) + + # Add output group + run_layout.addWidget(self.create_output_group()) + + run_tab.setLayout(run_layout) + self.addTab(run_tab, "Esecuzione") + + def create_search_group(self): + search_group = QGroupBox("Parametri di Ricerca") + search_layout = QFormLayout() + + self.search_terms = QLineEdit() + search_layout.addRow("Termini di ricerca:", self.search_terms) + + self.site_combo = QComboBox() + for site in sites: + self.site_combo.addItem(f"{site['name']}", site["index"]) + self.site_combo.setItemData(site["index"], site["flag"], Qt.ToolTipRole) + if self.site_combo.count() > 0: + self.site_combo.setCurrentIndex(0) + + search_layout.addRow("Seleziona sito:", self.site_combo) + search_group.setLayout(search_layout) + return search_group + + def create_control_layout(self): + control_layout = QHBoxLayout() + + self.run_button = QPushButton("Esegui Script") + self.run_button.clicked.connect(self.run_script) + control_layout.addWidget(self.run_button) + + self.stop_button = QPushButton("Ferma Script") + self.stop_button.clicked.connect(self.stop_script) + self.stop_button.setEnabled(False) + control_layout.addWidget(self.stop_button) + + self.console_checkbox = QCheckBox("Mostra Console") + self.console_checkbox.setChecked(False) + self.console_checkbox.stateChanged.connect(self.toggle_console) + control_layout.addWidget(self.console_checkbox) + + return control_layout + + def create_output_group(self): + output_group = QGroupBox("Output") + output_layout = QVBoxLayout() + + self.results_table = ResultsTable() + output_layout.addWidget(self.results_table) + + self.output_text = QTextEdit() + self.output_text.setReadOnly(True) + self.output_text.hide() + output_layout.addWidget(self.output_text) + + input_layout = QHBoxLayout() + self.input_field = QLineEdit() + self.input_field.setPlaceholderText("Inserisci l'indice del media...") + self.input_field.returnPressed.connect(self.send_input) + self.send_button = QPushButton("Invia") + self.send_button.clicked.connect(self.send_input) + + self.input_field.hide() + self.send_button.hide() + + input_layout.addWidget(self.input_field) + input_layout.addWidget(self.send_button) + output_layout.addLayout(input_layout) + + output_group.setLayout(output_layout) + return output_group + + def toggle_console(self, state): + self.output_text.setVisible(state == Qt.Checked) + + def run_script(self): + if self.process is not None and self.process.state() == QProcess.Running: + print("Script già in esecuzione.") + return + + self.current_context = None + self.selected_season = None + self.results_table.setVisible(False) + self.status_label.setText("Richiesta in corso...") + self.status_label.show() + + args = [] + search_terms = self.search_terms.text() + if search_terms: + args.extend(["-s", search_terms]) + + site_index = self.site_combo.currentIndex() + if site_index >= 0: + site_text = sites[site_index]["flag"] + site_name = site_text.split()[0].upper() + args.append(f"-{site_name}") + + self.output_text.clear() + print(f"Avvio script con argomenti: {' '.join(args)}") + + self.process = QProcess() + self.process.readyReadStandardOutput.connect(self.handle_stdout) + self.process.readyReadStandardError.connect(self.handle_stderr) + self.process.finished.connect(self.process_finished) + + python_executable = sys.executable + script_path = "run_streaming.py" + + self.process.start(python_executable, [script_path] + args) + self.run_button.setEnabled(False) + self.stop_button.setEnabled(True) + + def handle_stdout(self): + data = self.process.readAllStandardOutput() + stdout = bytes(data).decode("utf8", errors="replace") + self.update_output(stdout) + + if "Seasons found:" in stdout: + self.current_context = "seasons" + self.input_field.setPlaceholderText( + "Inserisci il numero della stagione (es: 1, *, 1-2, 3-*)" + ) + elif "Episodes find:" in stdout: + self.current_context = "episodes" + self.input_field.setPlaceholderText( + "Inserisci l'indice dell'episodio (es: 1, *, 1-2, 3-*)" + ) + + if "┏━━━━━━━┳" in stdout or "Seasons found:" in stdout: + self.parse_and_show_results(stdout) + elif "Episodes find:" in stdout: + self.results_table.hide() + self.status_label.setText(stdout) + self.status_label.show() + + if "Insert" in stdout: + self.input_field.show() + self.send_button.show() + self.input_field.setFocus() + self.output_text.verticalScrollBar().setValue( + self.output_text.verticalScrollBar().maximum() + ) + + def parse_and_show_results(self, text): + if "Seasons found:" in text: + self.status_label.hide() + num_seasons = int(text.split("Seasons found:")[1].split()[0]) + self.results_table.update_with_seasons(num_seasons) + return + + if "┏━━━━━━━┳" in text and "└───────┴" in text: + self.status_label.hide() + table_lines = text[text.find("┏") : text.find("└")].split("\n") + headers = [h.strip() for h in table_lines[1].split("┃")[1:-1]] + + rows = [] + for line in table_lines[3:]: + if line.strip() and "│" in line: + cells = [cell.strip() for cell in line.split("│")[1:-1]] + rows.append(cells) + + self.results_table.update_with_results(headers, rows) + + def send_input(self): + if not self.process or self.process.state() != QProcess.Running: + return + + user_input = self.input_field.text().strip() + + if self.current_context == "seasons": + if "-" in user_input or user_input == "*": + self.results_table.hide() + else: + self.selected_season = user_input + + elif self.current_context == "episodes": + if "-" in user_input or user_input == "*": + self.results_table.hide() + + self.process.write(f"{user_input}\n".encode()) + self.input_field.clear() + self.input_field.hide() + self.send_button.hide() + + if self.current_context == "seasons" and not ( + "-" in user_input or user_input == "*" + ): + self.status_label.setText("Caricamento episodi...") + self.status_label.show() + + def handle_stderr(self): + data = self.process.readAllStandardError() + stderr = bytes(data).decode("utf8", errors="replace") + self.update_output(stderr) + + def process_finished(self): + self.run_button.setEnabled(True) + self.stop_button.setEnabled(False) + self.input_field.hide() + self.send_button.hide() + self.status_label.hide() + print("Script terminato.") + + def update_output(self, text): + cursor = self.output_text.textCursor() + cursor.movePosition(cursor.End) + cursor.insertText(text) + self.output_text.setTextCursor(cursor) + self.output_text.ensureCursorVisible() + + def stop_script(self): + if self.process is not None and self.process.state() == QProcess.Running: + self.process.terminate() + if not self.process.waitForFinished(3000): + self.process.kill() + print("Script terminato.") + self.run_button.setEnabled(True) + self.stop_button.setEnabled(False) diff --git a/gui/utils/__init__.py b/gui/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gui/utils/site_manager.py b/gui/utils/site_manager.py new file mode 100644 index 0000000..b1e2393 --- /dev/null +++ b/gui/utils/site_manager.py @@ -0,0 +1,18 @@ +from StreamingCommunity.run import load_search_functions + + +def get_sites(): + search_functions = load_search_functions() + sites = [] + for alias, (_, use_for) in search_functions.items(): + sites.append( + { + "index": len(sites), + "name": alias.split("_")[0], + "flag": alias[:3].upper(), + } + ) + return sites + + +sites = get_sites() diff --git a/gui/utils/stream_redirect.py b/gui/utils/stream_redirect.py new file mode 100644 index 0000000..69612c6 --- /dev/null +++ b/gui/utils/stream_redirect.py @@ -0,0 +1,13 @@ +from PyQt5.QtCore import QObject, pyqtSignal + + +class Stream(QObject): + """Redirect script output to GUI""" + + newText = pyqtSignal(str) + + def write(self, text): + self.newText.emit(str(text)) + + def flush(self): + pass diff --git a/gui/widgets/__init__.py b/gui/widgets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gui/widgets/results_table.py b/gui/widgets/results_table.py new file mode 100644 index 0000000..bb059b5 --- /dev/null +++ b/gui/widgets/results_table.py @@ -0,0 +1,62 @@ +from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QHeaderView +from PyQt5.QtCore import Qt + + +class ResultsTable(QTableWidget): + def __init__(self, parent=None): + super().__init__(parent) + self.setup_table() + + def setup_table(self): + self.setVisible(False) + self.setSelectionMode(QTableWidget.NoSelection) + self.setEditTriggers(QTableWidget.NoEditTriggers) + self.setFocusPolicy(Qt.NoFocus) + self.setDragDropMode(QTableWidget.NoDragDrop) + self.setContextMenuPolicy(Qt.NoContextMenu) + self.verticalHeader().setVisible(False) + + # set custom style for diabled table + self.setStyleSheet( + """ + QTableWidget:disabled { + color: white; + background-color: #323232; + } + """ + ) + self.setEnabled(False) + + def update_with_seasons(self, num_seasons): + self.clear() + self.setColumnCount(2) + self.setHorizontalHeaderLabels(["Index", "Season"]) + + self.setRowCount(num_seasons) + for i in range(num_seasons): + index_item = QTableWidgetItem(str(i + 1)) + season_item = QTableWidgetItem(f"Stagione {i + 1}") + index_item.setFlags(Qt.ItemIsEnabled) + season_item.setFlags(Qt.ItemIsEnabled) + self.setItem(i, 0, index_item) + self.setItem(i, 1, season_item) + + self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) + self.horizontalHeader().setEnabled(False) + self.setVisible(True) + + def update_with_results(self, headers, rows): + self.clear() + self.setColumnCount(len(headers)) + self.setHorizontalHeaderLabels(headers) + + self.setRowCount(len(rows)) + for i, row in enumerate(rows): + for j, cell in enumerate(row): + item = QTableWidgetItem(cell) + item.setFlags(Qt.ItemIsEnabled) + self.setItem(i, j, item) + + self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) + self.horizontalHeader().setEnabled(False) + self.setVisible(True) diff --git a/streaming_gui.py b/streaming_gui.py index 59056ad..e14270d 100644 --- a/streaming_gui.py +++ b/streaming_gui.py @@ -1,384 +1,14 @@ import sys -from PyQt5.QtWidgets import ( - QApplication, - QMainWindow, - QWidget, - QVBoxLayout, - QHBoxLayout, - QLineEdit, - QPushButton, - QComboBox, - QTabWidget, - QTextEdit, - QGroupBox, - QFormLayout, - QTableWidget, - QTableWidgetItem, - QHeaderView, - QCheckBox, - QLabel, -) -from PyQt5.QtCore import Qt, QProcess, pyqtSignal, QObject -from StreamingCommunity.run import load_search_functions +from PyQt5.QtWidgets import QApplication +from gui.main_window import StreamingGUI -search_functions = load_search_functions() -sites = [] -for alias, (_, use_for) in search_functions.items(): - sites.append( - {"index": len(sites), "name": alias.split("_")[0], "flag": alias[:3].upper()} - ) - -class Stream(QObject): - """Redirect script output to GUI""" - - newText = pyqtSignal(str) - - def write(self, text): - self.newText.emit(str(text)) - - def flush(self): - pass - - -class StreamingGUI(QMainWindow): - def __init__(self): - super().__init__() - self.process = None - self.current_context = None # 'seasons', 'episodes', or None - self.selected_season = None - self.init_ui() - - # output redirect - self.stdout_stream = Stream() - self.stdout_stream.newText.connect(self.update_output) - sys.stdout = self.stdout_stream - - def init_ui(self): - self.setWindowTitle("StreamingCommunity GUI") - self.setGeometry(100, 100, 1000, 700) - - central_widget = QWidget() - main_layout = QVBoxLayout() - - tab_widget = QTabWidget() - run_tab = QWidget() - run_layout = QVBoxLayout() - - # search parameters group - search_group = QGroupBox("Parametri di Ricerca") - search_layout = QFormLayout() - - self.search_terms = QLineEdit() - search_layout.addRow("Termini di ricerca:", self.search_terms) - - self.site_combo = QComboBox() - for site in sites: - self.site_combo.addItem(f"{site['name']}", site["index"]) - self.site_combo.setItemData(site["index"], site["flag"], Qt.ToolTipRole) - if self.site_combo.count() > 0: - self.site_combo.setCurrentIndex(0) - - search_layout.addRow("Seleziona sito:", self.site_combo) - search_group.setLayout(search_layout) - run_layout.addWidget(search_group) - - # control buttons - control_layout = QHBoxLayout() - - self.run_button = QPushButton("Esegui Script") - self.run_button.clicked.connect(self.run_script) - control_layout.addWidget(self.run_button) - - self.stop_button = QPushButton("Ferma Script") - self.stop_button.clicked.connect(self.stop_script) - self.stop_button.setEnabled(False) - control_layout.addWidget(self.stop_button) - - # Console visibility checkbox - self.console_checkbox = QCheckBox("Mostra Console") - self.console_checkbox.setChecked(False) - self.console_checkbox.stateChanged.connect(self.toggle_console) - control_layout.addWidget(self.console_checkbox) - - run_layout.addLayout(control_layout) - - # Status label (replacing loader) - self.status_label = QLabel("Richiesta in corso...") - self.status_label.setAlignment(Qt.AlignCenter) - self.status_label.hide() - run_layout.addWidget(self.status_label) - - # output area - output_group = QGroupBox("Output") - output_layout = QVBoxLayout() - - # Table widget - self.results_table = QTableWidget() - self.results_table.setVisible(False) - self.results_table.setSelectionBehavior(QTableWidget.SelectRows) - self.results_table.setSelectionMode(QTableWidget.SingleSelection) - self.results_table.setEditTriggers(QTableWidget.NoEditTriggers) - output_layout.addWidget(self.results_table) - - # Console output - self.output_text = QTextEdit() - self.output_text.setReadOnly(True) - self.output_text.hide() - output_layout.addWidget(self.output_text) - - # Input controls - input_layout = QHBoxLayout() - self.input_field = QLineEdit() - self.input_field.setPlaceholderText("Inserisci l'indice del media...") - self.input_field.returnPressed.connect(self.send_input) - self.send_button = QPushButton("Invia") - self.send_button.clicked.connect(self.send_input) - - self.input_field.hide() - self.send_button.hide() - - input_layout.addWidget(self.input_field) - input_layout.addWidget(self.send_button) - output_layout.addLayout(input_layout) - - output_group.setLayout(output_layout) - run_layout.addWidget(output_group) - - run_tab.setLayout(run_layout) - tab_widget.addTab(run_tab, "Esecuzione") - - main_layout.addWidget(tab_widget) - central_widget.setLayout(main_layout) - self.setCentralWidget(central_widget) - - def toggle_console(self, state): - self.output_text.setVisible(state == Qt.Checked) - - def parse_and_show_results(self, text): - # Handle seasons list - if "Seasons found:" in text: - self.status_label.hide() - num_seasons = int(text.split("Seasons found:")[1].split()[0]) - - # Setup table for seasons - self.results_table.clear() - self.results_table.setColumnCount(2) - self.results_table.setHorizontalHeaderLabels(["Index", "Season"]) - - # Populate table with seasons - self.results_table.setRowCount(num_seasons) - for i in range(num_seasons): - index_item = QTableWidgetItem(str(i + 1)) - season_item = QTableWidgetItem(f"Stagione {i + 1}") - self.results_table.setItem(i, 0, index_item) - self.results_table.setItem(i, 1, season_item) - - # Adjust columns and show table - self.results_table.horizontalHeader().setSectionResizeMode( - QHeaderView.ResizeToContents - ) - self.results_table.setVisible(True) - self.results_table.itemSelectionChanged.connect(self.handle_selection) - return - - # Handle regular table output (episodes or search results) - if "┏━━━━━━━┳" in text and "└───────┴" in text: - self.status_label.hide() - - # Extract table content - table_lines = text[text.find("┏") : text.find("└")].split("\n") - - # Parse headers - headers = table_lines[1].split("┃")[1:-1] - headers = [h.strip() for h in headers] - - # Setup table - self.results_table.clear() - self.results_table.setColumnCount(len(headers)) - self.results_table.setHorizontalHeaderLabels(headers) - - # Parse rows - rows = [] - for line in table_lines[3:]: - if line.strip() and "│" in line: - cells = line.split("│")[1:-1] - cells = [cell.strip() for cell in cells] - rows.append(cells) - - # Populate table - self.results_table.setRowCount(len(rows)) - for i, row in enumerate(rows): - for j, cell in enumerate(row): - item = QTableWidgetItem(cell) - self.results_table.setItem(i, j, item) - - # Adjust columns - self.results_table.horizontalHeader().setSectionResizeMode( - QHeaderView.ResizeToContents - ) - - # Show table and connect selection - self.results_table.setVisible(True) - self.results_table.itemSelectionChanged.connect(self.handle_selection) - - def handle_selection(self): - if self.results_table.selectedItems(): - selected_row = self.results_table.currentRow() - if self.input_field.isVisible(): - if self.current_context == "seasons": - # For seasons, we add 1 because seasons are 1-based - self.input_field.setText(str(selected_row + 1)) - else: - # For episodes and search results, use the row number directly - self.input_field.setText(str(selected_row)) - - def run_script(self): - if self.process is not None and self.process.state() == QProcess.Running: - print("Script già in esecuzione.") - return - - self.current_context = None - self.selected_season = None - self.results_table.setVisible(False) - self.status_label.setText("Richiesta in corso...") - self.status_label.show() - - # build command line args - args = [] - search_terms = self.search_terms.text() - if search_terms: - args.extend(["-s", search_terms]) - - site_index = self.site_combo.currentIndex() - if site_index >= 0: - site_text = sites[site_index]["flag"] - site_name = site_text.split()[0].upper() - args.append(f"-{site_name}") - - self.output_text.clear() - print(f"Avvio script con argomenti: {' '.join(args)}") - - self.process = QProcess() - self.process.readyReadStandardOutput.connect(self.handle_stdout) - self.process.readyReadStandardError.connect(self.handle_stderr) - self.process.finished.connect(self.process_finished) - - python_executable = sys.executable - script_path = "run_streaming.py" - - self.process.start(python_executable, [script_path] + args) - self.run_button.setEnabled(False) - self.stop_button.setEnabled(True) - - def handle_stdout(self): - data = self.process.readAllStandardOutput() - stdout = bytes(data).decode("utf8", errors="replace") - self.update_output(stdout) - - # Detect context - if "Seasons found:" in stdout: - self.current_context = "seasons" - self.input_field.setPlaceholderText( - "Inserisci il numero della stagione (es: 1, *, 1-2, 3-*)" - ) - elif "Episodes find:" in stdout: - self.current_context = "episodes" - self.input_field.setPlaceholderText( - "Inserisci l'indice dell'episodio (es: 1, *, 1-2, 3-*)" - ) - - # Parse and show results if available - if "┏━━━━━━━┳" in stdout or "Seasons found:" in stdout: - self.parse_and_show_results(stdout) - elif "Episodes find:" in stdout: - self.results_table.hide() - self.status_label.setText(stdout) - self.status_label.show() - - # Show input controls when needed - if "Insert" in stdout: - self.input_field.show() - self.send_button.show() - self.input_field.setFocus() - self.output_text.verticalScrollBar().setValue( - self.output_text.verticalScrollBar().maximum() - ) - - def send_input(self): - if not self.process or self.process.state() != QProcess.Running: - return - - user_input = self.input_field.text().strip() - - # Handle season selection - if self.current_context == "seasons": - if "-" in user_input or user_input == "*": - # Multiple seasons selected, hide table - self.results_table.hide() - else: - # Single season selected, table will update with episodes - self.selected_season = user_input - - # Handle episode selection - elif self.current_context == "episodes": - if "-" in user_input or user_input == "*": - # Multiple episodes selected, hide table - self.results_table.hide() - - # Send input to process - self.process.write(f"{user_input}\n".encode()) - self.input_field.clear() - self.input_field.hide() - self.send_button.hide() - - # Show status label for next step - if self.current_context == "seasons" and not ( - "-" in user_input or user_input == "*" - ): - self.status_label.setText("Caricamento episodi...") - self.status_label.show() - - def handle_stderr(self): - data = self.process.readAllStandardError() - stderr = bytes(data).decode("utf8", errors="replace") - self.update_output(stderr) - - def process_finished(self): - self.run_button.setEnabled(True) - self.stop_button.setEnabled(False) - self.input_field.hide() - self.send_button.hide() - self.status_label.hide() - print("Script terminato.") - - def update_output(self, text): - cursor = self.output_text.textCursor() - cursor.movePosition(cursor.End) - cursor.insertText(text) - self.output_text.setTextCursor(cursor) - self.output_text.ensureCursorVisible() - - def stop_script(self): - if self.process is not None and self.process.state() == QProcess.Running: - self.process.terminate() - if not self.process.waitForFinished(3000): - self.process.kill() - print("Script terminato.") - self.run_button.setEnabled(True) - self.stop_button.setEnabled(False) - - def closeEvent(self, event): - if self.process is not None and self.process.state() == QProcess.Running: - self.process.terminate() - if not self.process.waitForFinished(1000): - self.process.kill() - sys.stdout = sys.__stdout__ - event.accept() - - -if __name__ == "__main__": +def main(): app = QApplication(sys.argv) gui = StreamingGUI() gui.show() sys.exit(app.exec_()) + + +if __name__ == "__main__": + main()