How do I connect three or more windows in PyQt

Viewed 48

I have a complex program in which I need to connect multiple windows. Unfortunately, I seem to be not fully understanding the concept/steps necessary to do this so bonus points if anyone can explain the steps/process well. In my current program, I have a list of items. Once I select them by moving them over to the right list widget, I need them to go to the third window. The third window should be activated by clicking the dots on the second window. The program runs and shows the second window appropriately but the signal/slot connection of the dots button does not work. However, the rest of the code is working because if I switch the toolkit to show the third window, that part is performing as expected. My code is below, and again, no errors are being returned, but clicking the dots button on the second window does nothing.

Also, a question - do I instantiate the third window within the second class, or only within the main window? Again, struggling to fully understand the process and I will need to do this multiple more times.

from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QListWidget, QLineEdit, QTextEdit, QGridLayout, QHBoxLayout, QVBoxLayout, QSizePolicy, QFileDialog, QTabWidget, QCheckBox
import PyQt5.QtGui as qtg
import glob
import os
from PyQt5.QtCore import Qt, QSettings
import inspect
from PyQt5 import QtCore
import pandas as pd 
import pathlib
import pyreadstat
import json


class ThirdWindow(QWidget):
    def __init__(self):
        super().__init__()
        
        
        self.layout = QGridLayout()
        self.setLayout(self.layout)
        self.allVariables = QListWidget()
        self.variablesSelected = QListWidget()
        #self.allVariables.insertItem(0, 'Hello')
        self.layout.addWidget(self.allVariables, 1,0)
        self.layout.addWidget(self.variablesSelected, 1, 1)
        
    def setItems(self, items):
        self.allVariables.clear()
        for item in items:
            self.allVariables.addItem(item)
     
    
     
class SecondWindow(QWidget):
    def __init__(self):
        super().__init__()
        
        ##not sure if I am supposed to instantiate this here or only in the main window class
        self.thirdWindow = ThirdWindow()
        
    
        self.layout = QGridLayout(self)
        self.by = QLabel("By")
        self.byVariables = QLineEdit()
        self.byButton = QPushButton("...")
        self.layout.addWidget(self.by, 1, 0)
        self.layout.addWidget(self.byVariables, 2, 0)
        self.layout.addWidget(self.byButton, 2, 1)
        
       
    def seconddWindowConnections(self):
        self.byButton.clicked.connect(self.show_third_window)
        #self.buttons['Toolkit'].clicked.connect(self.show_new_window)   
        
    def show_third_window(self):
        self.thirdWindow.show()
        
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        # Add a title
        self.setWindowTitle("GUI Querying Program")

        self.layout = QHBoxLayout()
        self.setLayout(self.layout)
        self.initUI()
        self.setButtonConnections()
        
        self.sw = SecondWindow()
        self.tw = ThirdWindow()
        

    def initUI(self):
        subLayouts = {}

        subLayouts['LeftColumn'] = QGridLayout()
    
        self.layout.addLayout(subLayouts['LeftColumn'],1)
        
        # Buttons
        self.buttons = {}
        self.buttons['addVariable'] = QPushButton('>')
        self.buttons['removeVariable'] = QPushButton('<')
        self.buttons['Toolkit'] = QPushButton('Toolkit')
        
        
        self.variables = QListWidget()
        self.selectedVariables = QListWidget()
        
        subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
        subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
        subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
        subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
        subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
        
        names = ['apple', 'banana', 'Cherry']
        self.variables.insertItems(0, names)
        
    def setButtonConnections(self):
        self.buttons['addVariable'].clicked.connect(self.add_variable)
        self.buttons['Toolkit'].clicked.connect(self.show_new_window)   
        self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
        
    def add_variable(self):
        for item in self.variables.selectedItems():
            self.selectedVariables.addItem(item.clone())

    def show_new_window(self):
        self.sw.show()
        
    def add_selected_variables(self):
        items = []
        for i in range(self.selectedVariables.count()):
            items.append(self.selectedVariables.item(i).clone())
        self.tw.setItems(items)


