0

I would like when I click on a buttom from a toolbar created with PyQt get the selected items in a QListWidget created in other class (LisWorkDirectory class).

In the ToolBar.py in the compilation_ function, I would like to get all selected items. I want to get the instance of the ListWorkDirectory class to get the QListWidget that I created the first time I have launched my app.

If I instanciate ListWorkDirectory, I get a new instance, and the selectedItems return a empty list, it is a normal behaviour.

Maybe my architecture is not correct, so if you have any suggestion or remarks don't' hesitate to learn me.

Below my code so that you understand my request :

main.py

from MainWindow import MainWindow
from MenuBar import MenuBar
from ToolBar import ToolBar
from PyQt5.QtWidgets import QApplication
import sys

app = QApplication(sys.argv)

#Window
windowApp = MainWindow("pyCompile")
#MenuBar
menuBar = MenuBar()
#ToolBar
toolBar = ToolBar()

windowApp.setMenuBar(menuBar)
windowApp.addToolBar(toolBar)

windowApp.show()

sys.exit(app.exec_())

MainWindow.py

from PyQt5.QtWidgets import QMainWindow, QWidget, QLineEdit, QPushButton, QListWidget,QListWidgetItem,QPlainTextEdit, QFileDialog, QStatusBar ,QVBoxLayout, QHBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
from ListWorkDirectory import ListWorkDirectory
from Logger import MyDialog
import logging
import os

class MainWindow(QMainWindow):
    def __init__(self, windowTitle):
        super().__init__()
        #Logger
        self.logger = MyDialog()
        logging.info("pyCompile version 0.1")

        self.setGeometry(150,250,600,350)
        self.setWindowTitle(windowTitle)
        
        self.workDirectoryField = QLineEdit()
        self.workDirectoryField.setPlaceholderText("Select your work directory ...")
        self.workDirectoryField.setText("F:/WORKSPACE/Projects")
        
        self.workDirectoryButton = QPushButton()
        self.workDirectoryButton.setIcon(QIcon(":folder.svg"))
        self.workDirectoryButton.clicked.connect(self.launchDialog)
        
        self.hBoxLayout = QHBoxLayout()
        self.hBoxLayout.addWidget(self.workDirectoryField)
        self.hBoxLayout.addWidget(self.workDirectoryButton)
        
        #List folder in work directory
        self.myListFolder = ListWorkDirectory()
        print(self.myListFolder)
        self.workDirectoryField.textChanged[str].connect(self.myListFolder.update)



        self.hBoxLayoutLogger = QHBoxLayout()
        self.hBoxLayoutLogger.addWidget(self.myListFolder)

        self.hBoxLayoutLogger2 = QHBoxLayout()
        self.hBoxLayoutLogger2.addWidget(self.logger)

        self.centralWidget = QWidget(self)
        self.setCentralWidget(self.centralWidget)
        
        self.vBoxLayout = QVBoxLayout(self.centralWidget)
        self.vBoxLayout.addLayout(self.hBoxLayout)
        self.vBoxLayout.addLayout(self.hBoxLayoutLogger)
        self.vBoxLayout.addLayout(self.hBoxLayoutLogger2)


        #Status Bar
        self.statusBar = QStatusBar()
        self.statusBar.showMessage("Welcome in pyCompile", 5000)
        self.setStatusBar(self.statusBar)

    
    def launchDialog(self):
        workDirectory = QFileDialog.getExistingDirectory(self, caption="Select work directory")
        print(workDirectory)
        self.workDirectoryField.setText(workDirectory)

MenuBar.py

from PyQt5.QtWidgets import QMenuBar

class MenuBar(QMenuBar):
    def __init__(self):
        super().__init__()
        self.fileMenu = "&File"
        self.editMenu = "&Edit"
        self.helpMenu = "&Help"
        self.initUI()
        
    def initUI(self):
        self.addMenu(self.fileMenu)
        self.addMenu(self.editMenu)
        self.addMenu(self.helpMenu)

ToolBar.py

from PyQt5.QtWidgets import QMainWindow, QToolBar, QAction
from PyQt5.QtGui import QIcon
import qrc_resources
from ListWorkDirectory import ListWorkDirectory

class ToolBar(QToolBar, ListWorkDirectory):
    def __init__(self):
        super().__init__()
        self._createActions()
        self.initUI()
    

    def initUI(self):

        self.setMovable(False)
        self.addAction(self.compileAction)
        self.addAction(self.settingsAction)
        self.addAction(self.quitAction)

    def _createActions(self):
        self.compileAction = QAction(self)
        self.compileAction.setStatusTip("Launch compilation")
        self.compileAction.setText("&Compile")
        self.compileAction.setIcon(QIcon(":compile.svg"))
        self.compileAction.triggered.connect(self.compilation_)


        self.settingsAction = QAction(self)
        self.settingsAction.setText("&Settings")
        self.settingsAction.setIcon(QIcon(":settings.svg"))
        


        self.quitAction = QAction(self)
        self.quitAction.setText("&Quit")
        self.quitAction.setIcon(QIcon(":quit.svg"))

    
    def compilation_(self):
        """
        Get the instance of ListWorkDirectory to get selected items and launch the 
        compilation
        """

