IonicWind Software

Aurora Compiler => GUI => Topic started by: Doc on January 31, 2006, 05:24:01 AM

Title: Tab Control?
Post by: Doc on January 31, 2006, 05:24:01 AM
Paul,
Is there any possibility that we may see a native tab control for Aurora?

This seems to be one of the most versatile controls for dealing with large/complex GUI's and one that I keep finding a need for in some of the stuff I do...

Part II
Whether the answer is yea or nay, does anyone have an idea of how to implement a non-native one in Aurora?

I've got a partially finished project that I started in an unrelated language that I would like to try porting to Aurora... not only does it need a speed boost, but that would give me an opportunity to do some real work while learning. :)

-Doc-
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on January 31, 2006, 05:30:32 AM
Doc,
All of the common controls will be included.  TreeView, Tab, and Slider will probably be in the next update.  The RichEdit control took up most of my time for the last one ;)
Title: Re: Tab Control?
Post by: Doc on January 31, 2006, 05:33:46 AM
You da man!  8) 8) 8) :D

-Doc-
Title: Re: Tab Control?
Post by: Parker on January 31, 2006, 01:24:06 PM
Non native as in not the windows API one? You'd have to keep a list of all the tabs and just handle the painting and tab change messages. There are a couple of things I wanted to do that requires tabs have handles and not just id slots, when there are API headers I'll try it but it may take quite a while.
Title: Re: Tab Control?
Post by: Doc on January 31, 2006, 05:51:29 PM
QuoteNon native as in not the windows API one?

Yepper, that's what I meant. Yuk. I read through the API doc's on using the tab control and it looks pretty messy to me. But then again *everything* with the API looks messy to me!  ::)

At any rate, since Paul has the Aurora versions already scheduled, don't worry with it unless it's something you need for your own use.... I'm perfectly happy to wait. :)

Thanks,
-Doc-
Title: Re: Tab Control?
Post by: Parker on January 31, 2006, 08:40:09 PM
The aurora controls just wrap the API controls into a class. If a functionality isn't provided by Microsoft it can't be used in Aurora.

What I meant is writing one from scratch which I'm going to do eventually, but it will probably be a long time before I start.
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on January 31, 2006, 08:53:35 PM
Quote
If a functionality isn't provided by Microsoft it can't be used in Aurora.

That is not necessarily true.  Ownerdraw controls let you provide your own drawing capability.  The button control uses this to provide colored buttons, something that is not provided by Microsoft in the stock control. Oddly enough.
Title: Re: Tab Control?
Post by: Parker on January 31, 2006, 08:57:57 PM
Sorry, I was referring to the ability to get a tab's handle which you can't do :(
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on January 31, 2006, 09:03:15 PM
That's because the tab control is a single entity, there is no handle to get, except for the entire control that is.  The control just 'draws' the tab. Much like there isn't a separate handle for the thumb bar or arrows of a scrollbar. 

For kicks you should look at the source for Wine.  A lot of reverse engineering went into the controls to make them look and feel the same.

Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 01, 2006, 02:51:35 PM
Here is a demo program of the tab control.  You won't be able to compile it until the next update...but I wanted to show you what will be involved.  Notice there isn't a pointer in sight ;).  That's because member classes are now constructed properly.


class TabDemo : window
{
declare OnClose(),int;
declare OnCreate(),int;
declare OnSize(int nType,int cx,int cy),int;
declare OnEraseBkgnd(),int;
CTabCtrl tab1;
}

#define TABID 2

global sub main()
{
TabDemo cp;
cp.Create(0,0,640,480,AWS_MINIMIZEBOX|AWS_MAXIMIZEBOX|AWS_SIZE|AWS_VISIBLE|AWS_SYSMENU,0,"Tab Control Test",0);
cp.EnableTabs(true);
Do{ wait(); }until cp.m_hWnd = 0;
}

TabDemo::OnCreate(),int
{
tab1.Create(0,0,640,480,AWS_BORDER|AWS_VISIBLE|AWS_TABSTOP|ATCS_TOOLTIPS|ATCS_HOTTRACK,TABID,"",this);
tab1.InsertTab(0,"Calendar");
tab1.InsertTab(1,"Trackbar");
tab1.InsertTab(2,"Progress Bar");
tab1.InsertTab(3,"Date/Time picker");
tab1.InsertTab(4,"IP Address");
//tooltips for the tabs
tab1.SetTip (0,tab1.GetTabText(0));
tab1.SetTip (1,tab1.GetTabText(1));
tab1.SetTip (2,tab1.GetTabText(2));
tab1.SetTip (3,tab1.GetTabText(3));
tab1.SetTip (4,tab1.GetTabText(4));
return true;
}