if __name__ == "__main__":
    import sys
    app = QApplication([])
    mw = MainWindow()
    mw.show()
    app.exec()
1 Answers

The main issue with your code is that secondWindowConnections is never called so the button actually does nothing. I corrected that and fixed a few other issues I found in my example below. I left out the bits where I made no changes and all the changes I did make I made inline notes explaining them:

class SecondWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.thirdWindow = None  # dont initialize until neccessary
        self.thirdWindowItems = []
        self.layout = QGridLayout(self)
        self.by = QLabel("By")
        self.byVariables = QLineEdit()
        self.byButton = QPushButton("...")
        self.layout.addWidget(self.by, 1, 0)
        self.layout.addWidget(self.byVariables, 2, 0)
        self.layout.addWidget(self.byButton, 2, 1)
        self.secondWindowConnections()  #  Run this to setup the
                                       #  signal for the third window.
    def secondWindowConnections(self):   # this had a typo
        self.byButton.clicked.connect(self.show_third_window)

    def show_third_window(self):
        if self.thirdWindow is None:           # if window has been created yet
            self.thirdWindow = ThirdWindow()   # create window
        if not self.thirdWindow.isVisible():   # if window is showing
            self.thirdWindow.show()            # show window
        self.thirdWindow.setItems(self.thirdWindowItems)  # send items to window

    def send_items(self, items):       # this is to collect the variable that
        self.thirdWindowItems = items  # move to the third window

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        # Add a title
        self.setWindowTitle("GUI Querying Program")
        self.layout = QHBoxLayout()
        self.setLayout(self.layout)
        self.initUI()
        self.setButtonConnections()
        self.sw = None    # dont initialize until neccessary.

    def initUI(self):
        subLayouts = {}
        subLayouts['LeftColumn'] = QGridLayout()
        self.layout.addLayout(subLayouts['LeftColumn'],1)
        self.buttons = {}
        self.buttons['addVariable'] = QPushButton('>')
        self.buttons['removeVariable'] = QPushButton('<')
        self.buttons['Toolkit'] = QPushButton('Toolkit')
        self.variables = QListWidget()
        self.selectedVariables = QListWidget()
        subLayouts['LeftColumn'].addWidget(self.variables, 7,0,4,1)
        subLayouts['LeftColumn'].addWidget(self.selectedVariables, 7,1,4,1)
        subLayouts['LeftColumn'].addWidget(self.buttons['addVariable'], 10,0,1,1)
        subLayouts['LeftColumn'].addWidget(self.buttons['removeVariable'], 10,1,1,1)
        subLayouts['LeftColumn'].addWidget(self.buttons['Toolkit'], 11,1,1,1)
        names = ['apple', 'banana', 'Cherry']
        self.variables.insertItems(0, names)

    def setButtonConnections(self):
        self.buttons['addVariable'].clicked.connect(self.add_variable)
        self.buttons['Toolkit'].clicked.connect(self.show_new_window)
        # self.buttons['Toolkit'].clicked.connect(self.add_selected_variables)
        # only use one connnect slot

    def add_variable(self):
        for item in self.variables.selectedItems():
            self.selectedVariables.addItem(item.clone())

    def show_new_window(self):     
        if self.sw is None:   #  check if window has been constructed
            self.sw = SecondWindow()  # construct window
        if not self.sw.isVisible():    #  If winow is not showing
            self.sw.show()         #  show window
        self.sw.send_items(self.add_selected_variables())   # send selected 
                                                            # variables to second window

    def add_selected_variables(self):
        items = []
        for i in range(self.selectedVariables.count()):
            items.append(self.selectedVariables.item(i).clone())
        # self.tw.setItems(items) ...  self.tw doesnt exist so return them
        return items 
Related