1

i have a requirement where i need to replace a frame with another frame. I have implemented below code which is working fine but issue is that i am doing in same file. Is it possible if i create frame1 in one .py file and frame2 in another .py file and still achieve same result.

The below way of solution will not help as it will create huge code in single file.

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(434, 362)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.frame = QtWidgets.QFrame(self.centralwidget)
        self.frame.setGeometry(QtCore.QRect(10, 10, 411, 311))
        self.frame.setFrameShape(QtWidgets.QFrame.Box)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")


        self.frame_2 = QtWidgets.QFrame(self.centralwidget)
        self.frame_2.setGeometry(QtCore.QRect(10, 10, 411, 311))
        self.frame_2.setFrameShape(QtWidgets.QFrame.Box)
        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_2.setObjectName("frame_2")


        self.label = QtWidgets.QLabel(self.frame_2)
        self.label.setGeometry(QtCore.QRect(10, 10, 131, 16))
        self.label.setObjectName("label")
    
        self.label_2 = QtWidgets.QLabel(self.frame)
        self.label_2.setGeometry(QtCore.QRect(10, 20, 131, 16))
        self.label_2.setObjectName("label_2")

        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(10, 330, 411, 23))
        self.pushButton.setObjectName("pushButton")
        self.pushButton.clicked.connect(self.changeFrame)
        MainWindow.setCentralWidget(self.centralwidget)

       self.frame.show()
       self.frame_2.hide()
    
       self.retranslateUi(MainWindow)
       QtCore.QMetaObject.connectSlotsByName(MainWindow)

   def retranslateUi(self, MainWindow):
       _translate = QtCore.QCoreApplication.translate
       MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
       self.label.setText(_translate("MainWindow", "Second Frame"))
       self.label_2.setText(_translate("MainWindow", "First Frame"))
       self.pushButton.setText(_translate("MainWindow", "Frame Change"))

   def changeFrame(self):
       self.frame.hide()
       self.frame_2.show()

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Frame1.Py

from PyQt5 import QtCore, QtGui, QtWidgets

class Frame1(object):
def setupUi(self, MainWindow):
     MainWindow.setObjectName("MainWindow")
     MainWindow.resize(434, 362)
     MainWindow.setWindowTitle("MainWindow")
     self.centralwidget = QtWidgets.QWidget(MainWindow)
     self.centralwidget.setObjectName("centralwidget")
     self.frame = QtWidgets.QFrame(self.centralwidget)
     self.frame.setGeometry(QtCore.QRect(10, 10, 411, 311))
     self.frame.setFrameShape(QtWidgets.QFrame.Box)
     self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
     self.frame.setObjectName("frame")
     self.label = QtWidgets.QLabel(self.frame_2)
     self.label.setGeometry(QtCore.QRect(10, 10, 131, 16))
     self.label.setObjectName("label")
     self.pushButton.setText("Frame One")
     MainWindow.setCentralWidget(self.centralwidget)
     QtCore.QMetaObject.connectSlotsByName(MainWindow) 

 Frame2.py

 from PyQt5 import QtCore, QtGui, QtWidgets

 class Frame2(object):
 def setupUi(self, MainWindow):
     MainWindow.setObjectName("MainWindow")
     MainWindow.resize(434, 362)
     MainWindow.setWindowTitle("MainWindow")
     self.centralwidget = QtWidgets.QWidget(MainWindow)
     self.centralwidget.setObjectName("centralwidget")
     self.frame = QtWidgets.QFrame(self.centralwidget)
     self.frame.setGeometry(QtCore.QRect(10, 10, 411, 311))
     self.frame.setFrameShape(QtWidgets.QFrame.Box)
     self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
     self.frame.setObjectName("frame")
     self.label = QtWidgets.QLabel(self.frame_2)
     self.label.setGeometry(QtCore.QRect(10, 10, 131, 16))
     self.label.setObjectName("label")  
     self.label.setText("Second Frame")
     MainWindow.setCentralWidget(self.centralwidget)
     QtCore.QMetaObject.connectSlotsByName(MainWindow)


  Main.py

  from PyQt5 import QtCore, QtGui, QtWidgets
  from Frame1 import *
  from Frame2 import *

  class Main(object):
  def setupUi(self, MainWindow):
     MainWindow.setObjectName("MainWindow")
     MainWindow.resize(434, 362)
     self.centralwidget = QtWidgets.QWidget(MainWindow)
     self.centralwidget.setObjectName("centralwidget")

     Frame1.frame.show()
     Frame2.frame.hide() 
     self.pushButton = QtWidgets.QPushButton(self.centralwidget)
     self.pushButton.setGeometry(QtCore.QRect(10, 330, 411, 23))
     self.pushButton.setObjectName("pushButton")
     self.pushButton.clicked.connect(self.changeFrame)
     MainWindow.setCentralWidget(self.centralwidget)
     QtCore.QMetaObject.connectSlotsByName(MainWindow)


    def changeFrame(self):
        Frame1.frame.hide()
        Frame2.frame.show()

    if __name__ == "__main__":
        import sys
         app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
         ui = Main()
         ui.setupUi(MainWindow)
         MainWindow.show()
         sys.exit(app.exec_())