TabDemo::OnClose(),int
{
Destroy();
return true;
}

TabDemo::OnSize(int nType,int cx,int cy),int
{

rcClient = GetClientRect();
tab1.SetSize(rcClient.left,rcClient.top,rcClient.right - rcClient.left,rcClient.bottom-rcClient.top);
return true;
}

TabDemo::OnEraseBkgnd(),int
{
//returning TRUE indicates we will handle erasing the windows background
//because the tab control covers the entire client area.
return true;
}
Title: Re: Tab Control?
Post by: Zen on February 01, 2006, 03:06:39 PM
Hey thats looking nice and tidy Paul. No pointers either, its like a dream come true ;)

Lewis
Title: Re: Tab Control?
Post by: Parker on February 01, 2006, 03:16:38 PM
The tab control will be a nice thing to have. I'll have to look at wine too, it'll be interesting to see.

I think what I meant by handles is something like a control ID. A single tab just has an index which isn't very helpful when you have an MDI tabbed interface and tabs can be removed by closing a window, then all the windows tab references have to be updated. I'd like it better if tab ID 1 always stays as 1 and doesn't change to 2 when a tab is inserted in front of it. But I guess I've got two choices; live with it or make my own.
Title: Re: Tab Control?
Post by: Zen on February 01, 2006, 03:20:51 PM
i suppose you dont have to make your own. Just make some subroutines to manage it how you want it too.

Lewis
Title: Re: Tab Control?
Post by: Parker on February 01, 2006, 03:27:02 PM
I can't do that since MS doesn't provide enough functionality. Or at least not the way I want to.
Title: Re: Tab Control?
Post by: Zen on February 01, 2006, 03:30:09 PM
What exactly is it you want to do? is this that thing you were going on about before when you were trying to get a handle to a clientarea type thing of the tab control?

Lewis
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 01, 2006, 03:50:05 PM
The tab control supports user data.  Just set that to the handle of the client window.  When the client window is going to close use that to match the tab...just a simple loop will do it.

In the Aurora control the two methods are SetItemData and GetItemData.
Title: Re: Tab Control?
Post by: Doc on February 01, 2006, 03:55:10 PM
Quote from: Lewis on February 01, 2006, 03:06:39 PM
Hey thats looking nice and tidy Paul. No pointers either, its like a dream come true ;)

Lewis

I completely agree. Awesome!

-Doc-
Title: Re: Tab Control?
Post by: Parker on February 01, 2006, 05:31:53 PM
Yeah but it's a two way system. The tab storing the window's hwnd I got fine. But I wanted to have a window store the tab's ID. Although, I suppose doing a loop wouldn't be a bad idea, just going through all the tabs.

And yes, I wanted the "client area" of a tab control because it changes based on what text size you have, whether there are images, etc. This image demonstrates what I'm looking for. Just ignore the bottom line.
(http://www.maj.com/gallery/virusscanner/screenshots/tabcontrol.png)

Maybe that area can't be calculated and you just have to subtract a tab's height from the whole control, I know that can be done.

I actually like working with pointers. They give you more flexibility, like passing NULL instead of having to fill a new type, and dynamically allocating them.
Title: Re: Tab Control?
Post by: Zen on February 01, 2006, 05:40:17 PM
i think the best way to do what you are doing would be to write a custom control that is basicly a subclassed tab control. That way it will be easy to use your new control and it should work on all systems.

Lewis
Title: Re: Tab Control?
Post by: Parker on February 01, 2006, 05:43:28 PM
Urgh... no, I don't feel like doing any subclassing or owner draw. If I have to do that I'd rather write my own that has all the functionality I want.

But see this
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/tab/messages/tcm_getitemrect.asp
I can just do a simple GetSize() and subtract to get the sizes I want. Maybe I'll try once again at this tabbed MDI thing.
Title: Re: Tab Control?
Post by: Zen on February 01, 2006, 05:53:21 PM
i didnt mean do all the owner draw stuff, basicly your own control would just hide all the nasty code that you would use to get the "client area" so to speak.

Lewis
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 01, 2006, 05:57:20 PM
No need to subclass with OOP.  Just derive your own class and add the functionaity you need.
Title: Re: Tab Control?
Post by: Zen on February 01, 2006, 05:58:21 PM
whOOPs that what i mean, still not used to the terminology, does the same kind of job though.

Lewis
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 01, 2006, 05:59:23 PM
As for a tabbed MDI....if you look at the IDE you'll note that the tab control is only as large as the tabs itself.  Normally you don't use the blank area of a tab control for anything.  You can, and I have made other controls children of a tab, but it is not necessary.

Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 02, 2006, 07:16:28 AM
TreeView is now done as well.
Title: Re: Tab Control?
Post by: Parker on February 02, 2006, 08:18:05 AM
With all these controls being included natively to the language, will the dialog editor have a bunch more buttons with customizations for those controls?
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 02, 2006, 08:26:06 AM
TreeView is already part of the dialog editor.  Have to add buttons for the other ones yet and wire in a dialog for properties.

Title: Re: Tab Control?
Post by: Doc on February 03, 2006, 05:28:55 AM
Having a quick look at the latest include file, I see some interesting options for the tab contol. :)

