We value your input!
Please participate in Archicad 28 Home Screen and Tooltips/Quick Tutorials survey

Archicad C++ API
About Archicad add-on development using the C++ API.

[SOLVED] How to create a TabControl

Anonymous
Not applicable
Hello

My goal is to create a TabControl but I can not find an example in DevKit folder.

I want to achieve this www.graphisoft.com/ftp/techsupport/documentation/developer_docs/AC_10/APIDevKit/DialogManager/DGHtml...

Please advise.
6 REPLIES 6
Tamas Zolnai
Graphisoft Alumni
Graphisoft Alumni
Hi,

Here is an example how it can be implemented.
1. Let see how resource file looks like. Two things is needed

1.1 First you need to add a TabControl item (e.g. NormalTab or SingleTab) to the corresponding dialog:

'GDLG'  32590  Modal | grow    300  300  387  350  "TabControl Dialog" {
/* [  1] */ Button				  308  311   70   20	LargePlain  "OK"
/* [  2] */ NormalTab			   12   12  364  285
                 32591  NoIcon  "TabPage1"
}

'DLGH'  32590  DLG_32590_TabControl_Dialog {
1	""							Button_0
2	""							NormalTab_0
}
As you see next to the 'OK' button here we have a NormalTab control and one TabPage
(it's important to add at least one TabPage to the TabControl otherwise resource file
won't compile).

1.2 After TabControl is added to the dialog, TabPages (you can define any of them) also should
be defined:

'GDLG'  32591  TabPage       0    0  256  121  "TabPage1" {
/* [  1] */ LeftText			    6   10  100   18	LargePlain  vCenter  "Some text"
/* [  2] */ TextEdit			   87    7  106   23	LargePlain  255
}

'DLGH'  32591  DLG_32591_TabPage1 {
1	""							LeftText_0
2	""							TextEdit_0
}
I added a LeftText and a TextEdit to the corresponding TabPage in this example just to see
something on the screen.

2. The C++ header contains a dialog and an observer class. You can overload any
virtual functions of NormalTabObserver to change the TabControl default behavior:

#ifndef (TABCONTROL_DIALOG_HPP)
#define TABCONTROL_DIALOG_HPP

#include	"DG.h"
#include	"DGModule.hpp"


#define TABCONTROL_DIALOG_RESID			32590

// --- TabControl Dialog -----------------------------------------------

class TabControlDialog: public DG::ModalDialog
{
	friend class TabControlObserver;

private:

	enum {
		OkButtonId	= 1,
		TabControlId	= 2,
	};

	DG::NormalTab		mTabControl;
	DG::Button		mOkButton;

public:

	TabControlDialog	(GSResModule dialResModule, short resId);
	~TabControlDialog	();
};

// --- TabControlObserver -----------------------------------------------

class TabControlObserver:	public DG::PanelObserver,
					public DG::NormalTabObserver,
					public DG::ButtonItemObserver,
					public DG::CompoundItemObserver
{
private:
	TabControlDialog*		mDialog;

protected:
	// DG::PanelObserver
	virtual void	PanelOpened (const DG::PanelOpenEvent& ev) override;

	// DG::ButtonItemObserver
	virtual void	ButtonClicked (const DG::ButtonClickEvent& ev) override;

public:
	explicit		TabControlObserver (TabControlDialog* testDialog);
	~TabControlObserver ();
};

#endif // TABCONTROL_DIALOG_HPP
3. In the C++ source file you can find how the dialog is initialized.

#include	"TabControlDialog.hpp"
#include	"DGMenu.hpp"
#include	"DGTabControl.hpp"


//---------------------------- Class TabControlDialog -----------------------

TabControlDialog::TabControlDialog (GSResModule dialResModule, short resId):
	DG::ModalDialog		(dialResModule, resId, dialResModule),
	mOkButton			(GetReference (), OkButtonId),
	mTabControl			(GetReference (), TabControlId)
{
}


TabControlDialog::~TabControlDialog ()
{
}


//-------------------------- Class TabControlObserver -----------------------

TabControlObserver::TabControlObserver (TabControlDialog* testDialog):
	mDialog (testDialog)
{
	mDialog->Attach (*this);
	AttachToAllItems (*mDialog);
}


TabControlObserver::~TabControlObserver ()
{
	mDialog->Detach (*this);
	DetachFromAllItems (*mDialog);
}


void TabControlObserver::PanelOpened (const DG::PanelOpenEvent& /*ev*/)
{
	mDialog->SetClientSize (mDialog->GetOriginalClientWidth (), mDialog->GetOriginalClientHeight ());
}


void TabControlObserver::ButtonClicked (const DG::ButtonClickEvent& ev)
{
	// Close dialog with acceptance
	if (ev.GetSource () == &mDialog->mOkButton) {
		mDialog->PostCloseRequest (DG::ModalDialog::Accept);
	}
}

After all of that you have a dialog with a TabControl.

Best Regards,
Tamás Zolnai
Graphisoft
Anonymous
Not applicable
Thank you for the answer!
Anonymous
Not applicable
Tamás wrote:
Hi,

Here is an example how it can be implemented.
1. Let see how resource file looks like. Two things is needed

1.1 First you need to add a TabControl item (e.g. NormalTab or SingleTab) to the corresponding dialog:

'GDLG'  32590  Modal | grow    300  300  387  350  "TabControl Dialog" {
/* [  1] */ Button				  308  311   70   20	LargePlain  "OK"
/* [  2] */ NormalTab			   12   12  364  285
                 32591  NoIcon  "TabPage1"
}

'DLGH'  32590  DLG_32590_TabControl_Dialog {
1	""							Button_0
2	""							NormalTab_0
}
As you see next to the 'OK' button here we have a NormalTab control and one TabPage
(it's important to add at least one TabPage to the TabControl otherwise resource file
won't compile).

1.2 After TabControl is added to the dialog, TabPages (you can define any of them) also should
be defined:

'GDLG'  32591  TabPage       0    0  256  121  "TabPage1" {
/* [  1] */ LeftText			    6   10  100   18	LargePlain  vCenter  "Some text"
/* [  2] */ TextEdit			   87    7  106   23	LargePlain  255
}

'DLGH'  32591  DLG_32591_TabPage1 {
1	""							LeftText_0
2	""							TextEdit_0
}
I added a LeftText and a TextEdit to the corresponding TabPage in this example just to see
something on the screen.

2. The C++ header contains a dialog and an observer class. You can overload any
virtual functions of NormalTabObserver to change the TabControl default behavior:

#ifndef (TABCONTROL_DIALOG_HPP)
#define TABCONTROL_DIALOG_HPP

#include	"DG.h"
#include	"DGModule.hpp"


#define TABCONTROL_DIALOG_RESID			32590

// --- TabControl Dialog -----------------------------------------------

class TabControlDialog: public DG::ModalDialog
{
	friend class TabControlObserver;

private:

	enum {
		OkButtonId	= 1,
		TabControlId	= 2,
	};

	DG::NormalTab		mTabControl;
	DG::Button		mOkButton;

public:

	TabControlDialog	(GSResModule dialResModule, short resId);
	~TabControlDialog	();
};

// --- TabControlObserver -----------------------------------------------

class TabControlObserver:	public DG::PanelObserver,
					public DG::NormalTabObserver,
					public DG::ButtonItemObserver,
					public DG::CompoundItemObserver
{
private:
	TabControlDialog*		mDialog;

protected:
	// DG::PanelObserver
	virtual void	PanelOpened (const DG::PanelOpenEvent& ev) override;

	// DG::ButtonItemObserver
	virtual void	ButtonClicked (const DG::ButtonClickEvent& ev) override;

public:
	explicit		TabControlObserver (TabControlDialog* testDialog);
	~TabControlObserver ();
};

#endif // TABCONTROL_DIALOG_HPP
3. In the C++ source file you can find how the dialog is initialized.

#include	"TabControlDialog.hpp"
#include	"DGMenu.hpp"
#include	"DGTabControl.hpp"


//---------------------------- Class TabControlDialog -----------------------

TabControlDialog::TabControlDialog (GSResModule dialResModule, short resId):
	DG::ModalDialog		(dialResModule, resId, dialResModule),
	mOkButton			(GetReference (), OkButtonId),
	mTabControl			(GetReference (), TabControlId)
{
}


TabControlDialog::~TabControlDialog ()
{
}


//-------------------------- Class TabControlObserver -----------------------

TabControlObserver::TabControlObserver (TabControlDialog* testDialog):
	mDialog (testDialog)
{
	mDialog->Attach (*this);
	AttachToAllItems (*mDialog);
}


TabControlObserver::~TabControlObserver ()
{
	mDialog->Detach (*this);
	DetachFromAllItems (*mDialog);
}


void TabControlObserver::PanelOpened (const DG::PanelOpenEvent& /*ev*/)
{
	mDialog->SetClientSize (mDialog->GetOriginalClientWidth (), mDialog->GetOriginalClientHeight ());
}


void TabControlObserver::ButtonClicked (const DG::ButtonClickEvent& ev)
{
	// Close dialog with acceptance
	if (ev.GetSource () == &mDialog->mOkButton) {
		mDialog->PostCloseRequest (DG::ModalDialog::Accept);
	}
}

After all of that you have a dialog with a TabControl.

Best Regards,
Thanks but somewhere I have to call TabControlObserver class right ? oterwise TabControlObserver class doesn't run
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
ggiloyan wrote:
Thanks but somewhere I have to call TabControlObserver class right ? oterwise TabControlObserver class doesn't run


To show the dialog you should call this method:
static void		Show_TabControlDialog (void) 
{ 
	TabControlDialog		dialog (ACAPI_GetOwnResModule (), 32590); 
	if (DBERROR (dialog.GetId () == 0)) { 
		return; 
	} 
 
	TabControlObserver		observer (&dialog); 
	dialog.Invoke (); 
	return; 
}

Regards,
Tibor
Tamas Zolnai
Graphisoft Alumni
Graphisoft Alumni
Hi,

Additional thing. If you need to define the behavior of your TabPage, you should create seperate
TabPage and TabPageObserver classes like this:

#include	"DGTabPage.hpp"
#include	"DGEditControl.hpp"
#include	"APIEnvir.h"
#include	"ACAPinc.h"


//---------------------------- Class MyTabPage -----------------------


class MyTabPage: public DG::TabPage
{
	friend class MyTabPageObserver;

private:
	enum {
		TextEditId		= 2
	};

	DG::TextEdit	mTextEdit;

public:

	MyTabPage	(const DG::TabControl& tabControl, short tabItem);
	~MyTabPage	(void);
};

MyTabPage::MyTabPage (const DG::TabControl& tabControl, short tabItem):
	DG::TabPage			(tabControl, tabItem, ACAPI_GetOwnResModule(), 32591, ACAPI_GetOwnResModule ()),
	mTextEdit			(GetReference (), TextEditId)
{

}


MyTabPage::~MyTabPage ()
{
}

//---------------------------- Class MyTabPageObserver -----------------------


class MyTabPageObserver:	public	DG::PanelObserver,
							public  DG::CompoundItemObserver
{

private:
	MyTabPage*		mTabPage;

protected:
	// DG::PanelObserver
	virtual void	PanelClosed (const DG::PanelCloseEvent& ev) override;

public:
	explicit		MyTabPageObserver (MyTabPage* tabPage);
	~MyTabPageObserver (void);
};


MyTabPageObserver::MyTabPageObserver (MyTabPage* tabPage):
mTabPage (tabPage)
{
	mTabPage->Attach (*this);
	AttachToAllItems (*mTabPage);
}


MyTabPageObserver::~MyTabPageObserver ()
{
	mTabPage->Detach (*this);
	DetachFromAllItems (*mTabPage);
}


void MyTabPageObserver::PanelClosed (const DG::PanelCloseEvent& ev)
{
	if (ev.GetSource () == mTabPage) {
		DGAlert(DG_INFORMATION, "Information box", "Text changed in the text edit to:", mTabPage->mTextEdit.GetText(),"OK");
	}
}
After you have these classes you need to use them inside your dialog class
("-": removed line, "+": added line, "": no change):

class TabControlDialog: public DG::ModalDialog
{
	friend class TabControlObserver;

private:

	enum {
		OkButtonId	= 1,
		TabControlId	= 2,
		TabPageId		= 3,
	};

	DG::NormalTab        mTabControl;
	DG::Button           mOkButton;
+  MyTabPage*           mTabPage;
+  MyTabPageObserver*   mTabPageObserver;

public:

	TabControlDialog	(GSResModule dialResModule, short resId);
	~TabControlDialog	();
};
In the constructor you can create the TabPage and link it with the Observer object:

TabControlDialog::TabControlDialog (GSResModule dialResModule, short resId):
	DG::ModalDialog	  (dialResModule, resId, dialResModule),
	mOkButton           (GetReference (), OkButtonId),
	mTabControl         (GetReference (), TabControlId),
+  mTabPage            (new MyTabPage (mTabControl, 1)),
+  mTabPageObserver    (new MyTabPageObserver (mTabPage))
{
}
Also take care of the dynamically allocated objects:

TabControlDialog::~TabControlDialog ()
{
+	delete mTabPageObserver;
+	delete mTabPage;
}
With these additional changes the new TabControl dialog will write out the text typed into the
text edit on the first TabPage when the dialog is closed.

Best Regards,
Tamás Zolnai
Graphisoft
Anonymous
Not applicable
Now everything is clear. Thank you for the detailed answer!