Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   Related Pages  

Lesson 6

Lesson6: Using dialogs and proper positioning and resizing.
In this lesson you will learn how to use dialogs and properly position your controls. We will modify code from Lesson 3.
There are two ways one can manage controls inside of the window. The first one is to position all controls using OnReshape(), this method will give you maximum control over your controls size and position, but it also requires you to take care of everything (what if window is resized, what if it is too small, and so on). The second one is to use panel classes sjgui::CPanel, sjgui::CStackPanel, sjgui::CSqueezePanel classes, which could:
  • Hide areas of child controls, which are outside of their area
  • Resize child controls to be complete within their area
  • Position child controls in a certain order You will learn both methods.
Note:
There is an option for each window to have minimum size (sjgui::CWnd::SetMinSize()). By default you can set it to any size, but if it is set to some value, it means that nothing will be able to make it smaller. This could be convenient for dialogs window, but if you are using such controls within panels they will not obey to the rules of the panel class.
See also:
sjgui::CPanelCtrlTmpl, sjgui::CStackCtrlPanel, sjgui::CSqueezePanelCtrlTmpl
Let us explore the first one: Manual control over positioning.
First dialog should be created:
See also:
sjgui::CDlg, sjgui::CWnd::OnReshape(), sjgui::CWnd::Reshape()
// For this lesson, you will learn how to control placement of widgets,
// as well how to use dialog windows. We will have a button in the center
// of the window (we will keep it there, even when window is resized, on button
// click we will get a dialog which will let us change the button text.

// We will start from creating a simple dialog window, which will allow
// user to enter a custom text.
class CCustomTextDlg: public sjgui::CDlg
{
    sjgui::CEdit    m_edt; // edit field
    sjgui::CLabel   m_lbl; // label with the hint
public:
    // This string will have the result of user interaction 
    // and it could be accessed by calling class
    std::string m_str;
    CCustomTextDlg()
    {
        sjgui::CDlg();
        SetAutoHide();              // Set autohide option 
        SetCaption("Text Dialog!"); // Change caption
        SetMinSize(200,100);        // Minimum size of the dialog
        SetSize(250,80);            // Default size
        RegisterChild(&m_lbl);      // Register label
        RegisterChild(&m_edt);      // Register edit field
        m_edt.SetText("sjgui");     // New text for edit field
        m_lbl.SetText("New Text:"); // Text for hint
    }
    // Place edit field in a proper position
    virtual void OnReshape()
    {
        // it should be under the caption
        m_lbl.PosWnd(5,m_Caption.GetBottom()+1,GetWidth()-10,m_edt.GetHeight());
        // it should be under the label
        m_edt.PosWnd(5,m_lbl.GetBottom()+1,GetWidth()-10,m_edt.GetHeight());
    }
    // React on closing the window, if it was Ok pressed then change the text
    virtual void OnComplete(){if(m_btnOk.IsPushed())m_str=m_edt.GetText();}
}; // end of CCustomTextDlgManual
Now it is time to modify space window:

sjgui::CButton, sjgui::CWnd::OnKeyUp()