Quote from: Ionic Wizard on February 01, 2006, 05:59:23 PM
As for a tabbed MDI....if you look at the IDE you'll note that the tab control is only as large as the tabs itself.  Normally you don't use the blank area of a tab control for anything.  You can, and I have made other controls children of a tab, but it is not necessary.



Hummm... some of this I'm not quite understanding.
Can we not set the size and placement of the tab control within a parent window? More importantly (to me at least) is there not a native way to place and use various controls on each tab?

For example, maybe I need to place a button and multi-line edit control on tab one, then a list box and multi-line edit on tab two... etc. Do-able?

If not, maybe someone can explain in fairly simple terms, how I can add that type of functionality on my own.  ???

-Doc-
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 03, 2006, 08:11:59 AM
I said you can do it.  But it is not necessary.

Remember the tab control is just a single element.  There are no 'panes' so if your going to place controls directly on top of the tab then you'll have to hide them when the user switches tabs.

Paul.
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 03, 2006, 09:02:06 AM
And that was about as clear as mud ;).  Not enough coffee yet this morning.

Layout each set of controls for each tab, when the user switches tabs you use the ShowWindow method to hide the previous set of controls and show the currently selected set.   It can be a little hard to impliment at first, but works.

What you probably want is property pages.  A property page is a different control, which uses individual dialog templates for each pane of controls.  Also known as 'wizards'.  And is something we will have available by the beta versions.

The tab controls purpose in life is just to show a bunch of tabs that a user can click on, and sends notifcation messages that a tab was pressed.  The task bar in windows is a tab control using button style tabs.

Paul.
Title: Re: Tab Control?
Post by: Doc on February 03, 2006, 03:59:25 PM
lol ...I know all too well about the coffee thing early in the morning. :)

On the other hand, it dawned on me what you were describing *after* I got to work, so maybe I was the one needing coffee.  ;) I'm not sure about the property page that you mentioned, but below I've pasted a sample (completely unrelated) of the type of interface I need for the app I'm building:

(http://www.dcwebenterprises.com/tabsample.jpg)

It's not really a "wizard" by any means, but I will be walking the user through a number of steps (tabs) where they will use various controls along the way. Once they reach the final tab, a button click will start a pretty nifty amount of processing, based on the data and options selected. Showing and hiding contols based on tab clicks could get a little messy, but I'm game if it can be done.  ;D

-Doc-
Title: Re: Tab Control?
Post by: Parker on February 03, 2006, 04:22:47 PM
You can actually accomplish this with a helper function and lists. Give me a while, I'll try to work out something. This will be the second time of my using Aurora's GUI though so it may take a while.
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 05, 2006, 12:08:16 AM
I'll have an example in the next update for you.  Actually the 'tabctrl.src' example really isn't finished yet ;)  It will have separate controls on each pseudo-pane.
Title: Re: Tab Control?
Post by: donh on February 16, 2006, 05:37:21 PM
I have been experimenting with the tab control I think I am doing somthing wrong with tist code you get no tabs displayed but if you comment out
this line it gives tabs d1.AddControl(CTTABCTRL,"Tab Control",57,20,179,126,0x54000040,0x0,TABID);
In the example it does not have this line is it realy requied?  I am stumped as this gets generated from the editor 
the other question is how do you set a child window to be the one with edit box / button.  I have been reading they talk about SetParrent but do not se that one or am I again miss understanding this stuff.  Trying to start out with small the ad the rest of my code.

Don


#define TABID 1
#define BUTTON_2 2
#define EDIT_3 3
class dlg:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
CTabCtrl tab1;
}

