I'm searching for help about lists in pgu gui for python. I need to know which methods and properties they have, so I can include them in my programs
My first suggestion
Use python's builtins to introspect on
import pgu.gui.List
import inspect
help(pgu.gui.List) # to read out the doc strings
print dir(pgu.gui.List) # to get the namespace of List class
# to get all methods of that class
all_functions = inspect.getmembers(pgu.gui.List, inspect.isfunction)
Always look at the source code, when it is available
http://code.google.com/p/pgu/source/browse/trunk/pgu/gui/area.py
From the code: You can create and clear a list.
class List(ScrollArea):
"""A list of items in an area.
<p>This widget can be a form element, it has a value set to whatever item is selected.</p>
<pre>List(width,height)</pre>
"""
....
def clear(self):
"""Clear the list.
<pre>List.clear()</pre>
"""
...
Usage :
# Create the actual widget
usagelist = gui.List(width, height)
Related
i want to find any object by a objectname string name inside of the QApplication
Something like
QApplication.instance().findByClassName("codeEditor")
which should return a list of widgets with this classname that i can iterate over if there is more then one
[QPushButton (QPushButton at: 0x0000008EA3B3DD80), QWidget (QWidget at: 0x0000008EA3F33F40)]
I have read this but it requires a object and i want something like *
This is something i came up with for testing:
def findWidget(name):
name = name.lower()
widgets = self.topLevelWidgets()
widgets = widgets + self.allWidgets()
ret = dict()
c = 0
for x in widgets:
c += 1
if name in x.objectName.lower() or name in str(x.__class__).lower():
ret["class:"+str(x.__class__)+str(c)] = "obj:"+x.objectName;continue
if hasattr(x, "text"):
if name in x.text.lower():
ret["class:"+str(x.__class__)+str(c)] = "obj:"+x.objectName
return ret
It doesn't even find the 'InfoFrame' which is clearly there:
>>> widget("info")
{}
I came up with this which works quite well
def getWidgetByClassName(name):
widgets = QApplication.instance().topLevelWidgets()
widgets = widgets + QApplication.instance().allWidgets()
for x in widgets:
if name in str(x.__class__).replace("<class '","").replace("'>",""):
return x
def getWidgetByObjectName(name):
widgets = QApplication.instance().topLevelWidgets()
widgets = widgets + QApplication.instance().allWidgets()
for x in widgets:
if str(x.objectName) == name:
return x
def getObjects(name, cls=True):
import gc
objects = []
for obj in gc.get_objects():
if (isinstance(obj, PythonQt.private.QObject) and
((cls and obj.inherits(name)) or
(not cls and obj.objectName() == name))):
objects.append(obj)
return objects
In Python, this can be done for any class using the gc module. It provides a method for retrieving the references of all objects tracked by the garbage-collector. This is obviously a quite inefficient approach, but it does (almost) guarantee that any type of object can be found.
Here's a function to get a list of all QObject instances either by class-name or object-name:
def getObjects(name, cls=True):
objects = []
for obj in gc.get_objects():
if (isinstance(obj, QtCore.QObject) and
((cls and obj.inherits(name)) or
(not cls and obj.objectName() == name))):
objects.append(obj)
return objects
This is only really a debugging tool, though - for a large application, there could easily be several hundred thousand objects to check.
If you only need objects which are subclasses of QWidget, use this function:
def getWidgets(name, cls=True):
widgets = []
for widget in QtGui.QApplication.allWidgets():
if ((cls and widget.inherits(name)) or
(not cls and widget.objectName() == name)):
widgets.append(widget)
return widgets
PS:
If you want to find all objects which are subclasses of QObject, this can only be achieved if you can somehow ensure that all the instances in your application have a valid parent (which, by definition, must also be a QObject). With that in place, you can then use root_object.findChildren(QObject) to get the full list. It is also possible to use findChild or findChildren to search for individual objects by object-name (optionally using a regular-expression, if desirable).
It is not possible to find all QObject instances in general. Qt does not keep track of them since objects can be used in multiple threads and the overhead of tracking them would be unnecessarily high.
Qt does keep track of all widgets, though, since widgets can only exist in the main thread, and they are fairly heavy objects so tracking them has comparably little overhead.
So, you could search all widgets you get from QApp.allWidgets(), and all of their children. You can also look through children of objects you otherwise have access to. But if a given object is parentless, or is not owned by a widget, then you won't find it that way.
I am building a program that will store some complex objects, and I am using wxPython for the UI. The objects hierarchy will have a tree representation (TreeCtrl). I am using a dictionary to map objects from the UI to the database, using the TreeItemIds returned by AppendItem as keys and the objects themselves as values (actually I am not using the objects as values, but it simplifies the problem). The following snippet exemplifies what I am trying to do:
import wx
class ComplexObject(object):
def __init__(self, name, otherdata):
self.name = name
self.otherdata = otherdata
class TestFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(TestFrame, self).__init__(*args, **kwargs)
self.tree = wx.TreeCtrl(self)
self.rootid = self.tree.AddRoot("Root")
self.tree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.onrightclick)
self.objectmap = {}
def addobject(self, obj):
itemid = self.tree.AppendItem(self.rootid, obj.name)
self.objectmap[itemid] = obj
def onrightclick(self, event):
itemid = event.GetItem()
if itemid == self.rootid:
return
obj = self.objectmap[itemid]
print "Do something with ComplexObject {}".format(obj.name)
if __name__ == '__main__':
app = wx.App(False)
testframe = TestFrame(None)
for i in range(3):
obj = ComplexObject('obj{}'.format(i), i)
testframe.addobject(obj)
testframe.Show()
app.MainLoop()
When I right-click an entry in the tree I get a KeyError, because the object I get from the event (itemid = event.GetItem()) is not the same I get when I add an item (itemid = self.tree.AppendItem(self.rootid, obj.name)). Is this the expected behavior? How should I proceed to achieve what I am trying to do? I am starting to experiment with SetPyData and GetPyData, but I hope there is a better way to do that.
Thank you very much.
Platform Information: MS Windows 7, Python 2.7.9, wxPython 2.8.12.1
Yes, it is expected.
You can think of the TreeItemId as a closed box with an implementation dependent handle inside, and that the treectrl is the only one that can open the box to get the handle out. You may see different boxes at different times for the same tree item, but they will all have the same handle inside. But since the handle itself is an implementation detail there is no program access to it.
Using SetPyData to associate data to tree items is the proper way to do things like this. If you want to keep your associated data in a separate dictionary then you could generate unique dictionary keys when adding the items, and then pass they key to SetPyData, and use GetPyData to fetch the key later when you need to fetch the value object from the dictionary.
I am working on a project using pydev. This is my first project using pydev.
My project structure is:
myProject(project)
projFolder(folder)
userInterface.py
makeTriangle.py
I've a file userInterface.py. This file is used to take input from the user and to show the desired result via a class after doing some operations on the input in another file.
Now I've to pass the value returned from this file to another file named makeTriangle. But I am unable to do that. How can I pass the value returned from one file to another file?
Please let me know if I am doing any thing wrong here. Your response will help me to sharpen my skills.
### userInterface.py #########
class userInterface():
getList = []
maxList = 4
def getUserList(self):
print("*** getting user input ***")
while len(self.getList) < self.maxList:
item = input("enter numbers: ")
self.getList.append(item)
return self.getList
def showUserList(self,passedList):
print("*** showing user input ***")
print (passedList)
### makeTriangle.py #########
from userInterface import userInterface
class makeTriangle():
### how to get the value of getUserList here
I would put your initialiaztion of userInterface variable in the init method:
### userInterface.py #########
class userInterface():
def __init__(self):
#do initialization.
self. getList = []
self. maxList = 4
Then in your other file you can create an instance of userInterface and invoke the methods needed. For instance in the example below the doSomething uses getUserList of userInterface.
### makeTriangle.py #########
from userInterface import userInterface
class makeTriangle():
def __init__(self):
#do any initialization.
def doSomething():
### how to get the value of getUserList here
UI = userInterface()
input = UI.getUserList()
for num in input:
#do whatever
I strongly recommend you read how classes work in python. Checkout https://docs.python.org/3.2/tutorial/classes.html
I agree that you really need to read the docs, but basically any thing that you labled with self.xxxx and any methods you made can be accessed in makeTriange by saying userInterface.xxxxx
so if you need access to the maxList variable, its:
userInterface.maxList
if you need to use the getuserList() function, its
userInterface.getUserList()
But like the other poster said, you should be using init(). Right now, you are making CLASS variables. Remember, you usually want to give these attributes to the objects you are making with the class, not the class it self, the init() method will do this for you.
right now, every time you are making a triangle, you are appending to the same list because getList is a CLASS method, but I think you want a new list for each triangle, so you need to make it an INSTANCE method by putting it in init(), which implicitly gets called every time you make an object with the class.
all of this is explained in the docs.
I currently have a CSV file with over 200 entries, where each line needs to be made into its own class file. These classes will be inheriting from a base class with some field variables that it will inherit and set values to based on the CSV file. Additionally, the name of the python module will need to be based off an entry of the CSV file.
I really don't want to manually make over 200 individual python class files, and was wondering if there was a way to do this easily. Thanks!
edit* I'm definitely more of a java/C# coder so I'm not too familiar with python.
Some more details: I'm trying to create an AI for an already existing web game, which I can extract live data from via a live stream text box.
There are over 200 moves that a player can use each turn, and each move is vastly different. I could possibly create new instances of a move class as it's being used, but then I would have to loop through a database of all the moves and its effects each time the move is used, which seems very inefficient. Hence, I was thinking of creating classes of every move with the same name as it would appear in the text box so that I could create new instances of that specific move more quickly.
As others have stated, you usually want to be doing runtime class generation for this kind of thing, rather than creating individual files.
But I thought: what if you had some good reason to do this, like just making class templates for a bunch of files, so that you could go in and expand them later? Say I plan on writing a lot of code, so I'd like to automate the boilerplate code parts, that way I'm not stuck doing tedious work.
Turns out writing a simple templating engine for Python classes isn't that hard. Here's my go at it, which is able to do templating from a csv file.
from os import path
from sys import argv
import csv
INIT = 'def __init__'
def csvformat(csvpath):
""" Read a csv file containing a class name and attrs.
Returns a list of the form [['ClassName', {'attr':'val'}]].
"""
csv_lines = []
with open(csvpath) as f:
reader = csv.reader(f)
_ = [csv_lines.append(line)
for line in reader]
result = []
for line in csv_lines:
attr_dict = {}
attrs = line[1:]
last_attr = attrs[0]
for attr in attrs[1:]:
if last_attr:
attr_dict[last_attr] = attr
last_attr = ''
else:
last_attr = attr
result.append([line[0], attr_dict])
return result
def attr_template(attrs):
""" Format a list of default attribute setting code. """
attr_list = []
for attr, val in attrs.items():
attr_list.append(str.format(' if {} is None:\n', attr, val))
attr_list.append(str.format(' self.{} = {}\n', attr, val))
attr_list.append(' else:\n')
attr_list.append(str.format(' self.{} = {}\n', attr, attr))
return attr_list
def import_template(imports):
""" Import superclasses.
Assumes the .py files are named based on the lowercased class name.
"""
imp_lines = []
for imp in imports:
imp_lines.append(str.format('from {} import {}\n',
imp.lower(), imp))
return imp_lines
def init_template(attrs):
""" Template a series of optional arguments based on a dict of attrs.
"""
init_string = 'self'
for key in attrs:
init_string += str.format(', {}=None', key)
return init_string
def gen_code(foldername, superclass, name, attrs):
""" Generate python code in foldername.
Uses superclass for the superclass, name for the class name,
and attrs as a dict of {attr:val} for the generated class.
Writes to a file with lowercased name as the name of the class.
"""
imports = [superclass]
pathname = path.join(foldername, name.lower() + '.py')
with open(pathname, 'w') as pyfile:
_ = [pyfile.write(imp)
for imp
in import_template(imports)]
pyfile.write('\n')
pyfile.write((str.format('class {}({}):\n', name, superclass)))
pyfile.write((str.format(' {}({}):\n',
INIT, init_template(attrs))))
_ = [pyfile.write(attribute)
for attribute
in attr_template(attrs)]
pyfile.write(' super().__init__()')
def read_and_generate(csvpath, foldername, superclass):
class_info = csvformat(csvpath)
for line in class_info:
gen_code(foldername, superclass, *line)
def main():
read_and_generate(argv[1], argv[2], argv[3])
if __name__ == "__main__":
main()
The above takes a csvfile formatted like this as its first argument (here, saved as a.csv):
Magistrate,foo,42,fizz,'baz'
King,fizz,'baz'
Where the first field is the class name, followed by the attribute name and its default value. The second argument is the path to the output folder.
If I make a folder called classes and create a classes/mysuper.py in it with a basic class structure:
class MySuper():
def __init__(*args, **kwargs):
pass
And then run the code like this:
$ python3 codegen.py a.csv classes MySuper
I get the files classes/magistrate.py with the following contents:
from mysuper import MySuper
class Magistrate(MySuper):
def __init__(self, fizz=None, foo=None):
if fizz is None:
self.fizz = 'baz'
else:
self.fizz = fizz
if foo is None:
self.foo = 42
else:
self.foo = foo
super().__init__()
And classes/king.py:
from mysuper import MySuper
class King(MySuper):
def __init__(self, fizz=None):
if fizz is None:
self.fizz = 'baz'
else:
self.fizz = fizz
super().__init__()
You can actually load them and use them, too!
$ cd classes
classes$ python3 -i magistrate.py
>>> m = Magistrate()
>>> m.foo
42
>>> m.fizz
'baz'
>>>
The above generates Python 3 code, which is what I'm used to, so you will need to make some small changes for it to work in Python 2.
First of all, you don't have to seperate python classes by files - it is more common to group them by functionality to modules and packages (ref to What's the difference between a Python module and a Python package?). Furthermore, 200 similar classes sound like a quite unusual design - are they really needed or could you e.g. use a dict to store some properties?
And of course you can just write a small python script, read in the csv, and generate one ore more .py files containing the classes (lines of text written to the file).
Should be just a few lines of code depending on the level of customization.
If this list changes, you even don't have to write the classes to a file: You can just generate them on the fly.
If you tell us how far you got or more details about the problem, we could help in completing the code...
Instead of generating .py files, read in the csv and do dynamic type creation. This way, if the csv changes, you can be sure that your types are dynamically regenerated.
I'm writing an exporter for a game my friend and I are making and it involves setting custom properties and tags to objects which are then recognized in the game and dealt with accordingly. Our engine, which is written in C/C++ has been successfully tested with my current version of the export script, and I''m currently working on tidying it up.
The script uses Blender's feature of custom properties to write custom tags to output file. The model typically consists of multiple 'parts' (Blender mesh objects that are parented to form a tree, with one 'parent' and multiple 'child' objects) and some of those parts are simple Blender Empty objects (for only it's X, Y and Z coordinates are needed) with custom properties that mark where things like ship's propulsion (it's a 3D shooter) are placed, or where the flames/explosions appear when ship's been shot. Those empty parts are also parented to either 'root' object or any of it's children. So far it's been working good, I have written a generic Operator class and some extended classes that reside in a panel which set part's properties (pretty handy since you don't have to add those custom properties by hand).
Now I want to speed thing up even more, that is to be able to simply click on an operator of desired type, and it should automatically add it to the scene and parent it to the active/selected object. I know how to do that, but I can't get those operators to change their labels. Basically, what I want is to operator to say 'Bullet point' when an existing empty is selected (I've got that part done), and when there's a mesh object selected to say 'Add bullet point'. So I just need a way to dynamically change operators' labels depending on the context (as the title of the question states clearly :))
This is what I got so far:
class OBJECT_OT_tg_generic (bpy.types.Operator):
bl_label = "Sets Generic Part Type"
bl_idname = "rbm.set_generic_part_type"
OB_TYPE = None
#classmethod
def poll (cls, context):
act = context.active_object
if 'Type' in act.keys ():
if act['Type'] == cls.OB_TYPE:
cls.bl_label = 'foo'
print (cls.bl_label)
# this prints foo but doesn't change the label
return False
return True
def execute (self, context):
# TODO: add code to automatically place empties and parent them to active object
bpy.context.active_object['Type'] = self.OB_TYPE
return{"FINISHED"}
And an example of a subclass:
class OBJECT_OT_tg_bullet_point (OBJECT_OT_tg_generic):
bl_label = "Bullet Point"
bl_idname = "rbm.set_bullet_point"
OB_TYPE = OT_BULLET_POINT
Here's how it looks in Blender:
http://i.imgur.com/46RAS.png
Guess I solved it. When you're adding an operator to a panel, you can do something like this:
def draw (self, context):
layout = self.layout
row = layout.row()
row.operator("foo.bar", text="Whatever you want")
and the "Whatever you want" is going to be your button's label. But what I did was something else. I didn't change the operators' labels, but instead gave them a different icons depending on whether it's a mesh or an empty currently selected/active:
def draw (self, context):
# (...) we're skipping some code here, obviously
act = context.active_object
if act.type == 'MESH':
op_icon = 'ZOOMIN'
else:
op_icon = 'EMPTY_DATA'
row = layout.column(align=True)
row.operator('rbm.set_bullet_point', icon=op_icon)
row.operator('rbm.set_rocket_point', icon=op_icon)
# (...) rest of the code