Maya C++ API: create a progress window
How to add a progress bar in Maya's UI. - 05/2022 - #Maya

Leaving some C++ code snippet to display a progress window (MProgressWindow) or progress Bar (MComputation) within Maya's interface. Note that using MProgessWindow or MComputation inside a node's compute() method is unsafe/undefined. I may add that as stated in the documentation you should not modify anything within a compute() method except for the node's output attributes.
Progress window snippet:

#pragma once
#include <string>
#include <time.h>
/**
* @brief Maya progress window wrapper.
*
* Display a progress window in Maya
*
Usage:
@code
int total = nb_iter;
Progress_window window("Process in progress", total);
// will only display progress if operation is running greater than
// a certain delay
window.set_delay(0.5); // (optional default = 1 sec)
for(int iter = 0; iter < total; iter++)
{
if(window.is_canceled())
break;
//do stuff
...
window.add(1);
}
window.stop(); // Optional (performed when the object is destructed)
@endcode
@warning Like a lot of things in Maya nodes it's not safe to use a
progress window (or any UI related functions)
inside a MPxNode::compute() MPxDeformer::deform() etc.
*
*/
class Progress_window {
private:
/// How much we wait before displaying the window
/// (time represented in clocks ticks) (see time.h clock())
time_t _delay;
/// starting time (in clock ticks) (see time.h clock())
time_t _start;
bool _is_init;
bool _interruptable;
std::string _win_title;
int _progress;
int _max_range;
public:
Progress_window();
Progress_window(const std::string& win_title, int max_range, bool interuptable = true);
~Progress_window();
void start(const std::string& win_title, int max_range);
void set_delay(float seconds) {
_delay = time_t((float)CLOCKS_PER_SEC*seconds);
_delay = _delay <= 0 ? 0 : _delay;
}
void add_progess(int increment = 1);
void stop();
/// @brief force window to show regardless of the delay
/// set with "set_delay()"
void show();
/// @return if the canceled button was hit by the user.
const bool is_canceled()const;
};
#include "progress_window.hpp"
#include <maya_error.hpp> // my custom macros to check errors
#include <maya/MProgressWindow.h>
#include <maya/MString.h>
Progress_window::Progress_window()
: _delay(CLOCKS_PER_SEC*1)
{
}
// -----------------------------------------------------------------------------
Progress_window::Progress_window(const std::string& win_title,
int max_range,
bool interuptable)
: _delay(CLOCKS_PER_SEC*1)
, _interruptable( interuptable )
{
start(win_title,max_range);
}
// -----------------------------------------------------------------------------
Progress_window::~Progress_window(void)
{
stop();
}
// -----------------------------------------------------------------------------
void Progress_window::start(const std::string& win_title, int max_range)
{
_max_range = max_range;
_win_title = win_title;
_start = clock();
_progress = 0;
_is_init = false;
}
// -----------------------------------------------------------------------------
void Progress_window::stop()
{
if (_is_init)
{
// Maya doc:
// Destroys the progress window and removes it from the screen.
// This method also unreserves the progress window,
// making it available for future reservation.
mayaCheck( MProgressWindow::endProgress() );
_is_init = false;
}
}
// -----------------------------------------------------------------------------
void Progress_window::add_progess(int increment)
{
if( clock() > (_start + Progress_window::_delay) ) {
show();
}
if (_is_init){
mayaCheck( MProgressWindow::advanceProgress(increment) );
}
else{
_progress += increment;
}
}
// -----------------------------------------------------------------------------
void Progress_window::show()
{
if(!_is_init )
{
// Maya doc: MProgressWindow::reserve()
// Reserves a progress window for use through this class.
// This method must be called before setting progress window parameters or starting progress.
// Returns: true if the progress window was successfully reserved
if (MProgressWindow::reserve())
{
_is_init = true;
mayaCheck( MProgressWindow::setProgressRange(0, _max_range) );
mayaCheck( MProgressWindow::setTitle( _win_title.c_str() ) );
mayaCheck( MProgressWindow::setProgressStatus(_win_title.c_str()) );
mayaCheck( MProgressWindow::setInterruptable(_interruptable) );
mayaCheck( MProgressWindow::setProgress(_progress) );
// Maya doc: Displays the progress window on the screen.
mayaCheck( MProgressWindow::startProgress() );
}
}
}
// -----------------------------------------------------------------------------
const bool Progress_window::is_canceled() const
{
return _is_init && MProgressWindow::isCancelled();
}
Progress bar snippet:

