Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

SolidWidgets Dialog Resource Editor

0.00/5 (No votes)
20 Jul 2012CPOL2 min read 8.3K  
A short tutorial to quickly show how the Visual Editor component is used.

Introduction

Free for PERSONAL and COMMERCIAL use

The SolidWidgets UI framework includes a very powerful dialog editor component that can be embedded directly in application. If you ever had a requirement to build an interactive visual designer that the users can use to design screen layouts, move around dialog resources, etc, you already know how difficult it is to build such functionality. This Visual Editor component included in the SolidWidgets library gives you the solution to this problem. The component is extremely simple to use, and can easily be integrated with any SolidWidgets application. I have been truly impressed with how much functionality this library includes, and the great design of the overall framework. Following is a short tutorial to quickly show how this component is used.

Using the Dialog Editor component

Following are the steps needed to integrate this component into your application:

  1. Create a dialog or a frame class, and make the class inherit swVisualEditorListener. swVisualEditorListener requires you to implement two functions that give you control over the types of objects that the user adds or modify at runtime.
  2. Include the header swVisualEditor.h:
  3. C++
    #include <swVisualEditor.h>
  4. Implement the following functions in your class:
  5. C++
    public: // swVisualEditorListener implementations
        void paint(swGDI *g,const swString& objId,const swString& objText,
        long x,long y,long width,long height);
        BOOL editObjectProperties(swString& objId,swString& objText);
  6. Add your code in the paint function to implement custom painting of the objects.
  7. Add your code in editObjectProperties to allow the user to edit the properties of the object.

The visual designer component tracks the id, text, and position of each object, you can maintain a separate list that tracks whatever other information your application requires about each object. The best way to do this is to have a list of object records, where each record has a matching id to an object in the component, and the record will have other attributes that describe the object. For example,

C++
class VEditDialog: public swDialog, public swVisualEditorListener
{
    class ScreenObject
    {
    public:
        swString objId;
        long objectType; // LABEL, TEXTFIELD, PICTURE, etc. You define these constants.
        swString pictureFilePath;
    };
    swVector<ScreenObject> m_screenObjects;
    swVisualEditor m_designer;
    swButton m_okBtn,m_cancelBtn;

public:

    void windowOpening();
    void windowOpened();
    BOOL windowClosing();
    void windowClosed();
    void actionPerformed(long sourceId,long eventId,const swString& eventName);

public: // swVisualEditorListener implementations

    void paint(swGDI *g,const swString& objId,const swString& objText,long x,long y,long width,long height);
    BOOL editObjectProperties(swString& objId,swString& objText);
};

Sample implementation of the paint method:

C++
void paint(swGDI *g,const swString& objId,const swString& objText,long x,long y,long width,long height)
{
    // Locate the object in m_screenObjects;
    long matchingObjectIndex = -1;
    long numObjects = m_screenObjects.size();
    for(long i=0;i<numObjects;i++)
    {
        if(m_screenObjects[i].objId.equalsIgnoreCase(objId))
        {
            matchingObjectIndex = i;
            break;
        }
    }
    //
    Rect objRect;
    objRect.SetRect(x,y,x+width-1,y+height-1);
    g->fillRect(objRect,swColor(255,255,255));
    //    
    if(matchingObjectIndex>=0)
    {
        if(m_screenObjects[i].objectType == LABEL)
            g->drawString(objText,objRect,ALIGNMENT_CENTER);
        else if(m_screenObjects[i].objectType == TEXTFIELD)
        {
            g->drawString(objText,objRect,ALIGNMENT_CENTER);
            g->draw3DRect(objRect,FALSE);
        }
        else if(m_screenObjects[i].objectType == PICTURE)
        {
            g->drawImageFile(m_screenObjects[i].pictureFilePath,objRect,FALSE);
            g->drawRect(objRect);
        }
    }
}

Sample implementation of the editObjectProperties method:

C++
BOOL editObjectProperties(swString& objId,swString& objText)
{
    // Locate the object in m_screenObjects;
    long matchingObjectIndex = -1;
    long numObjects = m_screenObjects.size();
    for(long i=0;i<numObjects;i++)
    {
        if(m_screenObjects[i].objId.equalsIgnoreCase(objId))
        {
            matchingObjectIndex = i;
            break;
        }
    }
    if(matchingObjectIndex>=0) // EXISTING OBJECT
    {
        // Do nothing right here
    }
    else // NEW OBJECT, ASSIGN IT A UNIQUE ID
    {
        ScreenObject newObj;
        newObj.objId = swString::static_fromLong(m_designer.getObjectCount()+1);
        m_screenObjects.push_back(newObj);
        matchingObjectIndex = m_screenObjects.size()-1; // save the index of the new object
        //
		objId = newObj.objId; // must return the id of the new object
    }
    //
    if(matchingObjectIndex>=0)
    {
        // Now display a custom dialog that allows the user to choose the type
        // of the object: LABEL, PICTURE, etc, in addition to other attributes
        return TRUE;
    }
    return FALSE;
}

Here is the resulting code:

