The Flexibility of Docking Windows
Within 3ds Max, windows and panels can either float freely or be docked onto another panel, providing a customizable layout tailored to the user's preferences. This flexibility proves vital, especially considering the diverse screen sizes and DPI configurations prevalent today. Ensuring our tools are strategically positioned enhances the user experience without compromising the workspace.
Docking isn't confined to native Win32 UI elements; 3ds Max supports the creation of custom tools (plugins) using Qt for the UI. This empowers developers to build robust tools that seamlessly align with their workflow. Even commercial tools can be crafted with the flexibility of docking to existing UI elements.
Crafting a Dockable Widget in Qt
To create a dockable widget in Qt for 3ds Max, we typically derive a widget class from QDockWidget. In the context of 3ds Max plugin development, the QMaxDockWidget offers enhanced control and integration with the 3ds Max UI elements. The SDK provides a variety of UI elements, accessible in the <sdk installation path/include/qt/> directory.
Here is an example:
// Code Excerpt
class ADNSampleQmaxDocking
: public UtilityObj,
public MaxSDK::QmaxDockWidget
{
// ... other member functions
public slots:
void onTopLevelChanged(bool isFloating);
private:
void LoadSavedLayout(); // To load saved layouts
// ... other member variables
QString m_layoutPath;
MaxSDK::QmaxMainWindow* qmaxMainWindow; // Save a reference to the Qt MainWindow
};
The code skeleton above outlines the necessary structure for creating a dockable Qt widget for a UtilityObj-derived plugin. Remember that, as a UtilityObj plugin, additional functions must be implemented. Our constructor initializes the dock widget and sets the QSettings saving path.
Below is an excerpt from the constructor:
// Code Excerpt
ADNSampleQmaxDocking::ADNSampleQmaxDocking(MaxSDK::QmaxMainWindow* parent)
: iu(nullptr), QmaxDockWidget(parent)
{
// ... other initialization
// Set the desired directory
MSTR path = GetCOREInterface()->GetDir(APP_SCENE_DIR);
path.append(_M("\\dockslayout.ini"));
// ... other setup
m_layoutPath = QString::fromWCharArray(path);
show();
}
The constructor establishes the default dock position, sets the desired save directory (we have used the scene directory in this example), and creates a filename for the .ini settings file. To load the layout after initialization, we implement the `BeginEditParams` function:
// Code Excerpt
void ADNSampleQmaxDocking::BeginEditParams(Interface* ip, IUtil* iu)
{
// ... initialization and adding plugin widgets
// Load the saved scene layout file if it already exists
LoadSavedLayout();
// Connect topLevelChanged for the dock window to the saving of the layout
connect(this, &MaxSDK::QmaxDockWidget::topLevelChanged,
this, &ADNSampleQmaxDocking::onTopLevelChanged);
}
We connect the `topLevelChanged` signal, saving the new layout only when the window is docked. The two slots, `onTopLevelChanged` and `LoadSavedLayout`, complete the setup as shown below.
// Code Excerpt
void ADNSampleQmaxDocking::onTopLevelChanged(bool isFloating)
{
// Save on docking state
// The isFloating flag can be used to save the docks when not floating
qmaxMainWindow->saveLayout(m_layoutPath);
}
void ADNSampleQmaxDocking::LoadSavedLayout()
{
try
{
qmaxMainWindow->loadLayout(m_layoutPath);
}
catch ()
{
// Handle errors
}
}
Executing the application and starting the plugin will create the .ini file in the selected directory if it doesn't exist. This file saves not only the single plugin but all widgets and toolbars in use, restoring them if they are already open.
Leveraging Qt in 3DS Max
In conclusion, when building UI in Qt for 3ds Max, utilizing Qt tools already integrated into the software provides an elegant solution for saving and restoring docking states. Further optimizations and adjustments can be made to meet specific needs. The full code is attached below as a .zip file; feel free to explore and share your thoughts on this functionality.
Happy coding! Cheers!
Full project source code: Download ADNDockingSample
Comments
You can follow this conversation by subscribing to the comment feed for this post.