Get Selected Keyframes?
-
Hi,
Is there now an API in getting the selected keyframe?
Much likedoc.GetActiveObjects
ordoc.GetActiveMaterials
My end goal operation is change the tangent handles (in the graph editor) of the selected kefyrames.
The closest solution is in this thead (https://developers.maxon.net/forum/topic/10989/how-to-get-the-selected-keyframes-in-active-timeline-fcurve-manager/7)
But it doesn't work on the latest versions of Cinema4D (even if you changed it to Python 3 syntax).Is there a way around this?
-
Hello @bentraje,
Thank you for reaching out to us. There always has been a means to retrieve the selection states of keyframes, namely the bit flags
NBIT_TL1_SELECT
, ...,NBIT_TL4_SELECT
. There are no plans to extend this with convenance methods, as this is just fine as is. On c4d.BaseList2D there are some keyframe selection convenance methods, but they are very specialized and probably not too useful for the average Python user.There is also a slight bump in the road here, namely that a CKey is a
C4DAtom
and aGeListNode
, but not aBaseList2D
, which is a quite uncommon thing. This throws a wrench into the usual way of determining a selection state,BaseList2D.GetBit(c4d.BIT_ACTIVE)
. The reason is that there can be up to four dope sheet timeline editors active at once, which each can have its own selection state. Therefore there are four answers to the question "is this keyframe selected in a dopesheet editor?".Find a simple example attached below.
Cheers,
FerdinandResult:
Code:
"""Prints out the selection state of keyframes for the currently selected object. Because there can be up to four timelines which do not share a selection state, there are four answers to the question "is this keyframe selected?". """ import c4d doc: c4d.documents.BaseDocument # The currently active document. op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. def main() -> None: """Called by Cinema 4D when the script is being executed. """ if not op: return # Iterate over all tracks of the active object. track: c4d.CTrack for track in op.GetCTracks(): curve: c4d.CCurve = track.GetCurve() # Iterate over all keys of the curve of this track. for i in range(curve.GetKeyCount()): key: c4d.CKey = curve.GetKey(i) # Check if the key #i is selected in any of the up to four timeline editors. for n in (c4d.NBIT_TL1_SELECT, c4d.NBIT_TL2_SELECT, c4d.NBIT_TL3_SELECT, c4d.NBIT_TL4_SELECT): isSelected: bool = key.GetNBit(n) if isSelected: # NBIT_TL1_SELECT has the value 5, NBIT_TL2_SELECT 6, etc. print (f"The key {key} in the track {track} is selected in the timeline '{n - 4}'.") if __name__ == '__main__': main()
-
Thanks for the response. This is probably the info I missed out:
CKey is a C4DAtom and a GeListNode, but not a BaseList2D, which is a quite uncommon thing
I tried your code but I'm not sure if its a bug.
If I select a key in the timeline (dope sheet mode). It works.
But if I select a key in the timeline (fcurve sheet mode). It doesn't.
(It spits out a value but the value it spits out is the last selected key in dopesheet and not the actively selected key in fcurve)So I'm guessing I need to replace
NBIT_TL1_SELECT
withNBIT_TL1_FCSELECT
but it still doesn't work.Am I missing something?
-
The NBITs you are looking for are
NBIT_TL1_SELECT2
...NBIT_TL4_SELECT2
. -
Slr. I can confirm the "Select2" works as expected.
Just want to point out though. That option is present in the documentation but doesn't have a proper description (?).
It's set to Private.https://developers.maxon.net/docs/py/2024_2_0/consts/NBIT.html?highlight=nbit_tl1_select
-
Hey @bentraje,
yes, we are aware that internal and private tags are something that plagues our documentation as they often have been abused by developers to skip documentation. But that is not so easy to fix.
I for example did and still do not know the purpose
NBIT_TLX_SELECT2
either. I was just experienced enough with the C4D API to poke in this place first.Physically fixing the docs, i.e., adding a blab here or there, is not the problem. The problem is to evaluate if the
private
tag in C++ (which then radiates into Python) is well founded or not, especially for ancient things like this. I would have to read a lot of code to make an assessment if this should be private or not, and even then would not be sure. And even an'Expresses the selection state of f-curve keys. @markprivate'
is problematic because for that I would have to be sure that it does not have a weird side effect.Cheers,
Ferdinand