3
\$\begingroup\$

EDIT: Changed title, few mistakes in code were resolved (now working properly)

The GUI I am trying to make will be a simple QTabWidget, leading a user straightforwardly towards the end tab by tab.

For now, I have three *.py files - main.py, tab1.py, tab2.py. In main.py is the main window of the app and function to run the app like this (simplified just to focus on my question):

import sys
import tab1
import tab2
import PyQt5.QtWidgets as qtw

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

class MainWindow(qtw.QmainWindow):
    def __init__(self):
        super().__init__()
        self.tabwidget = qtw.QTabWidget()
        self.setCentralWidget(self.tabwidget)

        self.tab1 = tab1.Tab_1()
        self.tab2 = tab2.Tab_2()

        # This is how I now passing the information from tab1 to tab2
        self.tab1.path_line.textChanged.connect(self.tab2.path_widget.setText)

        self.tabwidget.addTab(self.tab1, 'tab1')
        self.tabwidget.addTab(self.tab2, 'tab2')

if __name__ == '__main__':
    main()

In the tab1.py is defined class for a tabwidget which will serve as an input data tab. There is a button to open filedialog, read filename, and write the path into QLineEdit widget:

import PyQt5.QtWidgets as qtw

class Tab_1(qtw.QWidget):
    def __init__(self):
        super().__init__()
        self.path_line = qtw.QLineEdit()
        self.but = qtw.QPushButton('Open')
        self.but.clicked.connect(self.openfile)

        layout_1 = qtw.QVBoxLayout()
        layout_1.addWidget(self.but)
        self.setLayout(layout_1)

    def openfile(self):
        filename, _ = qtw.QFileDialog.getOpenFileName(self, 'Title', 'File types')
        if filename:
            self.path_line.setText(filename)
        else:
            self.path_line.setText('No file was selected!')

Now I want to in another file tab2.py use the path I got from qtw.OpenFileDialog. So the defined class Tab_2() looks like this:

import PyQt5.QtWidgets as qtw

class Tab_2(qtw.QWidget):
    def __init__(self):
        super().__init__()

        # Retrieving the information by QLabel widget
        self.path_widget = qtw.QLabel()
        # Transform the information into string variable
        self.path_string = self.path_widget.text()
        
        layout_2 = qtw.QVBoxLayout()
        layout_2.addWidget(self.path_widget) # The path from QFileDialog (Tab1) should appered on Tab2
        self.setLayout(layout_2)

My question is, is this the proper way to do it? Should I use MainWindow class as a "getter" and "passer" of the information like that or should that be implemented in the tab classes themselves? It works but I do not want to learn to do something bad way and eventually get used to it. I understand classes and their inheritance to some point (a lot of examples of dog classes or employee classes that I understand how it works but in my case I am confused). In combination with GUI, it messing up my head. Also, I want to have each tab as a separate class in a separate *.py file to make it clear and easy to add another one in the future. I see, that it might not be the right way to uses classes but each tab will have a different layout.

\$\endgroup\$
0

2 Answers 2

2
\$\begingroup\$

Basically your code works.

To write the selected path, you use the QLineEdit widget of the Tab_1 class. You don't show the path_line widget itself anywhere, but use the textChanged signal.

It is not clear why there is a path_string object in the Tab_2 class that you are not using.

I would suggest you:

  • object self.path_line = '' declare in the MainWindow class.

  • use the currentChanged signal:

    self.tabwidget.currentChanged.connect(self.current_changed)

  • when creating instances of the Tab_1 and Tab_2 classes, pass self as an argument, which will allow you to have access to objects of the MainWindow class in these widgets, for example path_line.

  • In the slot current_changed, you can write logic, which you will need when the index of the current page changes.


import sys
import PyQt5.QtWidgets as qtw

#from tab1 import Tab_1
class Tab_1(qtw.QWidget):
    def __init__(self, parent=None):                                 # + parent
        super().__init__()
        self.parent = parent                                         # + parent

        self.but = qtw.QPushButton('Open')
        self.but.clicked.connect(self.open_file)

        layout = qtw.QVBoxLayout(self)
        layout.addWidget(self.but)

    def open_file(self):
        filename, _ = qtw.QFileDialog.getOpenFileName(self, 'Title', 'File types')
        if filename:
            self.parent.path_line = filename                         # + parent
        else:
            self.parent.path_line = ''                               # + parent
 
 
#from tab2 import Tab_2
class Tab_2(qtw.QWidget):
    def __init__(self, parent=None):
        super().__init__()
        self.parent = parent

        self.path_widget = qtw.QLabel()
        
        layout = qtw.QVBoxLayout(self)
        layout.addWidget(self.path_widget) 
       

