Share

Manual Widget Binding

As of 3ds Max 2024 you can manually bind Qt widgets to param blocks. You can do this once during widget initialization, or (more usefully) re-bind widgets dynamically when the param changes, for example with tab-type params with P_VARIABLE_SIZE. The example below is summarized from the SDK howto sample under maxsdk/howto/ui/qtObjectDemo, which includes a rollup with a spinner that dynamically rebinds to a variable-sized tab param.

To manually bind a widget:

  • register a QMaxParamBlockWidget::PostConnectUI() callback for your param
  • in that callback use IParamMap2::ConnectUI() to create a new connection between a widget and a param

Then you can react to changes in the param size and unbind/rebind the Qt widget accordingly.

For example, the QtObjectDemo defines this param:

    pb_float_tab, _T("floatTabParam"), TYPE_FLOAT_TAB, 0, P_VARIABLE_SIZE | P_ANIMATABLE, 0,
        p_end,

The QtVariableFloatTabRollupWidget defines a PostConnect() callback that connects a spinner to the pb_float_tab param:

void QtVariableFloatTabRollupWidget::PostConnectUI(const MapID paramMapID)
{
    if (mPBlock && mParamMapID == paramMapID)
    {
        // Manually bind the tab parameter with the single 'Edit next' spinner,
        // since we want to bind it to a specific tab param index.
        // The automatic binding, based on the spinners Qt objectName matching the parameter name,
        // won't work for us due to the changing of the current tab index.
        auto map = mPBlock->GetMap(mParamMapID);
        map->ConnectUI(pb_float_tab, ui->spinner_tab_val, mCurTabIdx);
    }

    UpdateLabelTabValues(GetCOREInterface()->GetTime());
}

It also defines a method for changing the offset index for the pb_float_tab param. This method then calls the general ConnectUI(QMaxParamBlockWidget) on the param map as a whole, which in turn will call the callback (above) to connect the specific pb_float_tab parameter:

void QtVariableFloatTabRollupWidget::SetTabOffset(int newTabOffset)
{
    // In this example we use the automatic binding of Qt UI controls to parameters.
    // We have two spinners in the UI which show us a section of the tab parameter values.
    // For getting the auto binding to work, the Qt objectName of the UI control need
    // to match the parameter name plus the according tab index suffix.
    // For this reason when moving the displayed tab section up/down, we change the
    // spinners tab index suffix in the objectName here.
    // The more clever approach would have been using the parameter specific
    // IParamMap::ConnnectUI instead of the renaming and then doing a re-connect all parameters,
    // like it is done on the single spinner example in this demo.
    // But we also want to demonstrate alternatives here.
    int tabCount = mPBlock->Count(pb_float_tab);
    mTabOffset = std::clamp(newTabOffset, 0, tabCount - 2);
    ui->floatTabParam_tab_1->setObjectName("floatTabParam_tab_" + QString::number(mTabOffset + 1));
    ui->floatTabParam_tab_2->setObjectName("floatTabParam_tab_" + QString::number(mTabOffset + 2));
    // Re-connect all parameter with the UI again, so that the automatic parameter binding can do its magic.
    auto map = mPBlock->GetMap(mParamMapID);
    map->ConnectUI(this);
}

See the maxsdk/howto/ui/qtObjectDemo project for more details of the implementation for this example.

Was this information helpful?