I would like to access ShowBase and its attributes from other class defined outside the ShowBase. The code below shows the problem exactly
from direct.showbase.ShowBase import ShowBase
from direct.gui.DirectGui import *
class Core(ShowBase):
def __init__(self):
ShowBase.__init__(self)
ButtonBar()
class ButtonBar():
def __init__(self):
self.btnsr = DirectButton(parent=pixel2d) # how do I access ShowBase from this class?
core = Core()
core.run()
With the current code I cant parent btnsr to pixel2d as ButtonBar has no access to ShowBase. How do I access ShowBase while keeping the code separated into two classes
This was answered in another forum. Answer by Thaumaturge below
What you have there should work, and indeed, on my machine it does.
However, there is one problem: you haven’t set a scale on your button, and as pixel2d uses a scale of 1 Panda-unit per pixel (I think it is), your button at its default size is too small to easily see. If you give it a larger scale (say, “300”), you should see it peek in at the top-left of the window (the origin of pixel2d).
(Unless you’re seeing some error that I’m not getting, of course, in which case: what are you seeing on your end?)
More generally, if I’m not much mistaken, ShowBase establishes a global variable named “base” that, along with several other globally-accessible things (including “render” and “pixel2d”), should be accessible from pretty much anywhere.
You can thus do things like this:
from direct.showbase.ShowBase import ShowBase
from direct.gui.DirectGui import *
class Core(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.cat = "Kitty"
class SomeOtherClass():
def __init__(self):
print (base.cat)
print (base.win.getSize())
core = Core()
mew = SomeOtherClass()
core.run()
Which should print “Kitty”, followed by “LVecBase2i(, )”, where and are the width and height of the window–in my case, they’re 800 and 600, repsectively.
(The call to “run” is superfluous to running the print-statements in the example above.)
Related
I try to create a proper container Class for Gtk in Python (MyBin in the code below). There seems to be no authoritative documentation on how to do that, only bits and pieces, which I glued together with trial and error. – There are many open questions, but let me focus on size_allocate() here:
What is the the original size_allocate() function doing? And what is my overlaid version in my container class supposed to do?
I already do 95% know that I have to replace the original method with my own by prepending “do_” to form the do_size_allocate() method (by trial and error – see code below; I could not find anything talking about all those “do_*” functions).
I found so far, that calling self.set_allocation(allocation) seems to be a good idea as is self.get_child().size_allocate(...) to give the child some working space (see code). – Any other obligations I have to fulfill? What is the original function doing additionally?
Regarding the allocation I pass down to the child: I need to adapt it (not in the code below yet). I successfully(?) used a fresh Gdk.Rectangle() on which I set x, y, width and height, but I somehow feel that it’s wrong and something with (do_)adjust_size_allocation() should be used instead. But how?
Lets look into the documentation of do_size_allocate():
This function is only used by Gtk.Container subclasses, to assign a
size and position to their child widgets. [“Only used”? Only called from? Only implemented at? Only overwritten by? – Well, I’m doing it already, but the doc wasn’t helpful in finding out how.]
In this function, the allocation may be adjusted. [How?] It will be forced to
a 1x1 minimum size [Can confirm only that get_allocation() will return a 1x1 if I don’t set anything.],and the adjust_size_allocation virtual method on
the child will be used to adjust the allocation. [What? For my own allocation? Or for the one I set on the child via ...get_child().size_allocate()? Who calls that adjust method? In which conditions is it not called before size_allocate()?] Standard adjustments
include removing the widget’s margins, and applying the widget’s
Gtk.Widget :halign and Gtk.Widget :valign properties.
#!/usr/bin/python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyBin(Gtk.Bin):
def __init__(self):
super().__init__()
def do_size_allocate(self, allocation):
print('PARENT METHOD do_size_allocate', allocation.width)
# if not called, `get_allocation()` in `do_draw()` will return a 1x1 rectangle
self.set_allocation(allocation)
# strangely required so that `do_draw()` will be called even on this class!
self.get_child().size_allocate(allocation)
def do_draw(self, c):
allocation = self.get_allocation()
print('PARENT do_draw()', allocation.width)
self.propagate_draw(self.get_child(), c)
class MyChild(Gtk.Button):
def __init__(self):
super().__init__()
self.connect('size-allocate', self.size_allocate_handler)
self.connect('draw', self.draw_handler)
def size_allocate_handler(self, self2, allocation):
print('CHILD signal size-allocate', allocation.width)
def draw_handler(self, self2, c):
allocation = self.get_allocation()
print('CHILD signal draw', allocation.width)
class MainWindow(Gtk.Window):
def __init__(self):
super().__init__(title='d2see test pattern')
the_child = MyChild()
my_container = MyBin()
my_container.add(the_child)
self.add(my_container)
self.show_all()
if __name__ == '__main__':
MainWindow()
Gtk.main()
I'm working on a game as a python learning project, and I'm trying to move away from having a single file. What is the best way to parse functions out so they can still access important objects? For example, I have an object that basically controls the window and calculates the sizes of ui elements when the user resizes the window. I'd like to be able to use the instance of this object without having to pass it into every function through an argument. An example:
function.py
import test
def add_foo():
newfoo.add()
test.py
import function
class foo:
def __init__(self):
self.x = 1
def add(self):
self.x += 10
newfoo = foo()
if __name__ == '__main__':
newfoo.add()
print newfoo.x
function.add_foo()
print newfoo.x
Am I just thinking about this the wrong way? The obvious solution here is to add an argument to function.add_foo() that lets me pass in the newfoo instance which lets me use it. But I find this to be a pretty cumbersome way to deal with an object that essentially needs to be universally accessible to every module and function if I call it since it changes anytime the user resizes the window.
It's also possible I should be structuring my programs in a different way entirely.
I've got the following file/folder setup for my Python project (practicing inheritance) as follows:
my_project/new_classes.py
my_project/human/Human.py
my_project/human/__init__.py (note, this is a blank file)
Although it appears that my class Samurai(Human) is setup correctly, I'm receiving the following error:
line 41, in <module>
tom.sacrifice()
AttributeError: 'Samurai' object has no attribute 'sacrifice'
Here's the code from my my_project/new_classes.py file:
from human.Human import Human
class Wizard(Human):
def __init__(self):
super(Wizard, self).__init__()
self.intelligence = 10
def heal(self):
self.health += 10
class Ninja(Human):
def __init__(self):
super(Ninja, self).__init__()
self.stealth = 10
def steal(self):
self.stealth += 5
class Samurai(Human):
def __init__(self):
super(Samurai, self).__init__()
self.strength = 10
def sacrifice(self):
self.health -= 5
# create new instance of Wizard, Ninja, and Samurai
harry = Wizard()
rain = Ninja()
tom = Samurai()
print harry.health
print rain.health
print tom.health
harry.heal()
print harry.health
rain.steal()
print rain.stealth
tom.sacrifice()
print tom.health
print tom.stealth
The code breaks when it gets to line tom.sacrifice() - any ideas why?
One other question I had was at first, when trying to import the parent class, I was using the statement from human import Human, which I thought would work (as I thought the formula was from module_directory import ModuleFileName, but was receiving an error as follows: TypeError: Error when calling the metaclass bases module.__init__() takes at most 2 arguments (3 given). I resolved this by changing my import statement to, from human.Human import Human and was wondering why this worked while the other did not? I may be confused about correctly importing classes and was hoping someone also might be able to help clarify.
[EDIT] Removed comments.
I resolved this by changing my import statement to, from human.Human import Human and was wondering why this worked while the other did not?
This is because the first "Human" is your Python module (Human.py). The Human class is inside it, so that's why your import statement must be as you wrote last. You do not want to import the module, but the class.
As to your AttributeError problem, it's odd as your classes seem OK. It's probably something unusual inside the Human class. Can we have the code in it?
EDIT
I see you found the solution for the AttributeError problem so I'll leave the answer for the second problem only.
If you initialize the class in the same document, this code below runs. The reason you are receiving the error is because you are trying to change a variable that was never set during initialization.
class Human(object):
def __init__(self):
self.health = 100
self.stealth = 0
self.strength = 15
You have to initialize the variables. Make sure that every Human has the properties that you would want to change. You can probably set = the health, but not change -=5 it if it was not initialized.
I found my solution, in my Samurai method, I had a spacing issue!
I reformatted my code with proper tabs and everything is working!
Correct code is as follows:
class Samurai(Human):
def __init__(self):
super(Samurai, self).__init__() # use super to call the Human __init__ method
self.strength = 10 # every Samurai starts off with 10 strength
def sacrifice(self):
self.health -= 5
Am having much trouble splitting PyQt code:
main.py
(PyQt modules)
from titles import *
appl = QApplication(sys.argv)
from main import Ui_MainWindow
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
QMainWindow.__init__(self)
self.u = Ui_MainWindow()
self.u.setupUi(self)
Titles(self)
titles.py
import sys
(PyQt modules)
(dbconnections)
class Titles():
def __init__(self, a): #<-- APP IS PASSED AS ARGUMENT AND NOW CALLED 'A'
a.u.table.setModel(titles)
a.u.lineEdit.setText("Titles Init")
a.u.add.clicked.connect(titles.insertRow)
class TitlesTableModel(QSqlTableModel):
def __init__(self):
QSqlTableModel.__init__(self)
self.setTable("titles")
self.setEditStrategy(self.OnFieldChange)
self.select()
def insertRow(self):
return self.insertRecord(-1, self.record())
a.u.lineEdit.setText("Insert Title")
titles = Titles()
Running main.py loads all data. QPushButton inserts a row, but doesn't set lineEdit to "Insert Title", because "a" isn't defined globally. Mostly tried creating a function in titles.py, triggered when main.py loads, looking like:
a = 0 #<-- THIS WAS A LAST STRAW AS WARNED BY RESEARCHING OTHERS, BUT AM LOST
def start(app):
global a
a = app
Titles(a); TitlesTableModel(a) #<-- EVEN THOUGH TITLES.PY IS IMPORTED, IT DIDN'T INCLUDE THE APP REFERENCE, SO AM TRYING TO 'REFRESH' THE TITLESTABLEMODEL
...with Titles & TitlesTableModel requiring an extra argument (self, a)
This loads data & functions, but again, insertRow doesn't update lineEdit.
Other attempt
change Songs class to
class Songs():
def __init__(self, a):
titles = Titles(a)
...(rest the same)
...and removing titles=Titles() from below the model definition. This again, shows data, but doesn't update lineEdit when pressing 'Add'.
Ultimately, it feels titles.py needs to have 'from main import *', but the main applications instance is defined after titles.py is called, and importing main.Main creates a recursion. Have tried inheriting multiple times via 'from main import Main', & writing 'class Songs(Main)' (so Songs can use the UI without passing a reference), but again, recursion occurs. Nine hours today plus three weeks prior looking at others, so am really stumped. Others somewhat recommended using a config file of even 'builtin', but that looks very bad.
Regards
In PyQt, classes generally use Signals to communicate between one another, especially when one class inherits from QWidget and the other does not inherit from that, as you've demonstrated by connecting signals (albeit wrongly, or at least you're missing bits and pieces of your code here on SO).
However, your insertRow() -> lineEdit method as it stands will never be called because it follows a return statement, meaning that the lineEdit part will never be hit. But I would be surprised if this fixed the problem.
Also, I would consider redesigning (refactoring) your code from the grounds up. Is there really a reason you have a different Titles() class?
While this is shameless self-promotion, I think you might benefit from my course on YouTube that deals with building Python applications using PySide (which is nearly identical to PyQt) - I discuss cross-thread (cross-class) communication a fair bit - link is http://youtube.com/Deusdies2
Your code has several issues, but the main problem is the snippet:
def insertRow(self):
return self.insertRecord(-1, self.record())
a.u.lineEdit.setText("Insert Title")
as you can see you're returning from the function before the line a.u.lineEdit.setText("Insert Title") get excecuted. Hence, this function willl never change the text of your QLineEdit.
Change your code b
def insertRow(self):
a.u.lineEdit.setText("Insert Title") # First change text.
return self.insertRecord(-1, self.record()) # Then insert record and return.
On the other hand: If you are working with global variables (a bad practice, I have to say) why are you passing it as arguments? Try to not use global variables at least is absolutly necesary.
Background:
I have been working on a game in Python, and in order to keep everything clean, organized and in a pythonic way, I have a folder containing multiple python files, each containing one big class, for example "MapEngine" or "NPCEngine".
From main.py, I am loading each class from each file and "glueing everything together with a "Game" class, such as:
from folder import *
class Game:
def __init__(self):
self.MapEngine = MapEngine.MapEngine()
...
def loop(self):
...
Since classes such as "CollisionEngine" requires data from other classes such as, "MapEngine", I usually assign some variables in the former (i.e. CollisionEngine) to the latter (i.e MapEngine), in order to use MapEngine's loaded map data or functions:
class CollisionEngine:
def __init__(self, MapClass, ...):
self.MapEngine = MapClass
Problem:
Well, since many classes have to be linked to others, it became hard after a while to figure out which class to load first in order to assign variables. Furthermore, classes like "EventEngine" need to have access to every other class. My code became hard to read, and I have trouble when 2 classes are equally important to each other.
Question:
I have heard of class inheritance, but I do not think it can be applied here because each class is very different as in its function. Therefore, is there a way to beautifully link every class together, as if it was all part of one big class? In other words, is there a way to refer to variables from other classes, from within a class?
(My thoughts: Perhaps, I can write a class called "Request", and it will act as a top level class manager. Although, I think I will have to use functions such as exec() or eval(), which are not efficient and are somewhat dangerous.)
This is my first post, I've tried to be as explicit as possible, please ask me for clarification, & thank you for your reply!
Consider separating your project into layers - that should help you keep things more organised and make the imports more natural.
The principle is that lower layers of your code "cake" shouldn't depend on (read: import) upper layers of your code.
For example you might have a foundation layer which contains common data structures, util classes and algorithms that are used in lots of your code at various layers.
Then you might have a model layer which depends on the foundation layer (i.e. data structures/utils/algorithms) but nothing else. The model layer provides models of objects within the domain.
You might then have a game layer which depends on the model layer (so it would be quite reasonable for modules in your game layer to import things from the model layer, but not vice versa).
Well, after many tries, I have figured out a (sketchy) way of solving my problem. Of course, as eddiewould suggested, I will have a better organization and multiple layers for my code, but if one would like to have multiple classes all linked together, simply include a variable to the main class (that called every class) to every class. I believe that a code snippet will explain it better:
main.py
engine_folder
----> engine_1.py
----> engine_2.py
in main.py, engine_1 and engine_2 are loaded:
from engine_folder import engine_1, engine_2
class game:
def __init__(self):
self.engine_1 = engine_1.engine(self, ...)
self.engine_2 = engine_2.engine(self, ...)
#where engine_1.engine and engine_2.engine are
#two classes that need to transfer data between
#each other
def run(self):
self.engine_1.run()
self.engine_2.run()
Notice how engine_1.engine's first argument is self, which refers to the top level class which called this class. Now, in engine_1, if we would want to print a variable from engine_2, the class would look similar to this:
class engine:
def __init__(self, top_level_class, ...):
self.top_level_class = top_level_class
def run(self):
print self.top_level_class.engine_2.random_var
This is very beautiful (besides the fact that print self.top_level_class.engine_2.random_var is very long), but compared to something like:
class EventEngine:
def __init__(self, Camera_Class, Map_Class, Character_Class, Skill_Class,
Interface_Class, Sprite_Class, Dialog_Class, Game_Class,
Item_Class):
self.ItemEngine = Item_Class
self.GameEngine = Game_Class
self.DialogEngine = Dialog_Class
self.SpriteEngine = Sprite_Class
self.SkillEngine = Skill_Class
self.CameraEngine = Camera_Class
self.MapEngine = Map_Class
self.CharacterEngine = Character_Class
self.IEngine = Interface_Class
The new version:
class EventEngine:
def __init__(self, top_level_class):
self.top = top_level_class
#a var from Map_Class can be called as such:
#self.top.MapEngine.map[0][1]
#and I can call variables from every class, not only those I
#have loaded like before
is much better and much cleaner.