Dynamic Tabs was one of the great new features added to WinDev version 20. However based on some comments we had in a recent webinar, there are still quite a few folks out there that don’t know exactly what they are or how to use them. So this week I will be doing a primer on Dynamic Tabs. Along with Dynamic Tabs we will be covering Internal Windows as they are a key part of how Dynamic Tabs work, and we will also be looking at a small management class I created to help me track the open dynamic tabs in my application, this lets me switch focus to an existing tab when a menu option is selected for a second time, versus opening a new tab.
So lets start with exactly what is a Dynamic Tab. Dynamic Tabs allow you to open multiple windows on a single window. Each window is opened as a tab of a tab control. The best example of this style of interface is modern web browsers, which allow you to open new pages into tabs and have multiple tabs open. And just like modern browsers, the dynamic tab control also allows the end user to “pull” a tab out of the tab control and have it as a completely separate window.
Before we go any further there is another WinDev feature we need to discuss, Internal Windows. An internal window is a window that is display the window inside an Internal Window Control as part of another window. At runtime the window is “merged” into a single window. The power of this is at runtime you can change which Internal Window is displayed inside the Internal Window Control. For instance you might have an internal window that shows the current status of different areas of the company (Orders processed today, shipments received, etc). However the information that you want to show might be quite different for the CEO versus the shipping clerk. You could design the “base” window with the primary information that is only displayed, and an area defined as an internal window that displays the section of information that is different for each user. Then programmaticly, based on the user type, you can determine which internal window is displayed in that area.
From a maintenance standpoint this is much easier to maintain as the information that is different for each user type is defined as its own internal window, so you are able to work on that discrete area on its own. And of course the common information is only defined once on the “base” window. Without internal windows, you would have two choice on how to create that interface. You could declare several windows for each user type, and the common information area would be declare on each, making a change to the common information a maintenance nightmare. Your other option would be to have one window with all the information and then logic that hides/unhides and moves controls around on the screen for each user type, making for some very complex logic, especially if the look of the option information is quite different between user types. Having used both of those solutions in the past, I can tell you the Internal Window solution is better than either of them!
One last example of how you might use Internal windows, is if there is a certain feature that you make available in several windows of your application. One option for that would be to use a control template, another option would be to create an internal window and then show the internal window on each window that needs the feature.
Enough about Internal Windows, that isn’t what today’s topic is about, but the reason we needed to discuss Internal Windows is that Dynamic Tabs are really just a nice interface pcSoft has provided us to display Internal Windows, so you must understand and be able to work with Internal Windows in order to use Dynamic tabs.
Let’s talk about some basics of Dynamic Tabs next. First any tab control can become a Dynamic tab, it is just some additional features added to the Tab control we already know and use. In fact you can even turn the Dynamic features on and off programmaticly.
So let’s look at a typical use of dynamic tabs in one of my projects.
This is the “main menu” of the application, as they choose option from the ribbon bar, the corresponding window is opened as a tab of the Dynamic Tab control. This make it easy for a user to jump back and forth between different screens as each remains open as a tab. Even more powerful, the user can drag one of the tabs out into its own window, even on to another monitor if they have multiple monitors.
So let’s create a similar interface in the NextAge Open Source demo application. The first thing to know is that Dynamic Tabs require at least one “static” or “normal” tab. What I have choosen to do with this tab in most of my applications is use it as an “always available” about screen.
However in one of my projects, we used it to present a dashboard. So be creative, the rule is that there be one tab that is “always” there and isn’t dynamic, what you do with that tab is up to you.
We are going to create it as an “About Screen” for today’s session, so of the general tab we can go ahead and set the up. Note you can setup several static tabs, so if you situation warrants it, you could even have an interface that has a few tabs that are always there and then just add on dynamic tabs as the user needs. Perhaps opening up the most common features when the application is first ran. The possibilities are endless.
Let’s put the NextAge logo on the About tab. For you projects you might want to use your logo instead 😉
Next on the Details tab of the Tab control we enable dynamic tabs. I also disabled the New button. For this interface the user “adds” tabs by choosing options from the ribbon bar, so they don’t need a new feature on the tab control.
That is all there is to setting up the Dynamic Tab control, of course the next thing I need is some internal windows. Fortunately for me, I already have internal windows in the NextAge demo app, so that is already done. In fact the reason I have internal windows is that I had created my own interface similar to dynamic tabs prior to the Dynamic Tab feature being adding in V20. I can say pcSoft’s implementation is much easier and nicer than the manual one I had created for myself! To see some of the differences you can look at the original MainMenu in the project.
Note: Some of the code you may see in the screen shots below are because I am overriding the existing template code of the button that were used with my original Browse Form Manager class. I will release an update of this app and the Browse Form Manager class that included new logic for using Dynamic Tabs instead of my original tabbed interface logic at some point. However at this point I spend most of my time working on WebDev projects, so I haven’t had a compelling (read billable) need to update the class yet.
Let’s look at the code behind the Customer button for our new main menu window.
It can’t get much easier than that can it? TabOpen is a new function that creates a new tab on a dynamic tab control. The first parameter is the Dynamic Tab control to work with. The second parameter is the caption for the new tab. I am using the Caption property of the button, so that the tab will have the same caption as the button. That way in the future if I rename the button, the resulting tab will reflect that. Just another nice little feature of the WX environment that makes me more productive and not face so many maintenance headaches down the road. The last parameter is the name of the Internal Window to display on the Tab. In this case it is our Customer Browse.
I did need to create a different internal window for the customer browse than the original, since my original was using all of my “old” logic to open up the customer form as separate tabs. If you examine how I did that in the Browse Form Manager class, versus how I am able to do it using a dynamic tab you will see just how nice the new Dynamic Tab control is!
That is all there is to creating and using Dynamic Tabs. At this point our application is working. However there is one “feature” that I am not fond of. If the user clicks the Customer button multiple times it continues to open new tabs with the Customer Browse on them. This could get very confusing for the end user, and isn’t very efficient for the system either. We will address that later using a small class I created to manage the dynamic tabs.
But first lets look at opening up an edit form from the browse, as yet another dynamic tab.
The code behind my Change button looks like this
Although this may look a bit more complex, its really no different the first TabOpen we looked at. The first parameter is the Dynamic Tab we want to work with, the only difference is since we are on coding inside an Internal window now, we don’t have the control name immediately available to us via Intellisense without first prefixing it with the window name (WinMainDynamicTabs).
The next parameter is again the caption of the tab, since we can have multiple forms open, I want the caption to make it clear which customer the form is for, so I am adding the company name to the caption.
The third parameter is the Internal window to display, in this case our form. The next two parameters are parameters that are passed to that from, if we look at the definition of IFRM_Customer we see it is defined to take two parameters, the ID of the record and a instance of the BrowseFormManager Class.
If we look at the save button of the form we can see this code
All of the lines except for 7 have to do with how the record is saved using the BrowseFormManager Class. Line 7 using the new TabClose function to close a tab of a dynamic tab control.
Although the help shows that you can call this function with just the first parameter, the tab control, and it will close the current tab, I get a compile error if I don’t include both parameters.
So I am including the second parameter which is the value of the tab control, which happens to be the alias of the current tab, which is what the second parameter of the TabClose function wants.
Note we are really starting to see why I created a small management class for managing dynamic tabs. Without some additional logic, If I click the change button twice for the same record I would have the form open twice as two separate tabs, which would definitely not be what I want! Again we will address that shortly via the Class.
There is one other item that we need to discuss before moving on to the Class. That is the Independent HFSQL Context option. Since we have have the same window open multiple times inside different tabs we want each internal window to have its own context for the File buffers etc. Otherwise opening a second customer record up would change the buffer that would be updated if you then went back and updated the first opened form. So be sure to turn that feature on.
So now that you know the basics behind dynamic tabs you could head out and start incorporating them into your application. However I had a few things that I wanted my interface to do that were not standard with dynamic tabs. First if you click the Customer button a second time from the main ribbon bar, I don’t want to open a new tab, I want to bring the tab that already has the Customer browse into focus instead. Second and more importantly, although I do want to open up multiple forms as dynamic tabs, I don’t want to open up two forms for the same record as that could cause some serious issues. So I created a simple class that keeps track of the tabs as I open and close them, lets take a look at it now.
The structure of the class is pretty simple we have a structured array, which shouldn’t surprise you at all. What can I say I love ’em!!! The array tracks 3 pieces of information, The Name of the internal window, the alias, and the caption to display on the tab.
We need a single global instance of the class, so we declare it in the project.
The on the window where the tab is declared, we need to let the class know which control is the dynamic tab (what is it managing). The other line has to do with some special stuff I do with the About tab.
So then to open the tabs, we just make a call to the class instead of using the TabOpen Function. This has 3 parameters, the internal window name, a sub name that we will discuss shortly, and the caption of the tab.
If we look at the code behind that method, it may look complicated but really all it is doing is determining if the window is already open on a tab, and if it its it sets focus to that tab, instead of opening another tab.
One really advanced feature here is the * as a parameter, that lets this method accept any number of additional parameters, and then you can see in line 17 how I pass those parameters on to the window we are opening.
Uncle Pete’s Corner is webinar series on all things WX, to watch the watch the Uncle Pete’s corner webinar that is the companion to this article, and many other WX related webinars go to the WinDev US YouTube Channel and be sure to also join the WxLive – US Communityon Google+ to get notices about upcoming webinars. On the Google+ community you will find a active group developers discussing all things WX.