ListWorkDirectory.py

from PyQt5.QtWidgets import QListWidget,QListWidgetItem
from PyQt5.QtCore import Qt, QDir
import os

class ListWorkDirectory(QListWidget):
    
    def __init__(self):
        super().__init__()
        self.clear()

    
    def update(self, workDirectoryField):
        
        isPathCorrect = self.checkPath(workDirectoryField)
        
        if(isPathCorrect):
            listOfDirectory = self.getFolderList(workDirectoryField, os.listdir(workDirectoryField))
            for folder in listOfDirectory:
                self.item = QListWidgetItem(folder)
                self.item.setCheckState(Qt.Unchecked)
                self.addItem(self.item)

        else:
            self.clear()

    

    def checkPath(self, path):
        QPath = QDir(path)
        isQPathExist = QPath.exists()
        isPathEmpty  = self.isPathEmpty(path)
        if(isQPathExist and not isPathEmpty):
            return True
        else:
            return False

    
    def getFolderList(self, path, listOfFiles):
        listOfFolders=[]
        for file_ in listOfFiles:
            if(os.path.isdir(os.path.join(path, file_))):
                listOfFolders.append(file_)
            else:
                pass
        return listOfFolders
    
    
    
    def isPathEmpty(self, path):

        if(path != ""):
            return False
        
        else:
            return True

Thank you for your help.

9
  • 1
    send original instance to other class as parameter. ie. ToolBar(windowApp.myListFolder) Commented Jun 28, 2022 at 15:37
  • 1
    eventually it could get windowApp as parameter ToolBar(windowApp) and then it will have access to all variables inside MainWindow Commented Jun 28, 2022 at 15:40
  • I'm not sure but many widgets created inside MainWindow may have self.parent to access MainWindow and they could use self.parent.myListFolder Commented Jun 28, 2022 at 15:45
  • Your structure seems a bit too convoluted. Unless you need a very specific/custom behavior or you must use prototyping, I really see no need for subclasses of both QMenuBar and QToolBar. That said, it should not be the responsibility of ToolBar to do "something" on an object that is not related to it (if not by a common ancestor). The object hierarchy is clear: the topmost object is the window, so you should add the menubar/toolbar in that subclass, and connect the toolbar action to a function that will then access the list widget. Commented Jun 28, 2022 at 16:02
  • 2
    I found other problem - in ListWorkDirectory you create self.item = ... but this class has function self.item(number) to get item from list - and your self.item = ... replace original function. Commented Jun 28, 2022 at 16:19

1 Answer 1

1

When you add widget to window (or to other widget) then this window (or widget) is its parent and you can use self.parent() to access element in window (or widget). When widgets are nested then you may even use self.parent().parent()

def compilation_(self):
    """
    Get the instance of ListWorkDirectory to get selected items and launch the 
    compilation
    """

    print(self.parent().myListFolder)

EDIT:

Class ListWorkDirectory has function item(number) to get item from list - but you overwrite it with line self.item = QListWidgetItem(folder). If you remove self. and use

item = QListWidgetItem(folder)
item.setCheckState(Qt.Unchecked)
self.addItem(item)

then this will show only checked items

    def compilation_(self):
        """
        Get the instance of ListWorkDirectory to get selected items and launch the 
        compilation
        """
        lst = self.parent().myListFolder

        for x in range(lst.count()):
            item = lst.item(x)
            #print(item.checkState(), item.text())
            if item.checkState() :
                print(item.text())

Full working code - everyone can simply copy all to one file and run it.

from PyQt5.QtWidgets import QMainWindow, QWidget, QLineEdit, QPushButton, QListWidget,QListWidgetItem,QPlainTextEdit, QFileDialog, QStatusBar ,QVBoxLayout, QHBoxLayout
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
import logging
import os

# ---

from PyQt5.QtWidgets import QMenuBar

class MenuBar(QMenuBar):
    def __init__(self):
        super().__init__()
        self.fileMenu = "&File"
        self.editMenu = "&Edit"
        self.helpMenu = "&Help"
        self.initUI()
        
    def initUI(self):
        self.addMenu(self.fileMenu)
        self.addMenu(self.editMenu)
        self.addMenu(self.helpMenu)

# ---

from PyQt5.QtWidgets import QMainWindow, QToolBar, QAction
from PyQt5.QtGui import QIcon

class ToolBar(QToolBar):
    def __init__(self):
        super().__init__()
        self._createActions()
        self.initUI()
    

    def initUI(self):

        self.setMovable(False)
        self.addAction(self.compileAction)
        self.addAction(self.settingsAction)
        self.addAction(self.quitAction)

    def _createActions(self):
        self.compileAction = QAction(self)
        self.compileAction.setStatusTip("Launch compilation")
        self.compileAction.setText("&Compile")
        self.compileAction.setIcon(QIcon(":compile.svg"))
        self.compileAction.triggered.connect(self.compilation_)


        self.settingsAction = QAction(self)
        self.settingsAction.setText("&Settings")
        self.settingsAction.setIcon(QIcon(":settings.svg"))
        


        self.quitAction = QAction(self)
        self.quitAction.setText("&Quit")
        self.quitAction.setIcon(QIcon(":quit.svg"))

    
    def compilation_(self):
        """
        Get the instance of ListWorkDirectory to get selected items and launch the 
        compilation
        """
        lst = self.parent().myListFolder

        for x in range(lst.count()):
            item = lst.item(x)
            #print(item.checkState(), item.text())
            if item.checkState() :
                print(item.text())