// Here we will need button and an instance of our dialog
class CSpcWnd : public sjgui::CWnd
{
    sjgui::CButton              m_btn; // Button widget
    CCustomTextDlg              m_dlg; // Dialog window
public:
    // We reset m_fRotation and also set our check box parameters.
    CSpcWnd():CWnd()
    {
        RegisterChild(&m_btn);          // Register button
        RegisterChild(&m_dlg);          // Register dialog
    }
    // We need to handle resizing of the window so button and dialog
    // would be properly positioned
    void virtual OnReshape()
    {
        // We should set size of the button accordingly
        // to the length of the text
        m_btn.SetSize((m_btn.GetTextLen()+1)*m_btn.GetFontSize(),80);
        m_btn.ToCenter();  // button should be in the center
        m_dlg.ToCenter();  // dialog should be in the center
        // otherwise you would not be able to call base class implementation.
        using namespace sjgui;
        CWnd::OnReshape();  // It is a good habit
    }
    // Key up event handler to show dialog or change button text
    void virtual OnKeyUp(int &iKey)
    {
        // check if we need to change the text
        if(m_dlg.IsOk())
        {
            m_btn.SetLabel(m_dlg.m_str.data()); // Set text
            // We need to call Reshape() if we want button size
            // to be dynamically changed with the string.
            // And we call Reshape() instead of OnReshape(), because
            // we need child objects to be reshaped too!
            Reshape();
        }
        // Reset dialog status, so next time some key was pressed
        // we would not do the same thing again
        if(m_dlg.IsOk() || m_dlg.IsCancel())
            m_dlg.Reset();
        // Show dialog if button was pressed show or hide dialog
        if(m_btn.IsPushed())
        {
            m_btn.Reset(); // Important not to forget to reset the button!
            m_dlg.Show(!m_dlg.IsVisible()); // Switch dialog on or off
        }
    }
    // Drawing is very simple, we just need to set up the OpenGL projection mode
    // using predefined macro, and do not forget to Animate controls
    virtual void OnDraw(){Animate();SET_GL_FOR_GUI_DRAW;}
}; // end of CSpcWnd class
As one can see it was not that hard, but we had just two controls for CSpcWnd and two for CCustomTextDlg. Imagine that you have ten or more controls in one window? It would be just a pain to position all of them (look at the "examples/pos_manual.cpp" and you will see what I mean). So you would like elements to be positioned automatically! Easy! Use CStackPanel class as a base class for CustomTextDlg and see what happens:
// Automatic placement version.
// We are using the same base class, but with the different panel setting
typedef CDlgTmpl<CButton,CLabel,CSqueezePanel> base;
// Now a new version of the class
class CCustomTextDlg: public base
{
    CEdit   m_edt; // edit field
    CLabel  m_lbl; // label with the hint
public:
    // This string will have the result of user interaction 
    // and it could be accessed by calling class
    std::string m_str;
    CCustomTextDlg()
    {
        base(); // New Base class
    // Setting for the pannel
        // We want elements to be placed from top to bottom
        m_pnlClientArea.SetVertMode();
        // Distance between elements
        m_pnlClientArea.SetDist(1);
        // Initial offset from the top
        m_pnlClientArea.SetOffset(1);
        m_pnlClientArea.SetSideDist(5);
        // We want to have a little offset from the sides
        m_pnlClientArea.SetSideDist(5);
    // Old stuff
        SetAutoHide();              // Set autohide option 
        SetCaption("Text Dialog!"); // Change caption
        SetMinSize(200,100);        // Minimum size of the dialog
        SetSize(250,80);            // Default size
        RegisterToClientArea(&m_lbl);// Register label
        RegisterToClientArea(&m_edt);// Register edit field
        m_edt.SetText("sjgui");     // New text for edit field
        m_lbl.SetText("New Text:"); // Text for hint
    }
    // React on closing the window, if it was Ok pressed then change the text
    virtual void OnComplete(){if(m_btnOk.IsPushed())m_str=m_edt.GetText();}
}; // end of CCustomTextDlg automatic
The rest of the code should stay the same! As you can see there was no OnReshape() function at all, because panel class takes care of it. Just a few settings to set the panel as we would like it to be and we are ready to go! For more complex layouts you could combine panels one within another, so be creative. Look at the "examples/pos_auto.cpp" for an example containing 10 controls, other then controls of standard dialog.
Note:
You may ask what about order of elements? The answer is, that it is denoted by the order of registering child windows. You have option to reverse this order using sjgui::CStackPanel::ReverseOrder()
See also:
sjgui::CStackPanel::ReverseOrder()
Back to Lesson 5. Forward to Lesson 7.
This is full source code:
// This header includes all resources of the sjgui library
#include <sjgui/sjgui.h>

// Uncomment following line to see space window with automatic
// positioning of elements
//#define AUTO

// Choose proper version of the dialiog
#ifndef AUTO

// For this lesson, you will learn how to control placement of widgets,
// as well how to use dialog windows. We will have a button in the center
// of the window (we will keep it there, even when window is resized, on button
// click we will get a dialog which will let us change the button text.

// We will start from creating a simple dialog window, which will allow
// user to enter a custom text.
class CCustomTextDlg: public sjgui::CDlg
{
    sjgui::CEdit    m_edt; // edit field
    sjgui::CLabel   m_lbl; // label with the hint
public:
    // This string will have the result of user interaction 
    // and it could be accessed by calling class
    std::string m_str;
    CCustomTextDlg()
    {
        sjgui::CDlg();
        SetAutoHide();              // Set autohide option 
        SetCaption("Text Dialog!"); // Change caption
        SetMinSize(200,100);        // Minimum size of the dialog
        SetSize(250,80);            // Default size
        RegisterChild(&m_lbl);      // Register label
        RegisterChild(&m_edt);      // Register edit field
        m_edt.SetText("sjgui");     // New text for edit field
        m_lbl.SetText("New Text:"); // Text for hint
    }
    // Place edit field in a proper position
    virtual void OnReshape()
    {
        // it should be under the caption
        m_lbl.PosWnd(5,m_Caption.GetBottom()+1,GetWidth()-10,m_edt.GetHeight());
        // it should be under the label
        m_edt.PosWnd(5,m_lbl.GetBottom()+1,GetWidth()-10,m_edt.GetHeight());
    }
    // React on closing the window, if it was Ok pressed then change the text
    virtual void OnComplete(){if(m_btnOk.IsPushed())m_str=m_edt.GetText();}
}; // end of CCustomTextDlgManual

#else // !AUTO

