Writing a CustomDialog

From MantidProject

Jump to: navigation, search

A new plugin mechanism has been written that allows the use of custom widgets for certain algorithms rather than using the generic input dialog. The new library, MantidQt, contains an API to create new dialog widgets and specialised library containing any custom-made dialogs that have been written. When running an algorithm, assuming the library containing the widget(s) can be loaded, these will be used in place of the generic dialog. This page aims to guide you through this process.

Contents

Sub-classsing

For the API to understand the new widget, it must be created as a sub-class of AlgorithmDialog. Here I will assume we have an algorithm called 'MyAlg', for which the basic header and source code would look like

Header file (MyAlgDialog.h)

#ifndef MYALGDIALOG_H
#define MYALGDIALOG_H
 
#include "MantidQtCustomDialogs/ui_MyAlgDialog.h"
#include "MantidQtAPI/AlgorithmDialog.h"
 
class MyAlgDialog : public MantidQt::API::AlgorithmDialog
{
 
 Q_OBJECT
 
public:
  ///Constructor
  MyAlgDialog(QWidget* parent = 0);
 
private:
  ///Overloaded function to initialise the layout
  void initLayout();
 ///Overloaded function to parse the input from the dialog
  void parseInput();
 
private:
  /// Access the Ui form
  Ui::MyAlgDialog m_uiForm;
};
 
#endif //MYALGDIALOG_H

Source File (MyAlgDialog.cpp)

#include "MyAlgDialog.h"
 
//Register the class with the factory
DECLARE_DIALOG(MyAlgDialog)
 
///Constructor
MyAlgDialog::MyAlgDialog(QWidget* parent = 0) : AlgorithmDialog(parent)
{
}
 
///Reimplemented function to set up the layout
void MyAlgDialog::initLayout()
{
   m_uiForm.setupUI(this);
}
 
///Reimplemented function to extract to input from the dialog
void MyAlgDialog::parseInput()
{
}

Assuming this class were compiled into a library and that library were placed into the plugins directory of MantidPlot, we would now have a customwidget that would load when we ran MyAlg. This custom dialog would not contain anything yet since we have not added any other widgets to it.

Creating a new layout

At this point we can go in one of two directions. The first is the hand craft the layout code in initLayout and the second is to use the Qt Designer package. The first is more difficult and time consuming but is more flexible and the second means that you can instantly get a feel for the look of the dialog since you are creating it by dragging and dropping widgets with the mouse. Here I will look at the second method, using Qt Designer, as it should be used in the majority of cases.

Upon starting the designer, a wizard should ask if you would like to create a new dialog. Click on the desired option and this will bring up a new window representing the new dialog widget. Assuming the default setup, a list of draggable widgets should appear on the left of the screen and a box listing the properties of the current widget on the right. The first task is to ensure the object name is set correctly as we will need to refer to this later. To change this, left-click in the new window's title bar and then edit the field in the properties list that is called objectName. This should be set to the same name as your class, which in our example is MyAlgDialog. This is also a good time to change the text that appears in the title bar. This is done by editing the windowTitle field and can be set to anything. The tools within Qt designer can now be used to create a specialised dialog for the algorithm, which basically means creating widgets that correspond to algorithm properties. For example, a property that requires text entry will most probably require either a Line Edit or Text Edit field and a property that has a number of allowed values is best represented as a combo box. It is recommended that the object names for each of the fields taking user input be changed to something more representative of their contents, i.e. a box taking the input for a "Filename" property could have the object name filenameBox so that it can be referred to easily later on.

When the design is complete, it needs to be saved as a Qt form with a .ui extension and placed in the same directory as the header file MyAlgDialog.h. Once this is saved, it is included in the code by first adding:

#include "ui_MyAlgDialog.h"

before #include "MantidQtAPI/AlgorithmDialog.h" and

private:
  Ui::MyAlgDialog m_uiForm;

after void parseInput();. Please note that the file 'ui_MyAlgDialog.h' does not exist at this point as it is automatically generated by the Qt tools during the compilation process. The private variable m_uiForm provides an interface to the layout generated by the designer and is used to setup the layout. In the .cpp file, the initLayout() function should be changed to look like this,

///Reimplemented function to set up the layout
void MyAlgDialog::initLayout()
{
  m_uiForm.setupUi(this);
}

where the setupUi function is responsible for creating the layout.

Compiling into the library

We now have three files, MyAlgDialog.h, MyAlgDialog.cpp and MyAlgDialog.ui that need compiling into the MantidQtCustomDialogs library. This involves editing the CustomDialogs.pro file within the MantidQt/CustomDialogs directory. The file, at time of writing, contains lines that look like

SOURCES = \
  $$SRCDIR/LoadRawDialog.cpp \
  $$SRCDIR/LOQScriptInputDialog.cpp \
  $$SRCDIR/CreateSampleShapeDialog.cpp \
  $$SRCDIR/SampleShapeHelpers.cpp \
  $$SRCDIR/MantidGLWidget.cpp
HEADERS = \
  $$HEADERDIR/LoadRawDialog.h \
  $$HEADERDIR/LOQScriptInputDialog.h \
  $$HEADERDIR/CreateSampleShapeDialog.h \
  $$HEADERDIR/SampleShapeHelpers.h \
  $$HEADERDIR/MantidGLWidget.h
FORMS = \
 $$HEADERDIR/LOQScriptInputDialog.ui \
 $$HEADERDIR/CreateSampleShapeDialog.ui

and our new dialog files need to be added the appropriate variables.

Running qmake in the MantidQt directory will then ensure that the forms (.ui files) are processed and the appropriate header files created. Running make (nmake on Windows) then compiles the indicated files. The library is created, by default, in MantidQt/lib. For MantidPlot to pick the library up as a plugin, it must be in the location pointed to by plugins.directory variable of the Mantid.properties file.

Parsing the input

Running the code above will produce the dialog with the required layout but none of the widgets will be connected to their corresponding algorithm properties. The parseInput function is responsible for taking the input from the widget and assigning it to the correct property. Each of the boxes is accessible from the m_uiForm object by using the object names that were set in Qt designer. Using these and a function available from the base class called storePropertyValue the properties can be parsed out and set correctly. For example, if we had a property called 'OutputWorkspace' and a box called 'outputWSBox', the code

storePropertyValue("OutputWorkspace", m_uiForm.outputWSBox->text());

placed inside the parseInput function would extract the text from the outputWSBox and link it to the "OutputWorkspace" property. Doing the same for all other properties enables all of the properties to be parsed from the boxes.

Personal tools
Create a book