Python Forum
Issue with GUI screen switching in Python QT5 code
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Issue with GUI screen switching in Python QT5 code
#1
I have exhausted all the possible remedies ChatGPT could offer me in resolving my issue.
Basically I cant use a GUI command button on 2 seperate GUI screens to alternate between hiding one screen and showing the other (and vice-versa) without the python console complaining about ‘circular imports’. So ChatGPT came up with a solution to create a python file that will mediate between GUI screen transmission. As stated i Have four files

initgui .py - This is the main python file to launch the program
junction.py - This is the mediator file between the two bottom python files
intro.py - This is the file for the first GUI screen. The python QT5 code to dictate the GUI criteria is outsourced to a file named introgui.py. The screen has a button to load the GUI screen for rftrans.py and a program terminate button
rftrans.py this is the other screen. I wont bog you down with the content of it. Too laborious, but it too outsources it python QT5 code from rftransgui.py

Heres the issue

I can switch screens from intro to rftrans.py but for some reason I cant transit from rftrans.py to intro.py GUI screen depite no errors being outputted on python console. I am using pycharm on ubuntu 22.04. I have python3 installed via ubuntu terminal. I shall attach the 4 files. Hopefully someone may have the answer.

initgui.py
import sys
import os
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QFileDialog, QMessageBox, QLineEdit
from PyQt5.QtGui import QColor
from PyQt5.QtCore import QTimer, Qt,  QDir  # Import QTimer
from junction import WindowManager
from intro import IntroWindow
from rftrans import RFTransWindow

def main():
    app = QApplication(sys.argv)
    window_manager = WindowManager()

    intro_window = IntroWindow()
    intro_window.window_manager = window_manager
    window_manager.GUIJunction(intro_window)

    rftrans_window = RFTransWindow()
    rftrans_window.hide()

    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
junction.py

import sys
import os
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QFileDialog, QMessageBox, QLineEdit
from PyQt5.QtGui import QColor
from PyQt5.QtCore import QTimer, Qt,  QDir  # Import QTimer

class WindowManager:
    def __init__(self):
        self.current_window = None

    def GUIJunction(self, new_window):
        """Switch to a new window."""
        if self.current_window:
            self.current_window.close()  # Close the current window
        new_window.show()  # Show the new window
        self.current_window = new_window  # Update the current window reference
intro.py

import sys
import os
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QFileDialog, QMessageBox, QLineEdit
from PyQt5.QtGui import QColor
from PyQt5.QtCore import QTimer, Qt,  QDir  # Import QTimer
from introgui import Ui_MainWindow
from rftrans import RFTransWindow
from junction import WindowManager