# ---

from PyQt5.QtWidgets import QListWidget, QListWidgetItem
from PyQt5.QtCore import Qt, QDir
import os

class ListWorkDirectory(QListWidget):
    
    def __init__(self):
        super().__init__()
        self.clear()

    
    def update(self, workDirectoryField):
        
        isPathCorrect = self.checkPath(workDirectoryField)
        
        if(isPathCorrect):
            listOfDirectory = self.getFolderList(workDirectoryField, os.listdir(workDirectoryField))
            for folder in listOfDirectory:
                item = QListWidgetItem(folder)
                item.setCheckState(Qt.Unchecked)
                self.addItem(item)

        else:
            self.clear()

    

    def checkPath(self, path):
        QPath = QDir(path)
        isQPathExist = QPath.exists()
        isPathEmpty  = self.isPathEmpty(path)
        if(isQPathExist and not isPathEmpty):
            return True
        else:
            return False

    
    def getFolderList(self, path, listOfFiles):
        listOfFolders=[]
        for file_ in listOfFiles:
            if(os.path.isdir(os.path.join(path, file_))):
                listOfFolders.append(file_)
            else:
                pass
        return listOfFolders
    
    
    
    def isPathEmpty(self, path):

        if(path != ""):
            return False
        
        else:
            return True


class MainWindow(QMainWindow):
    def __init__(self, windowTitle):
        super().__init__()
        #Logger
        #self.logger = MyDialog()
        logging.info("pyCompile version 0.1")

        self.setGeometry(150,250,600,350)
        self.setWindowTitle(windowTitle)
        
        self.workDirectoryField = QLineEdit()
        self.workDirectoryField.setPlaceholderText("Select your work directory ...")
        self.workDirectoryField.setText("F:/WORKSPACE/Projects")
        
        self.workDirectoryButton = QPushButton()
        self.workDirectoryButton.setIcon(QIcon(":folder.svg"))
        self.workDirectoryButton.clicked.connect(self.launchDialog)
        
        self.hBoxLayout = QHBoxLayout()
        self.hBoxLayout.addWidget(self.workDirectoryField)
        self.hBoxLayout.addWidget(self.workDirectoryButton)
        
        #List folder in work directory
        self.myListFolder = ListWorkDirectory()
        print(self.myListFolder)
        self.workDirectoryField.textChanged[str].connect(self.myListFolder.update)

        self.hBoxLayoutLogger = QHBoxLayout()
        self.hBoxLayoutLogger.addWidget(self.myListFolder)

        self.hBoxLayoutLogger2 = QHBoxLayout()
        #self.hBoxLayoutLogger2.addWidget(self.logger)

        self.centralWidget = QWidget(self)
        self.setCentralWidget(self.centralWidget)
        
        self.vBoxLayout = QVBoxLayout(self.centralWidget)
        self.vBoxLayout.addLayout(self.hBoxLayout)
        self.vBoxLayout.addLayout(self.hBoxLayoutLogger)
        self.vBoxLayout.addLayout(self.hBoxLayoutLogger2)


        #Status Bar
        self.statusBar = QStatusBar()
        self.statusBar.showMessage("Welcome in pyCompile", 5000)
        self.setStatusBar(self.statusBar)

    
    def launchDialog(self):
        workDirectory = QFileDialog.getExistingDirectory(self, caption="Select work directory")
        print(workDirectory)
        self.workDirectoryField.setText(workDirectory)
        
# ---

from PyQt5.QtWidgets import QApplication
import sys

app = QApplication(sys.argv)

#Window
windowApp = MainWindow("pyCompile")
#MenuBar
menuBar = MenuBar()
#ToolBar
toolBar = ToolBar()

windowApp.setMenuBar(menuBar)
windowApp.addToolBar(toolBar)

windowApp.show()

sys.exit(app.exec_())
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you so much @furas I understand inheritance better now.
That is not inheritance, that's parentship. Also, while the above works in this specific example, it breaks many aspects of OOP (starting with modularity).
I added example which displays checked elements.
@musicamante thank you for the correction. Can you suggest me a structure to not break modularity. What is wrong and that break the modularity ?
@mnekkach generally speaking, an object should never know about the objects that exist "above" it (parents, grandparents, etc) or, at least, it should not do any operation on them, including doing something on other children of those parents, no matter if they're "siblings" (children of a common parent) or "distant cousins" (sharing a common ancestor, at any level). Consider a rain sensor in a car: it will not turn on or off the wipers on its own, it just signals its state to the onboard computer, and it's up to the computer to eventually decide whether to activate the wipers or not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.