Is there a way to limit node selector width for long node names?

I’m developing a module where users load a dynamic CT from DICOM as a Sequence. The automatic names for these nodes are generally very long, and are a pain for users to rename to shorten (just renaming in the subject hierarchy only renames the proxy node which is then replaced when the sequence current frame is changed; to make a persistent change, the user must open the Sequences module, go change tabs, select the sequence, then select rename current sequence).

I want the user to load the sequence and then be able to select in my module using a node selector as the first input. However, since the name is so long and the selector widget automatically resizes to show the whole name, the module panel ends up taking up way too much screen real estate (see screenshot). Is there a way to set a maximum width for the widget to avoid this? I could rename the sequence once it is selected to be shorter, but since this is the first input, I can’t really rename it before the user selects it, and at that point the module width has already been set too wide.

On other forum questions, I see the suggestion that reducing font size is one way to deal with long node names, but that doesn’t really seem helpful here: the font size would need to be reduced so much that the text would become unreadable, so what would be the point? A much better solution would be a truncated string that you could see the full length of when selecting from the dropdown. Is that possible using Qt settings somehow?

I really would like to know the answer to this as well. If possible to stop module pane to auto-adjust.

I don’t believe we have that currently, but Qt has methods to elide text taking into account the current font and layout. It would be great to add that to the combobox infrastructure. Probably needs to be in C++ at the CTK level. (see QFontMetrics Class | Qt GUI | Qt 6.9.0)

1 Like

OK thanks, good to know at least that it is not currently possible. I’ll stop trying to figure out how to do it :slight_smile: I’m pretty useless in C++, but this also seems pretty simple, so I’ll add this to my “maybe work on if I ever get around to it” pile. I appreciate the response @pieper, thanks!

If you are using qMRMLNodeComboBox, I would expect the text to be elided because the property Qt::ElideMiddle is already set [1]. This is made possible because qMRMLNodeComboBox itself instantiate ctkComboBox providing the function setElideMode.

If using qMRMLSubjectHierarchyComboBox, calling the function setElideMode should also be possible as it derives from ctkComboBox


  1. Slicer/Libs/MRML/Widgets/qMRMLNodeComboBox.cxx at cf620694f5a7addb540fdd656c8c0474f4fea08c · Slicer/Slicer · GitHub ↩︎

1 Like

It is indeed a qMRMLNodeComboBox, but it is definitely not eliding the middle by default. Is there another setting I can change, either in Slicer or in Qt Designer?

Sorry, I was partially wrong! If I manually resize the module panel, it will let me shrink it slightly and the middle of the node name does begin to elide (just a few characters before something stops it). Additionally, I just tried setting maximum widths on the combo boxes, and that also appears to be working, with the text being elided in the middle. I’m not sure what is preventing me from making the module panel even thinner, but I think I can work with pre-set maximum widths and this middle elide mode option.

You can choose how to set the size of a Qt combobox using sizeAdjustPolicy property. For some reason, the default in Qt is to set the size based on the first item length on first show.

Could you try if setting it to QComboBox::AdjustToMinimumContentsLengthWithIcon fixes your issue? The property is currently not exposed in Qt Designer but you can call self.ui.myComboBox.setSizeAdjustPolicy(qt.QComboBox.AdjustToMinimumContentsLengthWithIcon) in your widget setup method.

Thanks for the suggestion @lassoan. However, I am running into problems while trying it.

# Gather all node selector combo boxes in module ui
comboBoxes = [
            val
            for key, val in ui.__dict__.items()
            if type(val) == slicer.qMRMLNodeComboBox
        ]
# Set the SizeAdjustPolicy for each
for comboBox in comboBoxes:
    comboBox.setSizeAdjustPolicy(
        qt.QComboBox.AdjustToMinimumContentsLengthWithIcon
    )

Yields AttributeError: qMRMLNodeComboBox has no attribute named 'setSizeAdjustPolicy'. I tried a few variations like
comboBox.sizeAdjustPolicy = qt.QComboBox.AdjustToMinimumContentsLengthWithIcon , but that yields AttributeError: Property 'sizeAdjustPolicy' of type 'QComboBox::SizeAdjustPolicy' does not accept an object of type SizeAdjustPolicy (3)

Also, do I need to unset the maximum widths I was using in order to try this if we do manage to set the policy? I’m not clear on how this will help. Is the idea that the comboBox size will be set to a small size before being populated with list items? And that will help to trigger the eliding behavior? If so, do I need to do this in the module setup() method before uiWidget.setMRMLScene(slicer.mrmlScene), which is what I think will populate the comboBox lists of nodes?

It seems that the sizeAdjustPolicy property is not exposed on the public API of qMRMLNodeComboBox. Do you have a C++ build of Slicer? It should be easy to add it (just a few lines of code that calls sizeAdjustPolicy of the embedded QComboBox widget). If you don’t have a C++ build then I can add it in the next few days.

Unfortunately no.

I’ve moved on, using enforced maximum widths to prevent the module panel from getting too wide, but am willing to continue to test options if that would be helpful.

I wanted to quickly add it, but it seems to me that it is already exposed:

I tried using it on a node combobox and when getting the property it returns null, and when setting I get the same type of error @mikebind mentions (“does not accept an object of type…”).

Taking a quick look at the implementation I don’t see anything potentially wrong. I don’t have more time now to continue, but wanted to report these findings.

1 Like