how to call a function from a different class in python pyqt - python

Forgive me for overcomplicating this, thats just how it happened. so i have these two classes one's windowm and the other's modelm, i am trying to get it to re-start whenever newGame() is called so here are some snippets of code:
class windowm(QMainWindow):
def __init__(self):
super(windowm, self).__init__()
# a generic widget for the center of the window
widget = QWidget()
self.setCentralWidget(widget)
and the other class:
class Model:
def __init__(self):
# setup is just starting a new game, so use that method
self.newGame()
def newGame(self):
super(windowm, self).__init__()
yes i understand it is complicated and forgive me for that, that's just how the assignment is. So i understand that this has been answered before i just have this one annoying unique scenario. so as you can see in the second code snippet i am attempting to get it to jump back into the class "windowM" and into the function init(self) to re-start the game. please help and thank you!

You'll have to create a new instance of your other class and then use that to call the game function.
I think you'll want to change your game class though, so it's easier to start a new game from the other class.
class Model:
def startNewGame(self):
# setup is just starting a new game, so use that method
self.newGame()
def newGame(self):
super(windowm, self).__init__()
Then it can be used like this:
class windowm(QMainWindow):
def __init__(self):
super(windowm, self).__init__()
# a generic widget for the center of the window
widget = QWidget()
self.setCentralWidget(widget)
# create an instance of the other class
ng = Model()
# start a new game
ng.startNewGame()

Related

How do I create GUI classes for windows, which have subwindows/classes that can access to the main GUI's functions?

How do I create GUI classes for windows which have subwindows/classes that can access the main GUI's functions?
I have the below code which modifies the compiled .ui code from designer. What I want it to do is, when clicking the top-right "X", or using File -> Exit function, to close the window comprising the Window_SecondWindow class, and show the main window again--effectively calling the main window's show() from the subclass. I want to show only one window at a time.
When the code is run as-is, the Window_SecondWindow class hides, but immediately shows again, leading me to believe super is acting as self.
from PyQt5 import QtWidgets
from GUI import compiled_MainWindow
from GUI import compiled_SecondWindow
class Window_MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.ui = compiled_MainWindow.Ui_MainWindow()
self.ui.setupUi(self)
self.ui.closeEvent = self.clicked_EXIT
# connect widgets
self.ui.Btn.clicked.connect(self.clicked_Btn)
self.ui.actionExit.triggered.connect(self.clicked_EXIT)
# add windows
self.SecondWindow = SecondWindow()
# more windows attached to main window
def clicked_Btn(self):
self.hide()
self.SecondWindow.show()
def clicked_EXIT(self):
self.close()
class Window_SecondWindow(Window_MainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = compiled_SecondWindow.Ui_MainWindow()
self.ui.setupUi(self)
self.ui.closeEvent = self.clicked_EXIT
self.ui.actionExit.triggered.connect(self.clicked_EXIT)
def clicked_EXIT(self):
self.hide()
super().show()
Before answering your question, I'd like to address some important aspects.
First of all, never edit the generated code from pyuic to create your programs. They are intended to be used as imported modules, mostly as "resources": you import and integrate them into your code, but you should always leave them as they are. See the documentation on using Designer for more insight about this.
Be careful in overriding functions within the __init__: some functions are not "virtual" (thus, cannot be overwritten in such a way) and in some cases Qt always calls the base class function name anyway; just overwrite the method and call the base class implementation with super() if required. Also, closeEvent has the close event as a mandatory argument, and you have to add that to your overridden function, even if you don't use it (in the following examples I'm just using *args). That said, you should never use an overridden function as a slot that has a different argument, or viceversa.
Finally, you should not use capitalized names for attribute and variable names, as it is confusing and prone to errors (capitalization is mostly used for class names only, not their instancies).
Now, the answer
You are almost right, super() acts "as self", in the sense that it just calls the inherited show() method of the class against the instance. So, it calls the show method of Window_MainWindow, but since the instance is the second window, it's the same as doing Window_MainWindow.show(self), with self being the Window_SecondWindow instance; it is exactly as doing self.show().
There are two (and a half) possibilities.
The first, more obvious solution, is to give a reference of the main window instance to the second one:
class Window_MainWindow(QtWidgets.QMainWindow):
def __init__(self):
# ...
self.secondWindow = Window_SecondWindow()
self.secondWindow.mainWindow = self
class Window_SecondWindow(Window_MainWindow):
# ...
def clicked_EXIT(self, *args):
self.hide()
self.mainWindow.show()
Be aware that while, as #noras points out in the comment, you could set the main window as a parent in the init argument, but this only works as expected with QMainWindow and QDialog descendants; if the child widget is of any other kind, it will be shown inside the parent, not as a separate window.
The second (and more "Qt-wise correct") is to create a signal for the second class that is emitted when it's closed, and connect it in the main window so that it's shown again when that happens:
class Window_MainWindow(QtWidgets.QMainWindow):
def __init__(self):
# ...
self.secondWindow = Window_SecondWindow()
self.secondWindow.closed.connect(self.show)
class Window_SecondWindow(Window_MainWindow):
closed = QtCore.pyqtSignal()
def clicked_EXIT(self, *args):
self.hide()
self.closed.emit()
The second-and-a-half solution is to use an event filter:
class Window_MainWindow(QtWidgets.QMainWindow):
def __init__(self):
# ...
self.secondWindow = Window_SecondWindow()
self.secondWindow.installEventFilter(self)
def eventFilter(self, source, event):
if source == self.secondWindow and event.type() == QtCore.QEvent.Close:
self.show()
return super().eventFilter(source, event)