global sub main()
{
dlg d1;
d1.Create(0,0,300,202,0x80C80080,0,"Tab Test",0);
d1.AddControl(CTTABCTRL,"Tab Control",57,20,179,126,0x54000040,0x0,TABID);
d1.AddControl(CTBUTTON,"Button1",103,98,70,20,0x5000000B,0x0,BUTTON_2);
d1.AddControl(CTEDIT,"Edit1",85,53,126,21,0x50800000,0x200,EDIT_3);
d1.EnableTabs(true);
d1.DoModal();
return 0;
}

dlg::OnClose(),int
{
CloseDialog(1);
return true;
}

dlg::OnInitDialog(),int
{

// Create Tab Control And Add Tabs
tab1.Create(57,20,179,126,AWS_VISIBLE|AWS_TABSTOP|ATCS_TOOLTIPS|ATCS_HOTTRACK,TABID,"",this);
tab1.SetFont("Arial",12,400,0);
tab1.InsertTab(0,"First Tab");
tab1.InsertTab(1,"Second Tab");
tab1.InsertTab(2,"Third Tab");
CenterWindow();
return true;
}

dlg::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select nID
{
case TABID:
/* respond to control notifications here */
case BUTTON_2:
if(nNotifyCode = 0)
{
/*button clicked*/
}
case EDIT_3:
/* respond to edit notifications here */
}
return true;
}


Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 16, 2006, 05:42:13 PM
Your doing it wrong ;)

The tab control is added by AddControl and then created by Windows when you call DoModal.

Your OnInitDialog should look like this.

dlg::OnInitDialog(),int
{
CTabCtrl *tab = GetControl(TABID);
tab->InsertTab(0,"First Tab");
tab->InsertTab(1,"Second Tab");
tab->InsertTab(2,"Third Tab");
}

Creating the tab control manually is only needed for using it in a window, not a dialog.

Paul.
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 16, 2006, 05:44:13 PM
Also your EnableTabs function does nothing since a dialog already responds to the TAB key, which has nothing to do with a Tab control, even though they share the same name.

I've always thought MS should have called it a notebook control.
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 16, 2006, 06:00:23 PM
Here is a complete example generated from the dialog editor


#define TAB_1 1
class dlg:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
}

global sub main()
{
dlg d1;
d1.Create(0,0,300,202,0x80C80080,0,"Caption",0);
d1.AddControl(CTTABCTRL,"Tab Control",40,22,214,104,0x54000000,0x0,TAB_1);

d1.DoModal();
return 0;
}

dlg::OnClose(),int
{
CloseDialog(1);
return true;
}

dlg::OnInitDialog(),int
{
/* Initialize any controls here */
CTabCtrl *tab = GetControl(TAB_1);
tab->SetFont("Arial",10,200);
tab->InsertTab(0,"First Tab");
tab->InsertTab(1,"Second Tab");
tab->InsertTab(2,"Third Tab");
CenterWindow();
return true;
}

dlg::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select nID
{
case TAB_1:
/* respond to control notifications here */
}
return true;
}


The important thing to always remember is that with a dialog you don't create the controls with a Create method, Windows creates them based on a dialog template.  That template is created in memory with the CDialog::Create and subsequent AddControl methods.

When you call DoModal that template is loaded by the DialogBoxIndirectParamA API function, which reads each classname (windows class, not OOP class) and creates all of the controls in one sweep.

Before your OnInitDialog is called, Aurora's internal one is called which makes sure all of the Windows control handles are associated with a dynamically created CControl based object.

GetControl returns that object (oop class) based on the ID you specified in the AddControl method.

If you have the Aurora source code then read through the dialog_instance source file.  For AddControl you will see a SELECT statement and a corresponding NEW for each type of control class.   Then when the dialog handler receives WM_INITDIALOG it calls DoSubclass which basically just does:

pControl->m_hWnd = hControl;
SetPropA(hControl, "THIS", pControl);

The THIS property of the control allows GetControl to return a pointer to the original control object based on the handle to the control.

All of this serves the same purpose that it does in other languages.  Dialogs are reusable and you can call DoModal as many times to show the same dialog over and over again without having to recreate the controls or the dialog itself.  A window needs to bew recreated from scratch everytime it is closed.  A dialog just needs to reload the template.

Now using controls in a window has always been different.  You define a variable of one of the built in control classes, such as CTabCtrl and use the Create method to create and show the control.  It is your responsibility to manage the class then. When you use NEW you have to use DELETE, etc.

Paul.



