Hide unselected in Maya/Python - python

I'm trying for a while to get this sorted out in Maya:
I want a script which can hide my unselected lights for example, so the only way which comes to mind (and doesn't work) is this one:
lt=cmds.ls(lt=True,sl=False)
cmds.hide(lt)
I see that the argument False with selection doesn't work, so I want to find out about some other ways...thanks

#goncalops answer will work if you select the light shapes, but not their transforms.
Try:
lights = cmds.ls(type = 'light') or []
lights = set(cmds.listRelatives(*lights, p=True) or [])
for item in lights.difference(set(cmds.ls(sl=True))):
cmds.hide(item)

I think most of the answers go into over engineering land. The question is how to hide non selected lights at the end of your operation, Nothing says you can not hide them all and bring the lights selected back. So conceptually easier is to do (and slightly faster but that's beside the point):
cmds.hide(cmds.ls(lights=True, dag=True))
cmds.showHidden()
One comment: There's no need to fetch shapes separately in this case, as it has a the dag flag for this. See conceptually Maya items are packets of transform and the shape separately. However its so common occurrence that you want to convert between the shape and dag to shape that ls offers a way to do this with the dag and shapes flags.
Second comment: If you do not pass a list to Maya it will operate on selection thats why showHidden works without any data.
PS: conceptually neither my answer nor #theodox answer will work in all cases as you MAY indeed have selected the shape. However most users will not so it will commonly work this way.

Reading the documentation for the ls command in Maya 2011, it doesn't seem to have either lt or sl parameters, although it has lights and selection.
Further, it seems the selection argument only serves the purpose of returning the selected arguments, not of filtering unselected ones.
OTOH, the hide method accepts a single argument.
Try this:
lights= set(cmds.ls(lights=True)) - set(cmds.ls(selection=True))
for light in lights:
cmds.hide(light)

this will work for your condition
hide_light = set(cmds.ls(lights=True, l=True)) - set(cmds.ls(sl=True, dag=True, l=True, leaf=True))
for each_lit in hide_light:
cmds.setAttr("%s.visibility" % each_lit, 0)

Let's discuss the problem a bit:
There are a few things to consider. When users select a light, (from the Viewport or the Outliner), most of the time they would really be selecting the transform node of a light.
When we perform a cmds.ls(type='lights'), we are actually selecting their shape nodes. This is in line with what #theodox is saying.
I don't know about you, but when I hide lights manually, I select lights in Outliner/Viewport. When I hide them (ctrl-h), they grey out in the outliner. What I've done is hidden their transform nodes (not their shape nodes).
To make things more complicated, Maya actually lets us hide shape nodes too. But the transform node will not grey out when the shape node is hidden.
Imagine if my script were to hide the light shape node, in the Outliner there would be no indication that those lights are hidden, if the Outliner is not set to display shape nodes (this is the default setting in the Outliner). Without the greying-out to indicate that the lights are hidden, many artists especially less experienced ones would assume that lights are turned on when they have already been disabled and hidden. This is going to cost a lot of confusion, time wasted, frustration, basically not what we want.
Thus when I write a script like this I'll expect the user to be selecting transform nodes. Also when I hide lights, I will hide the transform nodes of the lights instead of hiding the light shapes directly. That would be my game plan.
import maya.cmds as mc
def hideDeselected(targetNodeType):
# selectedNodeTransforms will contain transform nodes
# of all target node type shapes that are selected
selectedNodeTransforms = []
for selNode in mc.ls(sl=True):
if targetNodeType in mc.nodeType(selNode):
# selected node is the correct type
# add the transform node to selectedNodeTransforms
selectedNodeTransforms.append(mc.listRelatives(selNode, parent=True))
elif mc.listRelatives(selNode, children=True, type=targetNodeType):
# selected node is a transform node
# with a child node of the correct type
# add the transform node to selectedNodeTransforms
selectedNodeTransforms.append(selNode)
if selectedNodeTransforms:
# only if something is selected, do the hiding thing.
# If we do not do this check, and if nothing is selected
# all transform nodes of targetNodeType will be hidden
print 'selected objects:',selectedNodeTransforms
for thisNode in mc.ls(type=targetNodeType):
# loops through all target shapes in the scene
# get the transform node
thisNodeTransform = mc.listRelatives(thisNode, parent=True)[0]
if not thisNodeTransform in selectedNodeTransforms:
print 'hiding', thisNodeTransform
hide(thisNodeTransform)
else:
print 'nothing is selected'
hideDeselected('light')
In the code above, I've made a function out of it so we can pass in any dag node type that is able to have a parent in the scene, and the code will work.
Thus, to hide all the other cameras in the scene that are not currently selected, we just have to call the function with the camera node type:
hideDeselected('camera')

Related

Incorrect hover area with QGraphicsPathItem and QPainterPathStroker

I am writing a class inheriting from QGraphicsItemGroup and its main child is a QGraphicsPathItem. The whole thing is used to draw polylines. I wanted to have a proper hover system for the lines, si I reimplemented the shape method of the object as follows:
def shape(self):
stroker = QtWidgets.QPainterPathStroker()
stroker.setWidth(10 * self.resolution) # resolution handles zoom and stuff
path = stroker.createStroke(self.__path.path()).simplified()
return path
In the above snippet, self.__path is the QGraphicsPathItem I mentioned ealier.
To make things simple, here are a few pictures. The line I drew, that I see on the screen:
The hover area I want:
The hover area I currently have with the reimplemented shape method shown above:
As you guessed, such a selection area is hardly useful for any purpose. Worst of all, I tried to use the exact same method to generate the outlines of the line, then used toFillPolygon to generate a polygon that I rendered in the same object by adding a QGraphicsPolygonItem child to my object: the shape that appears on my screen is exactly what I want, but when I use the same path to create the hover area via shape, it gives me the useless hover area (image 3) instead.
So, do you know why the path obtained with the QPainterPathStroker allows me to display a polygon that seems to exactly correspond to the hover area I want, but when I use that path in shape, the obtained over area is wonky? If so, do you know how to fix this problem?

Selecting points on a PlotWidget with Qt

I'm new to python/pyside/pyqtgraph and I'm kind of stuck in my program.
So, I have an numpy.ndarray representing 10000 values, and I plot it in a PlotWidget using the plot method.
The result is ok but now I want to allow the user to select points of the curve so I can save the X axis of the point and use it later on.
What I would like to do is creating a QPushButton which when clicked it waits for the user to select two points on the curve by left-clicking and then save the X axis. Seems pretty simple conceptually but I don't find the good way of doing it.
I would be really pleased if you could give me an example or something, I'm also open to any suggestion that deviate from this use case.
I can resume the code by this lines :
self.myWidget = pyqtgraph.PlotWidget()
self.myWidget.plot(myValues) # myValues is the numpy array
self.select2PointsButton = QtGui.QPushButton()
self.select2PointsButton.clicked.connect(self.waitForSelection)
def waitForSelection(self):
# Wait for a click left on the curve to select first point then save the X-axis
# Do it again to select the second point
Thanks,
Morgan
Edit after Zet4 answer :
Thank you for your answer it helped me get started.
In the end, I made a subclass of PlotWidget :
class PltWidget(pg.PlotWidget):
def __init__(self, parent=None):
super(PltWidget, self).__init__(parent)
self.selectionMode = False
def mousePressEvent(self, ev):
if self.selectionMode:
if ev.button() == QtCore.Qt.LeftButton:
# How do I get the X axis ?
else:
super(PltWidget, self).mousePressEvent(ev)
Then I use it in my window, connecting the button signal with the slot changing the boolean of my PltWidget :
..... # Other attributes and connections of my Window
self.T0Button = QtGui.QPushButton()
self.graphicsLeft = PltWidget()
self.T0Button.clicked.connect(self.selectT0)
def selectT0(self):
self.graphicsLeft.selectionMode = not(self.graphicsLeft.selectionMode)
I'll probably use your buffer strategy to command two selections from the user.
However, I still need to know how do I get the X axis of the PlotWidget from where I clicked. If anyone using pyqtgraph know the answer, please let me know.
Thanks.
My apologize, i'm not a pyqt expert, but your problem seems too be more conceptual than technical.
You can use your QPushButton.clicked (in your code, the waitForSelection function) to change the functional state of your object (allow or disable point selection).
So you need to :
create a function that intercept the click on your pushButton (your waitForSelection function)
create a function that intercept left click on your graphical object (i'll assume you name it onLeftClick)
a functional state handler : a boolean is the easiest way for it ( isSelectedMode ).
a buffer that represent a point. ( buffer here, it can be your X-axis as you say'ed )
Your waitForSelection function will only inverse the state of isSelectedMode. It will also clear the buffer, before you don't need it anymore. pseudocode :
if isSelectedMode == true
buffer = null;
isSelectedMode = !isSelectedMode;
The onLeftClick will do the harder of the work, see this pseudocode :
if isSelectedMode == true
if buffer != null // No point save, so this click is the first one
//Here you save your data in the buffer
else
// One point is saved so that's the second one.
// Do what you want with it and buffer
else
// The selection mode is not active.
This only thing that missing is the way of getting your X-axis from your left click.
I hope this can help you.
Best regards

Blender's internal data won't update after an scale operation

I have the following script:
import bpy
import os
print("Starter")
selection = bpy.context.selected_objects
for obj in selection:
print("Obj selected")
me = obj.data
for edge in me.edges:
vert1 = me.vertices[edge.vertices[0]]
vert2 = me.vertices[edge.vertices[1]]
print("<boundingLine p1=\"{0}f,0.0f,{1}f,1.0f\" p2=\"{2}f,0.0f,{3}f,1.0f\" />".format(vert1.co.x, vert1.co.y, vert2.co.x, vert2.co.y))
Pretty basic, right? It just prints out all the edges into the console, for me to copy paste into an xml document.
When I scale an object, and perform this script on the object, I get the OLD, unscaled values for the object outputed to the console, before it was scaled. I have tried moving every vertice in the object in all axises, which results in the values outputed being those outscaled and then transformed according to my movement.
If i press n to check the vertices global values, they are properly scaled.
Why am I not getting the correct values?!?
This script was supposed to save time, but getting anything to work in blender is a CHORE! It does not help that they has just updated their api, so all example code out there is outdated!
Allright, this is the deal: when you scale, translate or rotate an object in Blender, or otherwise perform an transformation, that transformation is "stored" somehow. What you need to do I choose the object of which you applied the transformation, and use the short cut CTRL + A, and then apply your transformation.
...
So there was no lack of contingency (am I using this word right? Checked out it's definition and it seems right) between the internal data accessible through the blender api, and the values actually displayed.
I am sure this design makes sense, but right now I want to punch the guy that came up with it, in the throat. If I scale something, I intend the thing that got scaled to be scaled!
But anyways, the reason I got weird values was because the scaling was not applied, which you do with CTRL + A, once you in object mode have selected the object that you scaled.
I`m not really a Blender user(but a Maya one), I think you could try something different(I woulds say slower too...), just iterate over the selected vertices, creating a locator or a null object and constraining it to the vertex position and getting it's x,y,z coordinates. I've done it in maya and works.
Lets say something like this:
data_list = []
selection = #selection code here#
for v in selection:
loc = locator()
pointconstraint(v, loc)
data_list.append(loc.translation_attributes)
Mesh objects have an internal coordinate system for their vertices, as well as global translation, scaling, and rotation transforms that apply to the entire object. You can apply the global scaling matrix to the mesh data, and convert the vertex coordinates to the global coordinate system as follows:
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.transform_apply(scale=True)
bpy.ops.object.select_all(action='DESELECT')
Other options to transform_apply() allow rotation and translation matrices to be applied as well.

"Inception" situation with wxPython

The title is amusing , I know. Its like movie "Inception" situation .Dream in a dream in a dream .
Hi everyone ,I am using wxpython to make an app.
I want to achieve something like this .(This is just idea of the problem)
func1(self,event):
some widgets added
func2
func2(self,event):
remove previous widgets (by using event.GetEventObject().GetParent().Hide())
add new ones
func3
func3(self,event):
remove widgets added in func2
recall widgets added in func1 (event.GetEventObject().GetParent().Show())
I have traversed too much inside , like 3 times jumping from functions to other nested
functions that i have no track of event .
If i store the ids of events (in a list) with
event.GetId()
while traversing in every function , is there a way if i can use those ids to
replace
event.GetEventObject().GetParent().Show()
event.GetEventObject().GetParent().Hide()
with
id1.GetEventObject().GetParent().Hide()
id2.GetEventObject().GetParent().Show()
I just want to know this kind of thing is possible ?
Or theres a better simpler way ?
If any still is in such trouble , I found some ways...
First of all , you don't need to use IDs for this.....Much simpler way is
create different panels........
When you want to hide one , you can simply do
panelname.Hide()
When you want to show another ,
panelname.Show() # Or this also works (event.GetEventObject().GetParent().Show()\Hide())
Note : 1) Remember to give all widgets (buttons etc) individual IDs (or -1 will do).
2) You can also create your overlapping panels with a function call too.(example - After a button is clicked).
3) Also you can create a common panel ( a parent panel ) and then create child panels and in the init body . And then you can simply hide and show these panels in a function binded (may be with a button etc) .
I solved my problem like this . Did'nt need to use GetId() . But there might be others ways. So do share if you have some other idea.I hope this helps someone someday...Thank you all.

Get and set the active row in QTreeview programmatically (PyQt)

Is there a way to get and change the active row in a QTreeView (not QTreeWidget)? By active, I mean the row with the focus highlight, not the selected row. In the paint event, I can use QStyle.State_HasFocus to get the active row, but this doesn't seem to work elsewhere.
You can get/set the active row with the currentIndex() and setCurrentIndex() functions that you can find in both QTreeView and QItemSelectionModel (the latter is returned by QTreeView.selectionModel()).
And despite its name, the QItemSelectionModel handles the view current item, and the view selection independently.
Current item is the one which is indicated by the focus rectangle. You can change it using selectionModel function of the tree view. If you don't want to change currently selected items, pass QtGui.QItemSelectionModel.NoUpdate as a second parameter to setCurrentIndex method. Below is an example:
index = model.index(3, 0);
view.selectionModel().setCurrentIndex(index, QtGui.QItemSelectionModel.NoUpdate)
this should move current item to the item with index 3
hope this helps, regards
For me it got nothing here new to ask such question, why because simple; you can use Qt-Designer and create QTreeView and then create line edit, then link them using the action editor, then transform the UI file to Py file, then you will see how things work behind the scene.
You will find this if you try:
QtCore.QObject.connect(self.treeView, QtCore.SIGNAL(_fromUtf8("clicked(QModelIndex)")), self.test)

Categories