Dynamically create/delete drawn objects on tkinter canvas? - python

I have managed to dynamically create various rectangles on the tkinter canvas widget using the below code:
setattr(self, "wall_" + str(counter), self.canvas_base.create_rectangle(*sel_wall,fill="black"))
Where counter is an increasing and variable integer, canvas_base is the canvas being drawn on, suffix is a string alternating between a and b, and sel_wall is a list of coordinates used to draw the rectangle.
Is there a way to dynamically delete these objects on the canvas (varying from wall_1 to something like wall_5), or is there a better alternative combination to create/delete these canvas objects?

When you need to deal with an arbitrary number of similar objects, the proper solution is to put them in a list (or other container object). You can easily iterate over the list to do something to all the objects, such as deleting them.

Related

wxpython dynamically referring to widgets (wxformbuilder)

I often find myself in a situation where I want to create a number of wx.StaticTextor some other widget in wxFormbuilder and be able to refer to these dynamically. Say i have a number of statictexts named a0 through a10
How would I go about finding them in code?
One way is to do a list with all the variables in, but it is ugly, and feels inefficient? Maybe not but atleast the code gets cluttered with long lists everywhere.
def updateLabels(self, data):
guiLabels = [self.a0, self.a1, self.a2 ..... ]
for i in range(len(guiLabels)):
guiLabels[i].SetLabel(data[i)
How do you go about fixing this?
Another alternative is to make the guiLabels list when initiating the app. However, I've had some problems with finding them. you have to call GetChildren() on the top window and set a different wx.ID for every StaticText and then go through every element and find this ID you made.. And the formatting when I do this is really off key.. The text gets different background colors and doesnt respect it's alignments and other funky stuff.
Any thoughts on how I can do this?
maybe something like this could work for you:
for x in xrange(10):
name = "a%s" % x # dynamically generating reference names
obj = getattr(self, name) # getting the object reference from the parent object
obj.SetLabel("xyz")

What is the difference between object and node in Maya (scripting)?

This question may sound silly I know, but I would like to know exactly what is the difference and in which way the hierarchy works in their case.
If I create for instance a polyCylinder and bind it to a variable
exVar = cmds.polyCylinder(name='cylinder_01')
And now I print exVar, I get a list with two Unicode string items: one for the name of the object and another one for the name of the node.
[u'cylinder_01', u'polyCylinder1']
If I go to the Outliner I just can see cylinder_01, I cannot see the polyCylinder1 item.
What do they mean? Is there any way to visualize them in the Outliner or the Hypergraph?
Thanks in advance.
cylinder_01 is the transform, which handles translation, rotation, scale, etc.
polyCylinder1 is the shape, which holds the vertices, polygons, shader connections, etc.
The shape is parented to the transform. You can see it in the Outliner if you select Display > Shapes

How to change the attributes for all objects inside a list in python(3)?

I am new to python and unfamiliar with manipulating python lists. I have a list of tkinter widgets, more specifically buttons, which have been added to my list btnList by using:
btnList.append(btn1)
btnList.append(btn2)
Normally to change an object's attribute value (the state attribute for example) one would use:
btn1.configure(state='disabled')
btn2.configure(state='disabled')
which would set the state attribute of both buttons to disabled,
Is there a way to change attributes for all of the objects contained in the list?
for example setting the state of each button to disabled?
There are a fair number of ways to express this, including some one-liners, but I think a simple for loop is the cleanest:
for button in btnList:
button.configure(state='disabled')
Simply loop over your list:
for button in btnList:
button.configure(state='disabled')
button will be assigned each button from your list in turn letting you call the configure() method on it.

Recognize which model object is clicked in Tkinter

I have many overlapping shapes representing irrelevant background items on a canvas. I also have a pattern of non-overlapping circles, each of which is a "hole". Each "hole" sprite (circle) has an associated "hole" object, though never explicitly in the code. (side note: I would love to have a logical association between model and view with these objects, but haven't found a smart way to do that). Each "hole" is different, and has different effects.
There is a small circular "ball" which can be dragged into any "hole". I found how to drag and drop from this question. I need to find which hole the ball went into.
The best way I have found to do that so far is to:
create a dict mapping the coordinates of the center of the hole sprite to the hole object
tag each hole like this:
t=("hole", "hole_at_{}_{}".format(x, y))
on releasing the ball, do this:
def on_ball_release(self, event):
'''Process button event when user releases mouse holding ball.'''
# use small invisible rectangle and find all overlapping items
items = self._canvas.find_overlapping(event.x - 10, event.y - 10, event.x + 10, event.y + 10)
for item in items:
# there should only be 1 overlapping hole
if "hole" in self._canvas.gettags(item):
# get the coordinates from the tag
coords = tuple([int(i) for i in self._canvas.gettags(item)[1].replace("hole_at_", "").split("_")])
# get associated object using dictionary established before
hole = self._hole_dict[coords]
hole.process_ball()
return
That seems very messy. I feel there should be some smarter way to do this.
Disclaimer: I don't use Python, but many Tkinter questions can be answered in a useful from an experience with Tcl/Tk, which I have. In this case, it takes some more work to figure out whether what I would do in Tcl is easy to represent with Tkinter.
First, I wouldn't add "identifier tags" (hole_at_...): if I have model objects corresponding to canvas items, I would use the item id (which canvas returns during item creation) as an index, to be able to find an object for an item id without parsing tags. (And if I had to add string identifiers, even if I decided to make them from coordinates, I would use that very string as my dictionary key, to avoid reparsing it. Do we need coordinates later? Then make them properties of the hole object).
Second, I would use pathName find subcommand with multiple criteria to find (canvas id of) item which is tagged as hole and is nearest to the given point (overlapping is fine when we want to ignore drops too far from any hole, closest is for the case where nearest hole should be used even if it's not too near). Here is the problematic part: does Tkinter support multiple criteria in canvases' $pathName find?

How to get the intersection of geometry of two QWidgets with different parents?

With Qt4 (here using PyQt4) to get the area of intersection of two QWidgets---and that's particularly useful with QRubberband when making a selection---one simply does:
intersection = rubberband.geometry().intersected(mydocumentwidget.geometry())
Now this assumes that rubberband and mydocumentwidget have the same parent widget, i.e. more precisely that their coordinates are relative to the same origin. This is because the method call is QRect.intersected() and QRect itself does not have a parent, it's a simple tuple with 4 integers and some method calls.
Now in my case rubberband and mydocumentwidget have the same parent, but I am interested in the interesection of the rubberband with mydocument's children, i.e. pages of the document.
Pages however take reference their coordinate to a different point on the screen.
How can I get to calculate the intersection between the rubberband and my page widgets? Is there a way to convert the coordinates to reference the parent's parent? I can of course just lay down the math myself, but I don't think it's very clean. Does Qt4 provide any means to convert this automatically?
What you can do is map the point of the QRect to the parent widget. You can map QPoints to various targets (parent, other, global), but since you specifically want to map to mydocumentwidget, here is what you do:
doc_child = getChildOfDocument() # pseudo
rect = doc_child.geometry()
mappedPoint = doc_child.mapToParent(rect.topleft())
# alternative #
# mappedPoint = doc_child.mapTo(mydocumentwidget, rect.topleft())
mappedRect = QtCore.QRect(mappedPoint, rect.size())
intersection = rubberband.geometry().intersected(mappedRect)

Categories