Title: Re: Tab Control?
Post by: donh on February 16, 2006, 07:33:42 PM
thanks Paul thats what I thought.  I was doing it wrong.  Been looking at many differant examples that are incomplete.
Now time to sit and look at the source some more and get the head around it.
Made these changes to my other program.  Now it's time to go back and play some more.
This old person will get it eventually

Don
Title: Re: Tab Control?
Post by: Doc on February 17, 2006, 07:15:47 PM
Okay, in hopes that I might actually start understanding this stuff, can someone please show me how to:

A.) set the font for the button just as it is with the tabs.
B.) Either make the button a "child" of tab 3 -or- show/hide as required to simulate that effect.
C.) Display the code required to show a response to the tab click on say... tab 2 for example.

(Code below was generated from the dialog editor with only the additional tabs added manually.)

#define TAB_1 1
#define BUTTON_3 3
class dlg:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
}

global sub main()
{
dlg d1;
d1.Create(0,0,371,246,0x80CB0080,0,"Caption",0);
d1.AddControl(CTTABCTRL,"Tab Control",12,23,334,199,0x54000040,0x0,TAB_1);
d1.AddControl(CTBUTTON,"Button1",54,84,70,20,0x5000000B,0x0,BUTTON_3);


d1.DoModal();
return 0;
}

dlg::OnClose(),int
{
CloseDialog(1);
return true;
}

dlg::OnInitDialog(),int
{
/* Initialize any controls here */
/* Initialize any controls here */
CTabCtrl *tab = GetControl(TAB_1);
tab->SetFont("Arial",10,200);
tab->InsertTab(0,"First Tab");
tab->InsertTab(1,"Second Tab");
tab->InsertTab(2,"Third Tab");

CenterWindow();
return true;
}

dlg::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select nID
{
case TAB_1:
/* respond to control notifications here */


case BUTTON_3:
if(nNotifyCode = 0)
{
/*button clicked*/
}
}
return true;
}


Absolutely nothing I've tried has worked up to this point...
Hep me, hep me, I'm losing my mind.  ;)

-Doc-
Title: Re: Tab Control?
Post by: donh on February 17, 2006, 08:51:16 PM
Doc,

You are not alone.  Been trying this out for several hours now tonight.
and last night.  Been studying the code from the source and the examples.  But like you a might bit stumped  ??? ??? ???


Don
Title: Re: Tab Control?
Post by: donh on February 17, 2006, 09:00:12 PM
Doc,

Here is what I got so far just got the tabs to be recognized this is a big break for me
so there might be hope for me.


Don

#define TAB_1 1

int NewTabIDX,OldTabIDX;
class dlg:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
}

global sub main()
{
dlg d1;
d1.Create(0,0,300,202,0x80C80080,0,"Caption",0);
d1.AddControl(CTTABCTRL,"Tab Control",40,22,214,104,0x54000000,0x0,TAB_1);

d1.DoModal();
return 0;
}

dlg::OnClose(),int
{
CloseDialog(1);
return true;
}

dlg::OnInitDialog(),int
{
/* Initialize any controls here */
CTabCtrl *tab = GetControl(TAB_1);
tab->SetFont("Arial",10,200);
tab->InsertTab(0,"First Tab");
tab->InsertTab(1,"Second Tab");
tab->InsertTab(2,"Third Tab");
CenterWindow();
return true;
}

dlg::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select nID
{
case TAB_1:
/* respond to control notifications here */
CTabCtrl *tab = GetControl(TAB_1);
NewTabIDX = tab->GetSelectedTab();
if (NewTabIDX <> OldTabIDX)
{
OldTabIDX = NewTabIDX;

if (NewTabIDX = 0)
{
messagebox(this,"First Tab Was Selected","Test",0);
}
if (NewTabIDX = 1)
{
messagebox(this,"Second Tab Was Selected","Test",0);
}
if (NewTabIDX = 2)
{
messagebox(this,"Third Tab Was Selected","Test",0);
}
}


}
return true;
}
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 17, 2006, 09:00:42 PM
Give me a little while and I will do it. Not really that difficult, just have to use a flag to indicate which group of controls is currently being displayed.  I did post an example of it in my previous language.

Title: Re: Tab Control?
Post by: Doc on February 17, 2006, 09:06:32 PM
Hey Don!
Well, at least I'm not alone... misery loves company ya know. :)

The real problem that I'm having is in understanding the relationship of the sub-tabs and/or other controls (button in this case) to Tab_1. This is one of those OOP/Class mysteries that I haven't fully gotten my head wrapped around yet.

Just adding a case statement for the 2nd tab throws up errors all over everywhere:
  case TAB_2:
/* respond to control notifications here */


