CUSTOMGUI_QUICKTAB trigger twice when click
-
Hello guys,
I want to achieve aCycle buttongui with python ( like subdivide UVs in a SDS ) , I findCUSTOMGUI_QUICKTABprovide a UI like this , but when I test my dialog , I click on a quicktab , it return id twice, but when I print something , it works well ( I just want keep this gui but not any sub dlg , and do some stuff when change a tab button like refresh ua and treeview , it executed twice is too expensive ) so what's wrong with my codes?[win 11@22H2 , c4d 2023.2.0]
import c4d ID_QUICKTAB_BAR = 110000 # ID for the quicktab customGui class QuickTabDialogExample(c4d.gui.GeDialog): def __init__(self): self._quickTab = None # Stores the quicktab custom GUI def CreateLayout(self): bc = c4d.BaseContainer() bc.SetBool(c4d.QUICKTAB_BAR, 0) bc.SetBool(c4d.QUICKTAB_SHOWSINGLE, True) bc.SetBool(c4d.QUICKTAB_NOMULTISELECT, 1) self._quickTab = self.AddCustomGui(ID_QUICKTAB_BAR, c4d.CUSTOMGUI_QUICKTAB, '', c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 0, 0, bc) self._quickTab.AppendString(0, "1", 1) self._quickTab.AppendString(1, "2", 0) self._quickTab.AppendString(2, "3", 0) self.AddButton(50, c4d.BFH_SCALEFIT, name="Print Selected") return True def Command(self, id, msg): print(id) # Displays the ID and name of the selected tab if id == 50: if self._quickTab.IsSelected(0): print("1 select") if self._quickTab.IsSelected(1): print("2 select") if self._quickTab.IsSelected(2): print("3 select") return True # Main function def main(): # Initializes a QuickTabDialogExample Dialog diag = QuickTabDialogExample() # Opens the Dialog in modal mode diag.Open(dlgtype=c4d.DLG_TYPE_MODAL, defaultw=0, defaulth=0) # Execute main() if __name__ == '__main__': main() -
Hi @Dunhou thanks for reaching us, looks like it was always the case at least I can reproduce it up to 21, and I stopped to check for earlier version. I opened a bug report about it, the only workaround would be track yourself the selection state and compare it each time.
Find bellow a prototype:import c4d import dataclasses ID_QUICKTAB_BAR = 110000 @dataclasses.dataclass class Entry: entryId: int entryName: str selectionState: bool class QuickTabDialogExample(c4d.gui.GeDialog): def __init__(self): self.entries = [] self.entriesHash = 0 self._quickTab = None def CreateLayout(self): bc = c4d.BaseContainer() bc.SetBool(c4d.QUICKTAB_BAR, 0) bc.SetBool(c4d.QUICKTAB_SHOWSINGLE, True) bc.SetBool(c4d.QUICKTAB_NOMULTISELECT, True) self._quickTab = self.AddCustomGui(ID_QUICKTAB_BAR, c4d.CUSTOMGUI_QUICKTAB, '', c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 0, 0, bc) self.entries.append(Entry(10001, "1", True)) self.entries.append(Entry(10002, "2", False)) self.entries.append(Entry(10003, "3", False)) self.entriesHash = hash(str(self.entries)) for entry in self.entries: self._quickTab.AppendString(entry.entryId, entry.entryName, entry.selectionState) self.AddButton(10050, c4d.BFH_SCALEFIT, name="Print Selected") return True def Command(self, id, msg): # Displays the ID and name of the selected tab if id == 10050: x = self._quickTab.GetData() if self._quickTab.IsSelected(10001): print("1 select") if self._quickTab.IsSelected(10002): print("2 select") if self._quickTab.IsSelected(10003): print("3 select") elif id == ID_QUICKTAB_BAR and self._quickTab: for entry in self.entries: entry.selectionState = self._quickTab.IsSelected(entry.entryId) newSelectionState = hash(str(self.entries)) if newSelectionState != self.entriesHash: self.entriesHash = newSelectionState print("Selection changed") return True # Main function def main(): diag = QuickTabDialogExample() diag.Open(dlgtype=c4d.DLG_TYPE_MODAL, defaultw=0, defaulth=0) # Execute main() if __name__ == '__main__': main()Cheers,
Maxime. -
@m_adam Thanks man! this
@dataclasses.dataclassdecorator is pretty handy , new knowledge incoming
And maybe some similar bug I have seen before , but I don't remember what it is (and even didn't know it is a bug or my bad coding
) , if I met some similar bugs I will update the topic , but now let's hope it will be fixed next release .Thanks for your help again
Cheers~
-
Sorry for necro'ing the post, I was looking for code references on Quicktabs.
Regarding Command triggering twice, is it because of the mouse events? mouse up/down
I print the contents of msg[c4d.BFM_ACTION_INDRAG] inside the Command function for testing.- When I click on the Quicktab, the first event returns True, while the second returns False.
- If I drag over two entries on the Quicktab gadget (click on one entry, then drag to the next entry and let go of the mouse,) Command triggers three times, msg[c4d.BFM_ACTION_INDRAG] returns True the first two times and False for the last one. Also, the first entry returns True for its IsSelected() check on mouse down. After dragging, the the second entry's IsSelected() is True. Second entry's IsSelected() is also true when I let go of the mouse.
So maybe it was by design, in case the interface needs to update as you drag across entries on the Quicktab gadget. And if you only need to update the gui once (regardless of whether the clicked entry was previously selected or not,) just check if msg[c4d.BFM_ACTION_INDRAG] is False (mouse released.)
def Command(self, id, msg): ## check if Quicktab was clicked, and only process when user is finished clicking if id == ID_QUICKTAB_BAR and not msg[c4d.BFM_ACTION_INDRAG]: self.RefreshGuiOnQuicktabMouseUp() return True -
Hey @Gene,
Thread-necromancy is often not so good, because it almost always derails the original topic and often also lacks in clarity. I also here do not understand what your concrete question is?
When I click on the Quicktab, the first event returns True, while the second returns False.
What do you mean by "the event returns true"? It is you, the developer, who returns the result for an event (or you do not handle it at all). Are you talking about something like
BFM_ACTION_VALUE?If I drag over two entries on the Quicktab gadget (click on one entry, then drag to the next entry and let go of the mouse,) Command triggers three times, msg[c4d.BFM_ACTION_INDRAG] returns True the first two times and False for the last one. Also, the first entry returns True for its IsSelected() check on mouse down. After dragging, the the second entry's IsSelected() is True. Second entry's IsSelected() is also true when I let go of the mouse.
I do not see any question here, so what is the goal?
Regarding Command triggering twice, is it because of the mouse events?
GeDialog.Commandis just a convenience wrapper forGeDialog.Messageevents (most from theBFM_ACTIONfamily). If you want the full picture, useMessage. I struggle to see a tangible question which I could answer, what do you want to achieve?Yes, some controls fire multiple times in
Command, it is impossible (and also somewhat futile) to reconstruct the reason for each of them. Someone thought at some point it would be convenient to forward this kind of event toCommandfor some feature in Cinema 4D.I am not familiar with the exact issue discussed in this topic, but at a glance, what Maxime wrote then looks a bit overkill with the hashing, I would just store the last selected element and be done with it. Alternatively you could design your code so that you do not tie any heavy logic to a tab being activated (which is IMHO not a great idea in general), so that you do not mind when such code runs multiple times.
Cheers,
Ferdinandclass MyDialog (c4d.gui.GeDialog): ID_TAB_1: int = 10000 ID_TAB_2: int = 10001 IDS_TABS: tuple[int, ...] = (ID_TAB_1, ID_TAB_2) def __init__(self) -> None: self._activeTab: int = MyDialog.ID_TAB_1 def Command(self, cid: int, msg: c4d.BaseContainer) -> bool: """ """ if cid == self._activeTab: return True elif cid in MyDialog.IDS_TABS: self._activeTab = cid if cid is MyDialog.ID_TAB_1: foo() elif cid is MyDialog.ID_TAB_2: bar() return True -
@ferdinand said in CUSTOMGUI_QUICKTAB trigger twice when click:
Thread-necromancy is often not so good, because it almost always derails the original topic and often also lacks in clarity. I also here do not understand what your concrete question is?
Hi Ferdinand,
At the end of the discussion, they were talking about how the Command function being triggered twice might be a bug. Because clicking on a Quicktab Gizmo triggers the Command function twice, compared to when clicking on a Button Gizmo triggers it once.
I wasn't really asking a question. What I was trying to say was that the Command function triggering more than once might be intended, and I was describing the behavior.
- When you MouseDown on a Quicktab gizmo, the Command function is called.
- When you drag the mouse, every time the cursor hits another entry on the Quicktab, it will trigger the Command function again.
- Then when you finally MouseUp, it will trigger the Command function one last time.
** The Button gizmo only triggers the Command function once, on MouseUp.
So depending on the situation, you might want to choose a specific way to handle Quicktabs in the Command function.
- If you need to only react to a change in the Quicktab's value, then Maxime's solution is ideal. More overhead, but it also lets you ignore the situation where the user clicks on the already-selected item on the Quicktab.
- If you only need to react to clicking on the Quicktab, inside the Command function you could just check if msg[c4d.BFM_ACTION_INDRAG] is False. (This is the MouseUp event after clicking on the Quicktab, similar behavior to clicking on a Button gizmo.)
- If you need to react to clicks and drags on the Quicktab, you check if msg[c4d.BFM_ACTION_INDRAG] is True. (It should then be safe to ignore the Command call when msg[c4d.BFM_ACTION_INDRAG] is False, since the contents of Quicktab should stay the same as the previous call.)
EDIT:
The behavior's also consistent with other gizmos. The one from GeDialog.AddEditSlider() for example, If you click/drag on the arrows, Command is called multiple times as well. If you click on the arrow, Command is called twice (on MouseDown and MouseUp.) If you hold on the arrow for a while, it's called more than twice. First call is when you MouseDown, the next ones are whenever the value updates as you keep the arrow pressed, and one last time when you MouseUp. If you click on its text field, Command is only called once either after you press Enter, press Escape, or click outside of the text field (Command also triggers every time you press the up/down keys to increment the value.) -
hey @Gene,
So, you were just trying to add information for future readers? That is of course very welcome and explains my inability to extract a question from your posting.
I would not have been that generous with the word bug either. Since this has never been fixed, chances are high that we came to the same conclusion internally.
In general, you should not expect
Commandcalling patterns to make perfect sense in every case. There are multiple cases whereCommandis triggered more often than one would think at first glance. I would also not try to interpret some deeper sense into all that.Cheers,
Ferdinand