Class for Each QStackedWidget Page - python

I am using PyQt5 and Qt-Designer to design an application.
How do I instantiate a class for each page on QstackedWidget. I can do it in a single class, all widgets belong to the same QMainWindow. But, the issue is that the file will get too long and impracticale. How do I assign a class for each page. For example, class I handles all the widgets on Page I and class II handles all the widgets on Page II; in the QMainWindow file I can just assign an Object that represents each page.
How can I do it?

Just create multiple modules:
widget1.py
from PyQt5.QtWidgets import QWidget
class Widget1(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
widget2.py
from PyQt5.QtWidgets import QWidget
class Widget2(QWidget):
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
main.py
from widget1 import Widget1
from widget2 import Widget2
from PyQt5.QtWidgets import QMainWindow, QApplication
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setTitle("Stackked widget demo")
self.stacked = QStackedWidget(self)
self.setCentralWidget(self.stacked)
self.widget1 = Widget1()
self.stacked.addWidget(self.widget1)
self.widget2 = Widget2()
self.stacked.addWidget(self.widget2)
if __name__ == "__main__":
app = QApplication([])
mainwin = MainWindow()
mainwin.show()
app.exec_()

Related

How to display navbar inside figure?

I am building an application in PyQt5 that requires a lot of visualization. I use matplotlib and create a custom MplWidget the following way:
import sys
from PyQt5.QtWidgets import QWidget, QMainWindow, QVBoxLayout, QApplication
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
class MplWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.canvas = FigureCanvasQTAgg(Figure())
vertical_layout = QVBoxLayout()
vertical_layout.addWidget(self.canvas)
self.canvas.axes = self.canvas.figure.add_subplot(111)
self.setLayout(vertical_layout)
self.canvas.toolbar = NavigationToolbar(self.canvas, self)
self.layout().addWidget(self.canvas.toolbar)
self.layout().addWidget(self.canvas)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
widget = MplWidget()
self.setCentralWidget(widget)
self.show()
app = QApplication(sys.argv)
w = MainWindow()
app.exec_()
It looks like this:
Is there a way to put the navbar inside the figure? There are applications where options (that are contained by the navbar) are invisible until the user hovers the mouse over them, then the navbar appears inside the figure (in the upper left corner for example). This way it does not disturb the figure and takes up less space. I want to do something like that with matplotlib. Can I put widgets on top of each other like this?

Calling function in parent class and accessing parent self

In my main window I set a variable self.print_this. I then call another class PhotoViewer and then in that class I call a function from my main window. In that function I try to print the self.print_this but I get the following error: AttributeError: PhotoViewer object has no attribute print_this
How do I access the self of the window class or avoid sending the self of PhotoViewer to the printfromwindow function?
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QPoint, QRect, QSize, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QApplication, QRubberBand, QColorDialog
from PyQt5.QtGui import QPixmap, QPainter, QPen
import sys
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
Window.printfromwindow(self)
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_this='test'
PhotoViewer(self)
def printfromwindow(self):
print(self.print_this)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
Untested, but perhaps something like this. Note that in your code, you're calling methods of the Window and PhotoViewer classes but not constructing an instance of those classes.
You need to instantiate and retain those instances within their parent/child class instances, if you want to be able to reference their methods/properties.
As noted in my comment above, Window.printfromwindow(self) should not have the self argument (and should instead refer to <instance of Window>.printfromwindow().
In the Window constructor, I assign self.viewer an instance of the PhotoViewer class and pass self (which is a Window instance) as the parent argument to its constructor.
Then, in PhotoViewer class constructor, we do self.window = parent which should allow you to call self.window.printfromwindow():
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
self.window = parent # relates the "parent" Window instance to this "child" PhotoViewer instance
self.window.printfromwindow() # calls the printfromwindow method from the "parent" Window instance
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_this='test'
self.viewer = PhotoViewer(self) # creates an instance of PhotoViewer class as an attribute of this Window instance
def printfromwindow(self):
print(self.print_this)
If you want to make this more readily available (i.e., not just from within the constructor of PhotoViewer) then assign the Window.printfromwindow to an attribute of the PhotoViewer, like:
class PhotoViewer(QtWidgets.QGraphicsView):
photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(PhotoViewer, self).__init__(parent)
self.window = parent # relates the "parent" Window instance to this "child" PhotoViewer instance
self.printfromwindow = self.window.printfromwindow
class Window(QtWidgets.QWidget):
def __init__(self):
super(Window, self).__init__()
self.print_this='test'
self.viewer = PhotoViewer(self) # creates an instance of PhotoViewer class as an attribute of this Window instance
def printfromwindow(self):
print(self.print_this)
Since functions are first-level objects in python, you can do this:
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.viewer.printfromwindow()
To access a parent class you need to pass the parent class through the function. def printfromwindow(Window). Then you inherit all of the attributes from the parent class. You can also modify a subclass with super().__init__ to add changes to the sub classes without effecting the parent class

Updating child widget in Qt

I have a simple project with the following classes
class MainWindow(QMainWindow)
class Home(QWidget)
class Login(QWidget)
All I want is to be able to nest the QWidget classes (make them children of the QMainWindow) and display them INSIDE the MainWindow. I can't seam to figure out how to make the QWidgets "appear" after I've called them in the MainWindow.
Code is bellow:
import sys
from gui.MainWindow import Ui_MainWindow
from gui.home import Ui_Home
from gui.login import Ui_Login
from PyQt4.QtGui import QMainWindow, QApplication, QWidget
class Home(QWidget, Ui_Home):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
class Login(QWidget, Ui_Login):
def __init__(self):
QWidget.__init__(self)
self.setupUi(self)
class MainWindow(QMainWindow,Ui_MainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
#INSERT pushButton.click to go to HOME here
#INSERT pushButton.click to go to LOGIN here
def setHome(self):
self.label_Screen.setText("HOME")
self.mainwidget = Home()
#NEEDS SOMETHING HERE
def setLogin(self):
self.label_Screen.setText("LOGIN")
self.mainwidget = Login()
#NEEDS SOMETHING HERE
if __name__ == '__main__':
app = QApplication(sys.argv)
Main = MainWindow()
Main.show()
sys.exit(app.exec_())
I think I just need something where I've tagged "#NEEDS SOMETHING HERE", but I'm not sure what!
Cheers!
RESOLVED: thanks to kh25
Just had to add a layout to the QMainWindow and change the setHome to this:
def setHome(self):
self.label_Screen.setText("HOME")
self.currentScreen = Home()
self.layout.addWidget(self.currentScreen)
self.setLayout(self.layout)
The equivalent should be done for the setLogin method also.
You need to create a layout and add the widgets to this layout first. There are various types of layout. Read here:
http://doc.qt.io/qt-4.8/layout.html
For a simple case like yours I'd suggest either using a QHBoxLayout or QVBoxLayout.
Declare this layout. Call addWidget() on the layout for each of the Login and Home widgets and then call setLayout() on the QMainWindow.

How to auto-expand QTreeWidget items

The code below create a simple QTreeWidget with two items one parented to another.
I want the items to be expanded from the begining (so the user doesn't have to click arrow to expand the items):
Here is how it looks by default:
And here is how I would like it to be (expanded: item "C" is visible):
What attribute needs to be set in order for this to work?
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class Tree(QtGui.QTreeWidget):
def __init__(self, *args, **kwargs):
super(Tree, self).__init__()
parentItem=QtGui.QTreeWidgetItem('P')
self.addTopLevelItem(parentItem)
childItem=QtGui.QTreeWidgetItem('C')
parentItem.insertChild(0, childItem)
self.show()
tree=Tree()
sys.exit(app.exec_())
You can use QTreeWidget.expandToDepth().
In your case:
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class Tree(QtGui.QTreeWidget):
def __init__(self, *args, **kwargs):
super(Tree, self).__init__()
parentItem=QtGui.QTreeWidgetItem('P')
self.addTopLevelItem(parentItem)
childItem=QtGui.QTreeWidgetItem('C')
parentItem.insertChild(0, childItem)
self.expandToDepth(0)
self.show()
tree=Tree()
sys.exit(app.exec_())
You could also use expandAll() to expand everything instead of only to certain depth.

PyQT4 - communication between 2 windows

I've got problem with communication between 2 windows in PyQt.
main window = UI_Form (class MyForm)
additional window = UI_Employee (class Employee)
I'd like, when i clicked AddTextButton (Ui_Employee), to set text in LineTextEdit (UI_Form)
This is my code.
import sys
from PyQt4 import QtCore, QtGui
from Form import Ui_Form
from Window import Ui_Employee
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.AddButton,QtCore.SIGNAL("clicked()"), self.add)
def add(self):
self.Employee = Employee(self)
self.Employee.show()
class Employee(QtGui.QMainWindow):
def __init__(self,parent=None):
QtGui.QWidget.__init__(self,parent)
self.ui = Ui_Employee()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.AddRowButton,QtCore.SIGNAL('clicked()'), self.addText)
def addText(self):
self.Form = MyForm()
self.Form.ui.textEdit.setText('someText')
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
I've got problem with line in method addText. First and second lines are ignored. I dont know why.
In your method Employee.addText you create a new MyForm. This is probably not what you want. You can access your original myapp from inside Employee via self.parentWidget().
class Employee(QtGui.QMainWindow):
def addText(self):
self.parentWidget().ui.textEdit.setText('someText')

Categories

Resources