class MainWindow(qtw.QMainWindow):
    def __init__(self):
        super().__init__()
        self.path_line = ''                                          # + path_line
        
        self.tabwidget = qtw.QTabWidget()
        self.tabwidget.currentChanged.connect(self.current_changed)  # + currentChanged
        self.setCentralWidget(self.tabwidget)
        
        self.tab1 = Tab_1(self)                                      # + self
        self.tab2 = Tab_2(self)                                      # + self

        self.tabwidget.addTab(self.tab1, 'Tab 1')
        self.tabwidget.addTab(self.tab2, 'Tab 2')
        
    def current_changed(self, index):
        if index == 0:
            self.statusBar().showMessage('Message in statusbar. '
                'Select the file to read.', 5000)
        if index == 1:
            self.tab2.path_widget.setText(self.path_line)
            if not self.path_line:
                self.statusBar().showMessage(
                    'Go to the first tab and select the file to read.', 5000)            
            

def main():
    app = qtw.QApplication(sys.argv)
    window = MainWindow()
    window.resize(400, 300)
    window.show()
    sys.exit(app.exec_())
    
if __name__ == '__main__':
    main()

enter image description here

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Thanks for your answer. Your suggestion is exactly what I was looking for! \$\endgroup\$
    – roPe
    Commented Jul 4, 2021 at 13:58
  • \$\begingroup\$ @roPe you are welcome \$\endgroup\$
    – S. Nick
    Commented Jul 4, 2021 at 14:00
  • \$\begingroup\$ You are shadowing a QWidget.parent() method that returns a parent with a parent attribute that holds a parent and call it a proper way to pass the information? Hmm. \$\endgroup\$ Commented May 4 at 12:44
0
\$\begingroup\$

Building on the answer by S.Nick, I would suggest something along the lines of:

    import sys
    import PyQt5.QtWidgets as qtw
    
    #from tab1 import Tab_1
    class Tab_1(qtw.QWidget):
        def __init__(self, parent=None):                                 # + parent
            super().__init__()
            self._parent = parent                                         # + parent
    
            self.but = qtw.QPushButton('Open')
            self.but.clicked.connect(self.open_file)
    
            layout = qtw.QVBoxLayout(self)
            layout.addWidget(self.but)
    
        def open_file(self):
            filename, _ = qtw.QFileDialog.getOpenFileName(self, 'Title', 'File types')
            if filename:
                self._parent.path_line = filename                         # + parent
            else:
                self._parent.path_line = ''                               # + parent
     
     
    #from tab2 import Tab_2
    class Tab_2(qtw.QWidget):
        def __init__(self, parent=None):
            super().__init__()
            self._parent = parent
    
            self.path_widget = qtw.QLabel()
            
            layout = qtw.QVBoxLayout(self)
            layout.addWidget(self.path_widget) 
           
    
    class MainWindow(qtw.QMainWindow):
        def __init__(self):
            super().__init__()
            self.path_line = ''                                          # + path_line
            
            self.tabwidget = qtw.QTabWidget()
            self.tabwidget.currentChanged.connect(self.current_changed)  # + currentChanged
            self.setCentralWidget(self.tabwidget)
            
            self.tab1 = Tab_1(self)                                      # + self
            self.tab2 = Tab_2(self)                                      # + self
    
            self.tabwidget.addTab(self.tab1, 'Tab 1')
            self.tabwidget.addTab(self.tab2, 'Tab 2')

            
        def current_changed(self, index):
            if index == 0:
                self.statusBar().showMessage('Message in statusbar. '
                    'Select the file to read.', 5000)
            if index == 1:
                self.tab2.path_widget.setText(self.path_line)
                if not self.path_line:
                    self.statusBar().showMessage(
                        'Go to the first tab and select the file to read.', 5000)            
                
    
    def main():
        app = qtw.QApplication(sys.argv)
        window = MainWindow()
        window.resize(400, 300)
        window.show()
        sys.exit(app.exec_())
        
    if __name__ == '__main__':
        main()

Note that tab1.parent() returns a different thing than tab1._parent. To get the instance of MainWindow, you need to call parent three times: tab1.parent().parent().parent() or use tab1.window() instead.

That is to say,

    print(self.tab1.parent())
    print(self.tab1.parent().parent())
    print(self.tab1.parent().parent().parent())
    print(self.tab1.window())

produces

<PyQt5.QtWidgets.QStackedWidget object at 0x00000245A7A08310>
<PyQt5.QtWidgets.QTabWidget object at 0x00000245A60DFE20>
<__main__.MainWindow object at 0x00000245A60DFD90>
<__main__.MainWindow object at 0x00000245A60DFD90>
\$\endgroup\$
2
  • \$\begingroup\$ You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. It may be worth (re-)reading How to Answer. \$\endgroup\$ Commented May 4 at 14:45
  • \$\begingroup\$ @TobySpeight My motivation for improving the original answer is given in the comment to that answer. Difference from the original is stated in my answer (starting from "Note that"). \$\endgroup\$ Commented May 5 at 18:08

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.