C++
//
// VEditDialog.h
//
#include <swDialog.h>
#include <swVisualEditor.h>
#include <swButton.h>

class VEditDialog: public swDialog, public swVisualEditorListener
{
    class ScreenObject
    {
    public:
        swString objId;
        long objectType; // LABEL, TEXTFIELD, PICTURE, etc. You define these constants.
        swString pictureFilePath;
    };
    swVector<ScreenObject> m_screenObjects;
    swVisualEditor m_designer;
    swButton m_okBtn,m_cancelBtn;

public:

    void windowOpening();
    void windowOpened();
    BOOL windowClosing();
    void windowClosed();
    void actionPerformed(long sourceId,long eventId,const swString& eventName);

public: // swVisualEditorListener implementations

    void paint(swGDI *g,const swString& objId,const swString& objText, 
               long x,long y,long width,long height);
    BOOL editObjectProperties(swString& objId,swString& objText);
};
//
// VEditDialog.cpp
//
#include "VEditDialog.h"

void VEditDialog::windowOpening()
{
    setSize(800,600);

    swPanel *contentPane = getContentPane();
    if(contentPane!=NULL)
    {
        contentPane->setMargins(10,10,10,10);

        contentPane->addRow();
        contentPane->addRow(10);
        contentPane->addRow(25); // Button Row

        contentPane->addColumn();
        contentPane->addColumn(100); // OK Button
        contentPane->addColumn(100); // Cancel Button

        contentPane->addChild(&m_designer,0,0,3,1); // occupies 3 columns and 1 row
        contentPane->addChild(&m_okBtn,1,2,1,1); // occupies 1 column and 1 row
        contentPane->addChild(&m_cancelBtn,2,2,1,1); // occupies 1 columns and 1 row
    }
    m_designer.setListener(this);
    //
    m_okBtn.setActionListener(this);
    m_okBtn.setText(L"OK");
    m_cancelBtn.setActionListener(this);
    m_cancelBtn.setText(L"Cancel");
}

void VEditDialog::windowOpened()
{
}

BOOL VEditDialog::windowClosing()
{
	return TRUE;
}

void VEditDialog::windowClosed()
{
}

void VEditDialog::actionPerformed(long sourceId,long eventId,const swString& eventName)
{
    if(sourceId == m_okBtn.getID())
    {
        dispose(swOK);
    }
    else if(sourceId == m_cancelBtn.getID())
    {
        dispose(swCANCEL);
    }
}

void VEditDialog::paint(swGDI *g,const swString& objId, 
     const swString& objText,long x,long y,long width,long height)
{
    // Locate the object in m_screenObjects;
    long matchingObjectIndex = -1;
    long numObjects = m_screenObjects.size();
    for(long i=0;i<numObjects;i++)
    {
        if(m_screenObjects[i].objId.equalsIgnoreCase(objId))
        {
            matchingObjectIndex = i;
            break;
        }
    }
    //
    Rect objRect;
    objRect.SetRect(x,y,x+width-1,y+height-1);
    g->fillRect(objRect,swColor(255,255,255));
    //    
    if(matchingObjectIndex>=0)
    {
        if(m_screenObjects[i].objectType == LABEL)
            g->drawString(objText,objRect,ALIGNMENT_CENTER);
        else if(m_screenObjects[i].objectType == TEXTFIELD)
        {
            g->drawString(objText,objRect,ALIGNMENT_CENTER);
            g->draw3DRect(objRect,FALSE);
        }
        else if(m_screenObjects[i].objectType == PICTURE)
        {
            g->drawImageFile(m_screenObjects[i].pictureFilePath,objRect,FALSE);
            g->drawRect(objRect);
        }
    }
}

BOOL VEditDialog::editObjectProperties(swString& objId,swString& objText)
{
    // Locate the object in m_screenObjects;
    long matchingObjectIndex = -1;
    long numObjects = m_screenObjects.size();
    for(long i=0;i<numObjects;i++)
    {
        if(m_screenObjects[i].objId.equalsIgnoreCase(objId))
        {
            matchingObjectIndex = i;
            break;
        }
    }
    if(matchingObjectIndex>=0) // EXISTING OBJECT
    {
        // Do nothing right here
    }
    else // NEW OBJECT, ASSIGN IT A UNIQUE ID
    {
        ScreenObject newObj;
        newObj.objId = swString::static_fromLong(m_designer.getObjectCount()+1);
        m_screenObjects.push_back(newObj);
        matchingObjectIndex = m_screenObjects.size()-1; // save the index of the new object
        //
		objId = newObj.objId; // must return the id of the new object
    }
    //
    if(matchingObjectIndex>=0)
    {
        // Now display a custom dialog that allows the user to choose
        // the type of the object: LABEL, PICTURE, etc, in addition to other attributes
        return TRUE;
    }
    return FALSE;
}

Final outcome:

Login

Points of interest

As easy and simplistic as this code looks, you will start realizing the power of this framework as you dig deeper into the various components. You can find more help on http://www.solidwidgets.com. The site includes a bunch of examples on how to use each component.

Conclusion

I hope this tutorial helps someone who needs to implement such functionality. Best of luck!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)