PyQt5 Making a subclass widgets

so I was wondering how I could make a subclass of a widget
For example if I wanted to create a widget, that inherited methods and attributes from QtWidgets.QPushButton, however I would create extra methods and attributes on top of that.
class Coord(QtWidgets.QPushButton):
def __init__(self):
super(Coord, self).__init__()
self.coordinates = []
#basically adding attributes to the object "QPushButton"
def set_text(self,text):
self.setText(text)
chrcount = 100 / len(text)
self.setStyleSheet("font-size: {}".format(chrcount))
#This will set the text of the button, yet will resize it appropriatly
This is an example. However, it creates the "button" widget as a new window. I was wondering how I could get it to act like QPushButton would anyway, just with the extra features I'd like to add to it
Edit: Fixed-
replaced my "super" function from
def __init__(self):
super(Coord, self).__init__()
to
def __init__(self,parent):
super(Coord, self).__init__(parent)
Don't really know how that fixed it but hey ho!
you can use the qt designer to create a button and set all possible features of a button there. If that is not enough you can adjust the button in your coding like self.button.whatever.set....If that is not enough attache the button to a class in qt designer, create a module and a class and do adjust whatever you want.

How to access variables in other classes

In Functions class, I would like to access the variable of the Frame class.
Please tell me if there is any way.
class Functions():
def changeText():
...
...
I want to change the 'text' in the Frame class
ex )Frame.text.SetFont('change text')
GUI element
class Frame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, ....)
....
....
self.text = wx.StaticText(panel, .....)
You can do this by sending an instance of the class to the function:
class myClass(object):
def __init__(self, text):
self.text = text
def changeText(input):
input.text = "world"
example = myClass("hello")
changeText(example)
You will have to tell your objects what to work on. Out of thin air your Functions instance will not know (how should it?) what Frame should be. You could make Frame a global, but I do not think that is a good idea (it will break if you want to work with more than one frame instance). So you would write:
class Functors:
...
def set_text(txt_frame, the_text):
"""txt_frame has to be a :class:`my_txt_frm` instance with ``self.text`` being a ``StaticText`` instance."""
txt_frame.text.SetLabel(the_text)
class my_txt_frm(wx.Frame): # do not name the derived class Frame to make more clear it is derived!
def __init__(# ...
...
self.text = wx.StaticText(#...
So now comes the interesting part: how to tie the parts together? You have to have something like that somewhere in your code:
funct = Functors() # the class which know how to do things on our GUI elements
frm = my_txt_frm(#...
Some lines later...
funct.set_text(frm, 'thenewtext')
So for your app which has the bigger picture it is necessary to keep references to the building blocks to be able to tie them together later.
An orderly way to tie things together is called MVC (see a great example in the wxPython wiki). Even if you do not want to model your app after this paradigm, you can learn from it how to reason about separation of concerns.

Tkinter; Toplevel in a new class

I'm working on a project using Python and Tkinter. I want to modularize it.
One of the main problems is that the implementation of my Toplevel widget is too big.
I heard that it's possible to put this widget in a new class. The problem is I don't know how.
Here is how I define my main window:
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
Config(self)
So for my Toplevel widget I tried:
class Config(tk.Toplevel):
def __init__(self, main):
tk.Toplevel.__init__(self)
Is it the right way to do this ?
Yes, that is the right way to do it. Though, you might want to keep a reference to the window so you can call methods on it later:
self.config = Config(self)

Create frame class in Tkinter Gui

I'm working on a Gui and I'd like to know how to create a class that would implement frame.
e.g.
class WindowContent(Tkinter.?)
""" This class would create a frame for my program window """
class App(Tkinter.Tk):
""" main window constructor """
def __init__(self):
Tkinter.Tk.__init__(self)
program_window = WindowContent ?
self.config(window = window_content) ?
rgds,
I found the answer :
class WindowProgram(Tkinter.Frame)
""" This class creates a frame for my program window """
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
class App(Tkinter.Tk):
""" application constructor """
def __init__(self):
Tkinter.Tk.__init__(self)
self.window_program = Window_Program(self)
Why do you want a class that creates several frames? Creating one class that creates multiple frames is not a very good solution. You don't need a single class for that.
Either create separate classes for each frame, or just create methods in your app to create each frame. I prefer the latter, but if you want a frame that can be used in multiple contexts it sometimes makes sense to create a class.
When I do a GUI I structure my code like this:
class App(Tkinter.Tk):
def __init__(self):
Tkinter.Tk__init__(self)
self.menubar = self.makeMenubar(...)
self.frame1 = self.makeFrame1(...)
self.frame2 = self.makeFrame2(...)
self.configure(menu=self.menubar)
self.frame1.grid(...)
self.frame2.grid(...)
In this way, each major section gets its own method to hide the details of widget creation. You could, of course, have each frame be a custom object but usually that's unnecessary.

Categories