Reuse PyQt window design across multiple instances - python

I have designed a window in QT designer and then converted it to Python code. Then I created class A and Class B which inherit from PYQT code. Then I create the third class call it C and inherit from class A and B.
from QTfile import *
from PyQt5.QtWidgets import *
class A(QMainWindow):
def __init__(self):
super().__init__()
self.A1= Ui_MainWindow()
self.A1.setupUi(self)
class B(QMainWindow):
def __init__(self):
super().__init__()
self.B1= Ui_MainWindow()
self.B1.setupUi(self)
Now the problem is when I want to use super().__init__() function, I only can initiate one of them.
class C( A,B):
def __init__(self):
super().__init__()
If I use A.__init__() and B.__init__(), it works again only for one classes
class C( A,B):
def __init__(self):
A.__init__()
B.__init__()
Now the question is how can I initiate the multiple classes?

If you want to reuse the design in multiple window instances, you can try the following:
class BaseWindow(Ui_MainWindow, QMainWindow):
def __init__(self):
Ui_MainWindow.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
class A(BaseWindow):
def __init__(self):
super().__init__()
class B(BaseWindow):
def __init__(self):
super().__init__()

Related

Metaclass conflict when trying to create a Python abstract class that also subclasses a PySide6 class

I'm trying to create an abstract base class that also inherits an arbitrary PySide6 class. However, the following produces the error TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases.
from abc import ABC, abstractmethod
from PySide6.QtWidgets import QApplication, QWidget
class MyBaseWidget(QWidget, ABC):
def __init__(self, parent=None):
super().__init__(parent=parent)
#abstractmethod
def foo(self):
pass
class MyConcreteWidget(MyBaseWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
app = QApplication([])
widget = MyConcreteWidget()
widget.show()
app.exec_()
I tried to resolve this using the solution seen below (inspiration came from Resolving metaclass conflicts, http://www.phyast.pitt.edu/~micheles/python/metatype.html, Multiple inheritance metaclass conflict, etc.).
class MyMeta(ABCMeta, type(QWidget)): pass
class MyBaseWidget(QWidget, metaclass=MyMeta):
def __init__(self, parent=None):
super().__init__(parent=parent)
#abstractmethod
def foo(self):
pass
class MyConcreteWidget(MyBaseWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
app = QApplication([])
widget = MyConcreteWidget()
widget.show()
app.exec_()
This executes without error, but I was expecting an error like TypeError: Can't instantiate abstract class MyConcreteWidget with abstract methods foo when instantiating MyConcreteWidget. Not being able to enforce the base class's interface really takes away the benefit of having an abstract base class. Any solutions?

How to bind a function to an Action from Qt menubar?

I'm using Python3 and PyQt5, make my widgets and windows in Qt Designer. What is more, I do not generate .py files from a .ui. I simply load it using next code:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi('UI/Qt/source/MainWindow.ui', self)
So, I wanted to know, how do I bind menu bar actions to functions.
Is there any way I can do something like this?
self.getActionByName("actionTest_Action").connect(self.do_something)
It is not necessary to use findChild when using loadUi since this method adds the object to the attributes of the class using the objectName as a name, for example in this particular case a cleaner code than the other answer is:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi('UI/Qt/source/MainWindow.ui', self)
self.actionTest_Action.triggered.connect(self.test)
def test(self):
print("Test")
So, answering my own question..
One way to do this, is to find an action by using FindChild(QAction, "ActionName") function, and then bind a function using connect() function
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
uic.loadUi('UI/Qt/source/MainWindow.ui', self)
action = self.findChild(QAction, "actionTest_Action")
action.triggered.connect(self.test)
def test(self):
print("Test")

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

How to create classes within classes?

I want to clearly be able to see that my class LoginScrollbar is a class (also a tkinter Frame) composing of elements belonging to the LoginFrame and not for example the MainWindow which is launched after logging in as it is very unclear which classes are simpley frameworks to display elements under which Frame (main class). What is the best way to achieve this goal?
I don't know what to try.
This is my code I currently have, as you can see it's very unclear that MainWindow and MainWindowScrollbar are related. It's hard to tell that MainWindowScrollbar is a grouping that contains elements for MainWindow. It appears that LoginFrame,LoginScrollbar,Mainwindow,MainwindowScrollbar are all classes in the same classification.
class LoginFrame:
def __init__(self):
#somecode
class LoginScrollbar:
def __init__(self):
#somecode
class MainWindow:
def __init__(self):
#somecode
class MainWindowScrollbar:
def __init__(self):
#somecode
This is what I want, is this somehow possible without creating a seperate file for each frame of my program?
class LoginFrame:
def __init__(self):
#somecode
class LoginScrollbar:
def __init__(self):
#somecode
class LeftSideOfLogin:
def __init__(self):
#WidgetsForLeftSideOfLogin
class MainWindow:
def __init__(self):
#somecode
class MainWindowScrollbar:
def __init__(self):
#somecode
class MainWindowRightSide:
def __init__(self):
#WidgetsForRightSideOfMainWindow

what is the best way to embed program logic that seats in some algorithm class into pyqt4 user interface

class SomNetwork(object):
def __init__(self, dataset):
# some parameters that are not important here
pass
def one_step_learn(self, k, sigma_0, gamma_0, alfa, mcolor,population_of_ids):
pass
def learn(self):
pass
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_QSom()
self.ui.setupUi(self)
self.frame = MyFrame(self)
self.setCentralWidget(self.frame)
self.frame.start()
self.show()
class MyFrame(QtGui.QFrame):
simulationSpeed = 5000
def __init__(self, parent):
super(Ramka, self).__init__(parent)
self.init_Board()
def init_Board(self):
self.timer = QtCore.QBasicTimer()
I would like to be able to interact with SomNetwork class in order to be able to call its methods from within inside of the MyFrame class methods. Are there any special design patterns that would suit this example the most or should I just add instance of the class as a field to the MyFrame class.
Thanks of your help in advance!
I don't know if your question is heading towards this, but for your network you could try to subclass a QtCore.QObject instead. On the whole you should instance your network as a member of your QMainWindow, so your frame and the net can interact via signals and slots.
... By the way, there is a little flaw in your code, when you call the constructor of a QWidget in the subclass of a QMainWindow.

Categories

Resources