#pragma once
#include <string>
#include <time.h>
#include <maya/MComputation.h>
/**
* @brief Maya MComputation wrapper.
*
* Display a progress bar in the lower left corner of Maya UI
* You can also cancel computation with "ESC" key
*
Usage:
@code
int total = nb_iter;
Progress_bar a_bar("Process in progress", total);
// will only display progress if operation is running greater than
// a certain delay
a_bar.set_delay(0.5); // (optional default = 1 sec)
for(int iter = 0; iter < total; iter++)
{
// Triggered on escape key:
if(a_bar.is_canceled())
break;
//do stuff
...
a_bar.add(1);
}
a_bar.stop(); // Optional (performed when the object is destructed)
@endcode
@warning Like a lot of things in Maya nodes it's not safe to use a
progress bar (or any UI related functions)
inside a MPxNode::compute() MPxDeformer::deform() etc.
*
*/
class Progress_bar {
private:
mutable MComputation _computation; /* MComputation is not const correct..*/
/// How much we wait before displaying the window
/// (time represented in clocks ticks) (see time.h clock())
time_t _delay;
/// starting time (in clock ticks) (see time.h clock())
time_t _start;
bool _is_init;
bool _interruptable;
std::string _win_title;
int _progress;
int _max_range;
public:
Progress_bar();
Progress_bar(const std::string& win_title, int max_range, bool interuptable = true);
~Progress_bar();
void start(const std::string& win_title, int max_range);
void set_delay(float seconds) {
_delay = time_t((float)CLOCKS_PER_SEC*seconds);
_delay = _delay <= 0 ? 0 : _delay;
}
void add_progess(int increment = 1);
void stop();
/// @brief force window to show regardless of the delay
/// set with "set_delay()"
void show();
/// @return if the canceled button was hit by the user.
const bool is_canceled()const;
};
#include "progress_bar.hpp"
#include <maya_error.hpp> // custom macros to hande errors
#include <maya/MString.h>
Progress_bar::Progress_bar()
: _delay(CLOCKS_PER_SEC*1)
{
}
// -----------------------------------------------------------------------------
Progress_bar::Progress_bar(const std::string& win_title,
int max_range,
bool interuptable)
: _delay(CLOCKS_PER_SEC*1)
, _interruptable( interuptable )
{
start(win_title,max_range);
}
// -----------------------------------------------------------------------------
Progress_bar::~Progress_bar(void)
{
stop();
}
// -----------------------------------------------------------------------------
void Progress_bar::start(const std::string& win_title, int max_range)
{
_max_range = max_range;
_win_title = win_title;
_start = clock();
_progress = 0;
_is_init = false;
}
// -----------------------------------------------------------------------------
void Progress_bar::stop()
{
if (_is_init)
{
_computation.endComputation();
_is_init = false;
}
}
// -----------------------------------------------------------------------------
void Progress_bar::add_progess(int increment)
{
_progress += increment;
if( clock() > (_start + Progress_bar::_delay) ) {
show();
}
if (_is_init){
_computation.setProgress(_progress);
}
}
// -----------------------------------------------------------------------------
void Progress_bar::show()
{
if(!_is_init )
{
_is_init = true;
_computation.beginComputation(true/*show progress bar*/, _interruptable, true /*wait cursor*/);
if( !_interruptable )
_computation.setProgressStatus( _win_title.c_str() );
_computation.setProgressRange(0, _max_range) ;
_computation.setProgress(_progress);
}
}
// -----------------------------------------------------------------------------
const bool Progress_bar::is_canceled() const
{
return _is_init && _computation.isInterruptRequested();
}
No comments