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.