class IntroWindow(QMainWindow):
    def __init__(self):
        super(IntroWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Assign functionality to GUI objects
        self.ui.cmdRFRecep.clicked.connect(self.RFReception)
        self.ui.cmdRFTrans.clicked.connect(self.RFTransmission)
        self.ui.cmdRSAKeyGen.clicked.connect(self.RSAKeyGeneration)
        self.ui.cmdFileEn.clicked.connect(self.FileEncryption)
        self.ui.cmdExit.clicked.connect(self.exitApplication)

    def RFReception(self):
        self.close()
    def RFTransmission(self):
        self.rftrans_window = RFTransWindow()
        self.rftrans_window.show()
        self.close()
    def RSAKeyGeneration(self):
        self.close()
    def FileEncryption(self):
        self.close()
    def exitApplication(self):
        # Code to exit the application goes here
        print("Exiting application...")
        sys.exit()
rftrans.py

import sys
import os
import time
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import bluetooth  # Import the bluetooth module
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QFileDialog, QMessageBox, QLineEdit
from PyQt5.QtGui import QColor
from PyQt5.QtCore import QTimer, Qt,  QDir  # Import QTimer
from rftransgui import GUIRFTransWindow
from junction import WindowManager

class RFTransWindow(QMainWindow):
    def __init__(self, intro_window=None, window_manager=None):
        super().__init__()
        self.ui = GUIRFTransWindow()
        self.ui.setupUi(self)
        self.intro_window = intro_window
        self.window_manager = window_manager

        # Assign functionality to GUI objects
        self.ui.cmdScanBlue.clicked.connect(self.scanBluetoothDevices)
        self.ui.cmdConnectBlue.clicked.connect(self.connectToDevice)
        self.ui.cmdStartTrans.clicked.connect(self.startTransmission)
        self.ui.cmdStopTrans.clicked.connect(self.stopTransmission)
        self.ui.cmdExit.clicked.connect(self.exitApplication)
        self.ui.cboSBlueAddr.setHidden(True)
        self.ui.cmdSlctIFile.clicked.connect(self.openFile)
        self.ui.cmdSlctPubKey.clicked.connect(self.openRSAFile)
        self.ui.sldrFreq.valueChanged.connect(self.updateFrequencyLabel)
        self.ui.chkRSATrans.stateChanged.connect(self.toggleRSATransmission)  # Connect checkbox to method
        self.ui.chkShowRSA.clicked.connect(self.toggleRSAEchoMode)
        self.ui.chkSwIFile.clicked.connect(self.toggleIFileEchoMode)
        self.ui.cmdClrIFile.clicked.connect(self.ClearInput)
        self.ui.cmdClrRSA.clicked.connect(self.ClearRSA)
        # Add more connections as needed

    def TSawtooth(self):
        #if self.ui.chkSwIFile.isChecked():
        if self.ui.chkSawtooth.isChecked():
            self.ui.chkSine.setChecked(False)
            self.ui.chkSquare.setChecked(False)
            self.ui.chkTriangle.setChecked(False)

    def TSine(self):
        if self.ui.chkSine.isChecked():
            self.ui.chkSawtooth.setChecked(False)
            self.ui.chkSquare.setChecked(False)
            self.ui.chkTriangle.setChecked(False)
    def TSquare(self):
        if self.ui.chkSquare.isChecked():
            self.ui.chkSawtooth.setChecked(False)
            self.ui.chkSine.setChecked(False)
            self.ui.chkTriangle.setChecked(False)
    def TTriangle(self):
        if self.ui.chkTriangle.isChecked():
            self.ui.chkSawtooth.setChecked(False)
            self.ui.chkSine.setChecked(False)
            self.ui.chkSquare.setChecked(False)
    def ClearInput(self):
        self.ui.txtSlctIFile.clear()
    def ClearRSA(self):
        self.ui.txtSlctPubKey.clear()
    def toggleRSAEchoMode(self):
        # Toggle echo mode of txtSlctPubKey based on chkShowRSA checkbox state
        if self.ui.chkShowRSA.isChecked():
            self.ui.txtSlctPubKey.setEchoMode(QtWidgets.QLineEdit.Normal)
        else:
            self.ui.txtSlctPubKey.setEchoMode(QtWidgets.QLineEdit.Password)

    def toggleIFileEchoMode(self):
        # Toggle echo mode of txtSlctPubKey based on chkShowRSA checkbox state
        if self.ui.chkSwIFile.isChecked():
            self.ui.txtSlctIFile.setEchoMode(QtWidgets.QLineEdit.Normal)
        else:
            self.ui.txtSlctIFile.setEchoMode(QtWidgets.QLineEdit.Password)


    def toggleRSATransmission(self, state):
        # Method to enable/disable RSA transmission based on checkbox state
        if state == Qt.Checked:  # Use Qt.Checked directly without QtCore prefix
            self.ui.chkShowRSA.setVisible(True)
            self.ui.txtSlctPubKey.setVisible(True)
            self.ui.cmdSlctPubKey.setVisible(True)
            self.ui.cmdClrRSA.setVisible(True)
        else:
            self.ui.chkShowRSA.setVisible(False)
            self.ui.txtSlctPubKey.setVisible(False)
            self.ui.cmdSlctPubKey.setVisible(False)
            self.ui.cmdClrRSA.setVisible(False)
    def openFile(self):
        # Open file dialog
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getOpenFileName(self, "Select Input File", QDir.homePath(),
                                                  "All Files (*);;Text Files (*.txt)", options=options)

        if fileName:
            # Set selected file path in txtSlctIFile text box
            self.ui.txtSlctIFile.setText(fileName)
            self.input_file = fileName

    def openRSAFile(self):
        # Open file dialog
        options = QFileDialog.Options()
        RSAfileName, _ = QFileDialog.getOpenFileName(self, "Select Input File", QDir.homePath(),
                                                  "All Files (*);;Text Files (*.txt)", options=options)

        if RSAfileName:
            # Set selected file path in txtSlctIFile text box
            self.ui.txtSlctPubKey.setText(RSAfileName)
            #self.input_file = RSAfileName

    def scanBluetoothDevices(self):
        # Change lblBStatus text and background color
        self.ui.lblBStatus.setText("Scanning for nearby devices...")
        self.ui.lblBStatus.setStyleSheet("background-color: rgb(255, 0, 0);")
        self.ui.cboListBDev.clear()
        self.ui.cboSBlueAddr.clear()

        # Code to scan Bluetooth devices goes here
        nearby_devices = bluetooth.discover_devices(lookup_names=True)
        print("SCANNING!!!!...")
        for addr, name in nearby_devices:
            # Add each device name to the combo box
            self.ui.cboListBDev.addItem(name)
            # Store the device address in a variable
            self.ui.cboSBlueAddr.addItem(addr)
        self.ui.lblBStatus.setText("Bluetooth Status")
        self.ui.lblBStatus.setStyleSheet("background-color: rgb(143, 240, 164);")  # Reset style to default
        print("STOP SCANNING!!!!...")

    def connectToDevice(self):
        # Get the selected item text from cboListBDev
        selected_device = self.ui.cboListBDev.currentText()

        # Get the index of the selected item in cboListBDev
        selected_index = self.ui.cboListBDev.currentIndex()

        # Use the selected index to retrieve the corresponding Bluetooth address from cboSBlueAddr
        if selected_index != -1:  # Ensure an item is selected
            device_address = self.ui.cboSBlueAddr.itemText(selected_index)

        # Try to connect/pair with the selected Bluetooth device
        try:
            # Code to connect/pair with the Bluetooth device using its address
            # Example: bluetooth.connect(device_address)
            print(f"Connecting to Bluetooth device: {device_address}")
        except Exception as e:
            # Display error message if connection/pairing fails
            QMessageBox.warning(self, "Connection Error", f"Failed to connect to the selected device: {e}")

    def updateFrequencyLabel(self, value):
        # Update the label text with the current value of the slider
        self.ui.lblDFreq.setText(str(value) + " (KHz)")

    def startTransmission(self):

        input_file_path = self.ui.txtSlctIFile.text()
        rsa_key_path = self.ui.txtSlctPubKey.text()

        if self.ui.chkRSATrans.isChecked():
            # Load RSA public key
            with open(rsa_key_path, 'rb') as key_file:
                rsa_key = RSA.import_key(key_file.read())

            # Create a cipher object for encryption
            cipher = PKCS1_OAEP.new(rsa_key)

            # Prepare output file path
            output_file_path = os.path.splitext(input_file_path)[0] + "_RSACONV"

            try:
                # Open input and output files
                with open(input_file_path, 'rb') as input_file, open(output_file_path, 'wb') as output_file:
                    # Read and encrypt file chunk by chunk
                    chunk_size = 85
                    while True:
                        chunk = input_file.read(chunk_size)
                        if not chunk:
                            break  # End of file
                        encrypted_chunk = cipher.encrypt(chunk)
                        output_file.write(encrypted_chunk)

                QMessageBox.information(self, "Success", "File encrypted successfully.")
            except Exception as e:
                QMessageBox.warning(self, "Encryption Error", f"Failed to encrypt file: {e}")

        else:
            if self.input_file:
                try:
                        self.transmitData(file)
                except Exception as e:
                    QMessageBox.warning(self, "Transmission Error", f"Failed to transmit data: {e}")
                else:
                    QMessageBox.warning(self, "File Error", "Please select an input file.")

    def transmitData(self, data):
        # Transmit data via Bluetooth
        # Replace this with your actual Bluetooth transmission code
        print(f"Transmitting data: {data}")

    def stopTransmission(self):
        # Code to stop transmission goes here
        print("Stopping transmission...")

    def exitApplication(self):
        # Code to exit the application goes here
        print("Exiting application...")
        if self.window_manager:
            self.window_manager.GUIJunction(IntroWindow(window_manager=self.window_manager))
Reply
#2
You are creating multiple QApplication objects. You can't do that. Create one QApplication progject and multiple windows. I would argue that multiple windows is bad sesign and you should only create one window that has multiple views.

This is how you can have one window that serves as a window manager of sort.
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout
from PySide6.QtGui import QFont
from functools import partial

class MyOwnWindow(QWidget):
    """A window that cannot be closed by the window manager."""
    def __init__(self, text):
        super().__init__()
        font = QFont("Helvetica", 30)
        label = QLabel(f"This is the {text} window", self)
        label.setFont(font)
        button = QPushButton("Close", self)
        button.setFont(font)
        button.clicked.connect(self.hide)
        layout = QVBoxLayout(self)
        layout.addWidget(label)
        layout.addWidget(button)

    def closeEvent(self, event=None):
        """Intercept window manager close event"""
        self.hide()


class WindowManager(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.windows = {
            text: MyOwnWindow(text)
            for text in ("This", "That", "The Other Thing")
        }
        font = QFont("Helvetica", 30)
        layout = QVBoxLayout(self)
        for text in self.windows:
            button = QPushButton(text, self)
            button.setFont(font)
            button.clicked.connect(partial(self.show_window, text))
            layout.addWidget(button)

    def show_window(self, id):
        """Display windows[id]"""
        for window in self.windows.values():
            window.hide()
        self.windows[id].show()

    def closeEvent(self, event):
        """Intercept window manager close event.  Close all windows"""
        for window in self.windows.values():
            window.close()
        self.close()


app = QApplication()
window = WindowManager()
window.show()
app.exec()
This is the same thing using multiple views that can be displayed one at a time.
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QComboBox, QVBoxLayout, QStackedLayout
from PySide6.QtGui import QFont
from PySide6.QtCore import Qt

class View(QWidget):
    def __init__(self, parent, text):
        super().__init__(parent)
        font = QFont("Helvetica", 30)
        layout = QVBoxLayout(self)
        for text in ("This is the", text, "window"):
            label = QLabel(text, self)
            label.setFont(font)
            label.setAlignment(Qt.AlignCenter)
            layout.addWidget(label)


class MainWindow(QWidget):
    """A window that has multiple views."""
    def __init__(self):
        views = ("This", "That", "The Other Thing")
        super().__init__()
        layout = QVBoxLayout(self)

        stack = QStackedLayout(self)
        layout.addLayout(stack)
        for text in views:
            view = View(self, text)
            stack.addWidget(view)

        cbox = QComboBox()
        layout.addWidget(cbox)
        cbox.addItems(views)
        cbox.currentIndexChanged.connect(stack.setCurrentIndex)


app = QApplication()
window = MainWindow()
window.show()
app.exec()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Switching from tkinter to gtk is difficult! snakes 1 1,489 Aug-08-2022, 10:35 PM
Last Post: woooee
  [PyQt] QPainter issue showing black screen mart79 0 2,025 May-06-2020, 12:02 PM
Last Post: mart79
  [Tkinter] Python code issue tedarencn 2 1,988 Apr-15-2020, 07:19 PM
Last Post: tedarencn
  [Tkinter] Unable to Access global Variable when switching between frames tziyong 1 3,506 Nov-03-2019, 01:08 AM
Last Post: balenaucigasa
  [Tkinter] Call a function when switching layouts 4096 0 3,562 Sep-22-2019, 07:39 PM
Last Post: 4096
  [PyGUI] Switching between two frames using Tkinter jenkins43 1 4,654 Jul-17-2019, 10:53 AM
Last Post: metulburr
  [Tkinter] switching frames nick123 2 7,967 Apr-18-2019, 04:50 PM
Last Post: francisco_neves2020
  Problem with pygame not switching the mouse image Mondaythe1st 6 6,816 Jul-26-2017, 10:53 PM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020