However! I do believe that once I finally understand this one in particular, the "Aha!" light is just about ready to come on for a large portion of the other OOP stuff.

-Doc-
Title: Re: Tab Control?
Post by: Doc on February 17, 2006, 09:08:31 PM
You guys posted while I was asleep at the wheel...

Quote from: Ionic Wizard on February 17, 2006, 09:00:42 PM
Give me a little while and I will do it. Not really that difficult, just have to use a flag to indicate which group of controls is currently being displayed.  I did post an example of it in my previous language.



Much appreciated! Yep, ready for that "Aha!" light to come on.  ;D

-Doc-
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 17, 2006, 09:17:34 PM
Here is the first example.  It is in a window.  Dialog example to follow


class TabDemo : CWindow
{
declare OnClose(),int;
declare OnCreate(),int;
declare OnSize(int nType,int cx,int cy),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
declare OnEraseBkgnd(),int;
CTabCtrl tab1;
CButton btn1;
CListBox box1;

}

#define TABID 2
#define BTNID 3
#define BOXID 4

global sub main()
{
TabDemo cp;
cp.Create(0,0,640,480,AWS_MINIMIZEBOX|AWS_MAXIMIZEBOX|AWS_SIZE|AWS_VISIBLE|AWS_SYSMENU,0,"Tab Control Demo 2",0);
cp.EnableTabs(true);
Do{ wait(); }until cp.m_hWnd = 0;
}

TabDemo::OnCreate(),int
{
tab1.Create(0,0,640,480,AWS_BORDER|AWS_VISIBLE|AWS_TABSTOP|ATCS_TOOLTIPS|ATCS_HOTTRACK,TABID,"",this);
tab1.SetFont("Arial",12,400,0);
tab1.InsertTab(0,"Tab 1");
tab1.InsertTab(1,"Tab 2");
tab1.InsertTab(2,"Tab 3");
//tooltips for the tabs
tab1.SetTip (0,tab1.GetTabText(0));
tab1.SetTip (1,tab1.GetTabText(1));
tab1.SetTip (2,tab1.GetTabText(2));
//create our controls for the tabs, The listbox is invisible
btn1.Create(10,40,80,20,AWS_VISIBLE,BTNID,"A Button",this);
box1.Create(10,40,80,100,0,BOXID,"",this);
box1.AddString("It is a");
box1.AddString("A list box");
return true;
}

TabDemo::OnClose(),int
{
Destroy();
return true;
}

TabDemo::OnSize(int nType,int cx,int cy),int
{

rcClient = GetClientRect();
tab1.SetSize(rcClient.left,rcClient.top,rcClient.right - rcClient.left,rcClient.bottom-rcClient.top);
return true;
}

TabDemo::OnEraseBkgnd(),int
{
//returning TRUE indicates we will handle erasing the windows background
//because the tab control covers the entire client area.
return true;
}

TabDemo::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
switch(nID)
{
case TABID:
if(nNotifyCode = TCNSELCHANGE)
{
nTab = tab1.GetSelectedTab();
switch(nTab)
{
case 0: //show the button
btn1.ShowWindow(SWSHOW);
box1.ShowWindow(SWHIDE);
case 1: //show the listbox
btn1.ShowWindow(SWHIDE);
box1.ShowWindow(SWSHOW);
case 2: //an empty tab
btn1.ShowWindow(SWHIDE);
box1.ShowWindow(SWHIDE);

}
}
return false; //we return false or the tabs won't change

}
return true;
}
Title: Re: Tab Control?
Post by: donh on February 17, 2006, 09:19:11 PM
Paul,

You are to fast you realy make feel old.
Title: Re: Tab Control?
Post by: Doc on February 17, 2006, 10:04:31 PM
Thanks Paul!
I've got your window example printed to hard copy and I'm ready to dig into it.
...maybe now you'll have a few minutes to do something beside holding my hand.
Much appreciated.

-Doc-
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 17, 2006, 10:16:38 PM
Still working on the dialog one.  Stargate Atlantis is on so working when the commercials are on.
Title: Re: Tab Control?
Post by: Doc on February 17, 2006, 10:23:49 PM
Quote from: Ionic Wizard on February 17, 2006, 10:16:38 PM
Still working on the dialog one.  Stargate Atlantis is on so working when the commercials are on.

lol... that's how you guys caught me sleeping at the wheel earlier in this thread, except it was something on the Olympics coverage that caught my eye. :)

-Doc-
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 17, 2006, 11:21:34 PM
Just a quickie example.  You'll get the general idea from it.