// MVCS has problems with using sjgui::CDlgTmpl, but it can be worked
// around, by just using namespace. Note then you can skip sjgui:: part
// for all other controls
using namespace sjgui;
// Automatic placement version.
// We are using the same base class, but with the different panel setting
typedef CDlgTmpl<CButton,CLabel,CSqueezePanel> base;
// Now a new version of the class
class CCustomTextDlg: public base
{
    CEdit   m_edt; // edit field
    CLabel  m_lbl; // label with the hint
public:
    // This string will have the result of user interaction 
    // and it could be accessed by calling class
    std::string m_str;
    CCustomTextDlg()
    {
        base(); // New Base class
    // Setting for the pannel
        // We want elements to be placed from top to bottom
        m_pnlClientArea.SetVertMode();
        // Distance between elements
        m_pnlClientArea.SetDist(1);
        // Initial offset from the top
        m_pnlClientArea.SetOffset(1);
        m_pnlClientArea.SetSideDist(5);
        // We want to have a little offset from the sides
        m_pnlClientArea.SetSideDist(5);
    // Old stuff
        SetAutoHide();              // Set autohide option 
        SetCaption("Text Dialog!"); // Change caption
        SetMinSize(200,100);        // Minimum size of the dialog
        SetSize(250,80);            // Default size
        RegisterToClientArea(&m_lbl);// Register label
        RegisterToClientArea(&m_edt);// Register edit field
        m_edt.SetText("sjgui");     // New text for edit field
        m_lbl.SetText("New Text:"); // Text for hint
    }
    // React on closing the window, if it was Ok pressed then change the text
    virtual void OnComplete(){if(m_btnOk.IsPushed())m_str=m_edt.GetText();}
}; // end of CCustomTextDlg automatic

#endif // !AUTO

// Here we will need button and an instance of our dialog
class CSpcWnd : public sjgui::CWnd
{
    sjgui::CButton              m_btn; // Button widget
    CCustomTextDlg              m_dlg; // Dialog window
public:
    // We reset m_fRotation and also set our check box parameters.
    CSpcWnd():CWnd()
    {
        RegisterChild(&m_btn);          // Register button
        RegisterChild(&m_dlg);          // Register dialog
    }
    // We need to handle resizing of the window so button and dialog
    // would be properly positioned
    void virtual OnReshape()
    {
        // We should set size of the button accordingly
        // to the length of the text
        m_btn.SetSize((m_btn.GetTextLen()+1)*m_btn.GetFontSize(),80);
        m_btn.ToCenter();  // button should be in the center
        m_dlg.ToCenter();  // dialog should be in the center
        // otherwise you would not be able to call base class implementation.
        using namespace sjgui;
        CWnd::OnReshape();  // It is a good habit
    }
    // Key up event handler to show dialog or change button text
    void virtual OnKeyUp(int &iKey)
    {
        // check if we need to change the text
        if(m_dlg.IsOk())
        {
            m_btn.SetLabel(m_dlg.m_str.data()); // Set text
            // We need to call Reshape() if we want button size
            // to be dynamically changed with the string.
            // And we call Reshape() instead of OnReshape(), because
            // we need child objects to be reshaped too!
            Reshape();
        }
        // Reset dialog status, so next time some key was pressed
        // we would not do the same thing again
        if(m_dlg.IsOk() || m_dlg.IsCancel())
            m_dlg.Reset();
        // Show dialog if button was pressed show or hide dialog
        if(m_btn.IsPushed())
        {
            m_btn.Reset(); // Important not to forget to reset the button!
            m_dlg.Show(!m_dlg.IsVisible()); // Switch dialog on or off
        }
    }
    // Drawing is very simple, we just need to set up the OpenGL projection mode
    // using predefined macro, and do not forget to Animate controls
    virtual void OnDraw(){Animate();SET_GL_FOR_GUI_DRAW;}
}; // end of CSpcWnd class

// Now we need to setup our window, we do it in the function main.
int main(int argc, char* argv[])
{
    // Events receiver
    CSpcWnd SpcWnd;
    // Position the window
    SpcWnd.PosWnd(20,50,320,240);
    // Create window
    if(sjgui::Create(argv[0],&SpcWnd))
    {
        // Run it. Now all events are transferred to our class.
        sjgui::GlobalMainLoop();
    }
    else
        // Print error message if something was wrong.
        printf("Could not create opengl window.\n");
    return 0;
} // the end of main
sjgui logo
Quick Links:

 News
 Description
 Screen Shots
 Projects
 Downloads
 Source Code
 Help/FAQ
 Want to help?
 Credits
 Disclaimer


Documentation:

 Documentation
 Reference
 Lessons


Useful links:

sjcomp logo
sjcomp

opengl logo

nehe logo

SourceForge.net Logo

Last modified:


Started by Alexander Shyrokov. Generated at Wed Apr 28 12:31:05 2004 for the sjgui by doxygen 1.3.1. SourceForge.net Logo