Saurabh
  • 73
  • 6
  • I don't understand your question, what do you mean by replace? If the code that you show works then it is irrelevant by itself, in which code does it not work? – eyllanesc Jul 22 '20 at 21:20
  • Hi Eyllanesc, if you see the current code .. When i run it frame 1 shows up and frame2 not. And when I click on pushbutton frame1 disappear and frame 2 shows up. this code is working. But assume if i have 20 frames then i have to right in similar way and my code becomes non-readable. What i am looking, is there any possiblity that i create two python scripts, let say frame1.py and frame2.py...... 3rd one is main.py. In main, if I click on pushbutton1 then frame1 will appear and when i click on pushbutton2 then frame2 will appear. I hope i am able to explain my question. – Saurabh Jul 22 '20 at 21:27
  • What are frame1.py and frame2.py for? What if you had 20 Frame then you would have frame1.py, frame2.py, ..., frame20.py? that confuses me. remember that the files (.py) are only a separation to organize the code but it does not intervene in the operation (in general) – eyllanesc Jul 22 '20 at 21:30
  • Ok, Let me try to keep it simple. I have Frame1.py, Frame2.py & Main.py. When execute Main.py then frame created in Fram1.py should appear. When I click on a push button on Main.py then Frame created in Fram2.py should appear and first frame ( from Frame1.py) should disappear. I am not sure how to do that, if you could give some sample code that will help. – Saurabh Jul 22 '20 at 21:51
  • shows the code of frame1.py and frame2.py – eyllanesc Jul 22 '20 at 21:52
  • Sorry, I was not able to put the code in comment so put it in answer section. Please check and assist. Something like this i want to do. – Saurabh Jul 22 '20 at 22:08
  • NO, the answers section is exclusively for answers, edit your question and add it there. – eyllanesc Jul 22 '20 at 22:14
  • Sorry , I am new here. I have added the code as u suggested, Please share your answer. – Saurabh Jul 22 '20 at 22:19
  • You should spend a little of your time knowing the dynamics of the site if you want to get help. – eyllanesc Jul 22 '20 at 22:21
  • Sure. Now, I have put the all required info, Could you please assist ? i really appreciate – Saurabh Jul 22 '20 at 22:29

1 Answers1

0

Your question is not complex but if you require many improvements:

  • If you want to change the visibility of the widget (not replace) then you must use a QStackedLayout or a QStackedWidget.

  • In your original example you use QFrame but in your new code you use QMainWindow, and that is confusing since each widget has a goal, and in the case of QMainWindow it is to be a window with a predefined structure. So I will recreate frame1.py and frame2.py from scratch.

  • The code generated by QtDesigner are not widgets, so other classes must be used as a base (for more information see here)

Considering the above, the designs of frame1 and frame2 should be created based on QFrame:

enter image description here

frame1.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Frame</class>
 <widget class="QFrame" name="Frame">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Frame</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QLabel" name="label">
     <property name="text">
      <string>First Frame</string>
     </property>
     <property name="alignment">
      <set>Qt::AlignCenter</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

frame2.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Frame</class>
 <widget class="QFrame" name="Frame">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Frame</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QLabel" name="label">
     <property name="text">
      <string>Second Frame</string>
     </property>
     <property name="alignment">
      <set>Qt::AlignCenter</set>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

Convert the .ui to .py:

pyuic5 frame1.ui -o frame1_ui.py -x
pyuic5 frame2.ui -o frame2_ui.py -x

Create frame1.py and frame2.py:

frame1.py

from PyQt5 import QtWidgets

from frame1_ui import Ui_Frame


class Frame1(QtWidgets.QFrame, Ui_Frame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

frame2.py

from PyQt5 import QtWidgets

from frame2_ui import Ui_Frame


class Frame2(QtWidgets.QFrame, Ui_Frame):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

You must create QMainWindow with as many buttons as QFrame you want to show, and establish a QStackedWidget:

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <widget class="QStackedWidget" name="stackedWidget"/>
    </item>
    <item>
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <widget class="QPushButton" name="btn1">
        <property name="text">
         <string>PushButton</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="btn2">
        <property name="text">
         <string>PushButton</string>
        </property>
       </widget>
      </item>
      <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

Convert from .ui to .py:

pyuic5 mainwindow.ui -o mainwindow_ui.py -x

Implement the logic in main.py:

main.py

from PyQt5 import QtWidgets

from mainwindow_ui import Ui_MainWindow
from frame1 import Frame1
from frame2 import Frame2


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)

        self.frame1 = Frame1()
        self.frame2 = Frame2()

        self.stackedWidget.addWidget(self.frame1)
        self.stackedWidget.addWidget(self.frame2)

        self.btn1.clicked.connect(self.on_clicked1)
        self.btn2.clicked.connect(self.on_clicked2)

    def on_clicked1(self):
        self.stackedWidget.setCurrentIndex(0)

    def on_clicked2(self):
        self.stackedWidget.setCurrentIndex(1)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Eyllanesc , one question, do you have any example code of DB usage with python. I know how to do connectivity etc. I am just looking for standard approach. I checked your github page but could not find any. In case if you are aware, please share me the link. Thanks in advance.! – Saurabh Jul 23 '20 at 01:22