#define TAB_1 1
#define BUTTON_2 2
#define LISTBOX_3 3
class TabDlg:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
//member pointers to copy the control class pointers into.
CTabCtrl *m_tab1;
CButton *m_btn1;
CListBox *m_list1;
}

global sub main()
{
TabDlg d1;
d1.Create(0,0,300,202,0x80C80080,0,"Caption",0);
d1.AddControl(CTTABCTRL,"",0,0,299,202,0x54000000,0x0,TAB_1);
d1.AddControl(CTBUTTON,"A Button",32,40,70,20,0x5000000B,0x0,BUTTON_2);
d1.AddControl(CTLISTBOX,"",31,40,103,95,0x50800140,0x200,LISTBOX_3);

d1.DoModal();
return 0;
}

TabDlg::OnClose(),int
{
CloseDialog(1);
return true;
}

TabDlg::OnInitDialog(),int
{
m_tab1 = GetControl(TAB_1);
m_btn1 = GetControl(BUTTON_2);
m_list1 = GetControl(LISTBOX_3);

/* Initialize any controls here */
m_tab1->SetFont("Arial",10,400,0);
m_tab1->InsertTab(0,"Tab 1");
m_tab1->InsertTab(1,"Tab 2");
m_tab1->InsertTab(2,"Tab 3");
//tooltips for the tabs
m_tab1->SetTip (0,m_tab1->GetTabText(0));
m_tab1->SetTip (1,m_tab1->GetTabText(1));
m_tab1->SetTip (2,m_tab1->GetTabText(2));

m_list1->AddString("It is a");
m_list1->AddString("List Box");
m_list1->ShowWindow(SWHIDE);

CenterWindow();
return true;
}

TabDlg::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
select nID
{
case TAB_1:
/* respond to control notifications here */
if(nNotifyCode = TCNSELCHANGE)
{
nTab = m_tab1->GetSelectedTab();
switch(nTab) {
case 0:
m_btn1->ShowWindow(SWSHOW);
m_list1->ShowWindow(SWHIDE);
case 1:
m_btn1->ShowWindow(SWHIDE);
m_list1->ShowWindow(SWSHOW);
case 2:
m_btn1->ShowWindow(SWHIDE);
m_list1->ShowWindow(SWHIDE);

}


}
return false;
case BUTTON_2:
if(nNotifyCode = 0)
{
/*button clicked*/
}
case LISTBOX_3:
/* respond to control notifications here */
}
return true;
}
Title: Re: Tab Control?
Post by: donh on February 18, 2006, 06:31:43 AM
Thanks much

Much beter examples than waht I have been looking at in several books they only gave partial examples at the explination was clear as mud.
Now what you explied the other day and this I should be able to make better progress.  I already see from your example a better way to respond to the tab than my ugly way.
But thats what one book showed.
;D
Title: Re: Tab Control?
Post by: Doc on February 18, 2006, 08:56:49 AM
Bet you folks think this thread will never end...  ;)

Because they seem to be perfect candidates (due to a personal motivation factor), I've decided that these tab examples will serve as my "line in the sand" from an OOP learning perspective. It's gonna be now or never, so hopefully you good folks will have enough patience.

.........................

I understand that in the Window version of the tab sample, a new window named "TabDemo" is subclassed, complete with the methods necessary to work with the new class. Based on that, maybe someone can fill in the gaps for the things I know that I don'y fully understand.

Q1.
Snip-> class TabDemo : CWindow
I'm thinking that the colon designates that the new class is derived from the CWindow class, but does it actually serve as a pointer to the parent class?

Q2.
Snip->TabDemo::OnClose(),int
How exactly does the double colon function exactly? A pointer to a virtual function or method?


Q3.
cp.Create(0,0,640,480,
...
...
cp.EnableTabs(true);

In simple terms, what does the "cp" used in cp.xxxx mean? My only guess at this point, is that it represents a pointer to the new class and/or methods. Yes/No?

Patience and assistance will be much appreciated.

-Doc-
Title: Re: Tab Control?
Post by: Ionic Wind Support Team on February 18, 2006, 09:52:30 AM
Q1.   Your just deriving a class from CWindow.  It is not a pointer, more like a UDT definition.  Classes are based on structures (UDT).

Q2.  Again not a pointer.  It is a implimentation of the method of a class.  In otherwords a subroutine that is part of the class and not accessable unless you are using an instance of that class.

Q3. 'cp' is the variable name. 

def cp as TabDemo;

A class is a type of variable, a very advance type but just a variable nonetheless.

Class, OOP, etc all came about with the idea of encapsulation.  Objects should manage their own data and not external global variables. 

Lets say you have a UDT containing all of the members needed to represent an image. 


struct myimage
{
int width;
int height;
int bpp; //bits per pixel
pointer memory; //where the graphic is stored
}


Then a bunch of functions that might take a parameter of the UDT type 'myimage'.  Basic stuff here, you have used it in other languages.


SUB LoadImage(mi as myimage, name as string)
{
...load the file
mi.width = GetWidth(name);
...etc
}

SUB ShowImage(mi as myimage, hwnd as UINT)
{
...
}

SUB SaveImage(mi as myimage, name as string)
{
...
}



So in order to use these functions you have to first define a variable of myimage and pass it to the functions.


def image1 as myimage;
LoadImage(image1, "happy.bmp");
ShowImage(image1, win.hwnd);
SaveImage(image1, "sad.bmp");


Simple enough, you are used to using UDT's.  And what you have done above is used OOP in its simplest form.  image1 is an instance of the myimage UDT.  The problems with the above method is that the programmer has to keep track of what function works with what UDT type.  What happens when someone changes the UDT definition without changing the subroutines?  It can get chaotic.

Classes extend the idea of a UDT 'object' by coupling them with functions that work with the data in that structure.  So lets look at a partial  class representation of the above.


class myimage
{
declare LoadImage(name as string);
declare SaveImage(name as string);
declare ShowImage(HWND as UINT);
int width;
int height;
int bpp; //bits per pixel
pointer memory; //where the graphic is stored
}

myimage::LoadImage(name as string)
{
...load the file
width = GetWidth(name);
...etc
}


Now when you declare a variable of that class you don't need the external UDT to hold the data.  Instead the compiler knows those particular members are part of the class


def image1 as myimage;
image1.LoadImage("happy.bmp");
image1.ShowImage(win.hwnd);
image1.SaveImage("sad.bmp");


What is happening here is the first statement defines a variable of type 'myimage' which is a class.  Internally it is just a structure (UDT) that has all of the member variables + 1 for a table of virtual functions.  If you were to peer into memory it would just look like a structure.

myimage
{
pointer _VTABLE_
int width;
int height;
int bpp; //bits per pixel
pointer memory; //where the graphic is stored
}

And you can use a class variable just like it was a UDT in most cases.


def image1 as myimage;
image1.width = 0;


The fun part comes with the member functions.  Lets look at one of them:


image1.LoadImage("happy.bmp");


The compiler translates this into a function call that kind of looks like this:


myimage@LoadImage(&image1, "happy.bmp");


Think about it.  When you wrote the class method for LoadImage the compiler first came up with unique name so the subroutine wouldn't clash with any other names, and then did something interesting.  It added a parameter at the beginning called the 'this' pointer.


myimage::LoadImage(name as string)
{
}


Gets converted to  (in psuedo terms)


SUB myimage@LoadImage(myimage *this, name as string)
{
}


The result is a group of subroutines, and the data associated with those subroutines, in one package known simply as an "object". When your code is executing within a method of that object (a subroutine of that class) it has direct access to the variables of the object structure.  For example consider the snippet, copied from above


myimage::LoadImage(name as string)
{
...load the file
width = GetWidth(name);
...etc
}


In particular the line

width = GetWidth(name);

"width" is a member variable of the class "myimage".  When the compiler encounters a variable name that your referencing in a class method it first checks the class to see if you have a member of that name.  In this case we do so in essance the compiler is doing this:


this->width = GetWidth(name);


'this' is that added parameter the compiler adds to each class subroutine.  It is a pointer whose type is the same as the class and an address of your class variable is passed.  Putting it together with the function call:

image1.LoadImage("happy.bmp");

translates to:

myimage@LoadImage(&image1,"happy.bmp");

------------

myimage::LoadImage(name as string)

translates to

SUB myimage@LoadImage(myimage *this, name as string)

------------

and

this->width = GetWidth(name);

accesses the 'width' member of the class structure passes automatically to the LoadImage method.

Understand?
Title: Re: Tab Control?
Post by: Doc on February 18, 2006, 10:07:50 AM
QuoteUnderstand?

Well, obviously not just yet. But I will.  :)
...I'm not gonna backoff an inch or head in any other directions until I *do* have a basic understanding. I've put it off way too long already and I've reached a point where avoiding the issue is a hindrance.

I'll print your mini-lecture and study it along with the examples until it becomes clear.

Thank you very much kind sir!

-Doc-