|
||||||||||||||||||
|
||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionWho is this article for? Generally it is for intermediate level coders familiar with C++/CLI in Visual Studio C++ 2008. To get the most out of this article, intermediate level here means you will find it more suitable if you:
At the very least, if you just want to use the sample code in another project, you should be able to follow the typical process of including a new class (object) in a project, instantiating an instance of an object and using it (it’s outlined in the summary of this article). Ok…now on with the Show! My main aim was to use rollup controls in a Windows Forms based application. A secondary interest was to ‘see how far we have come’ in our progression towards programming nirvana (What?); that is, to see how much more easy it would be to write a .NET based version of a rollup control, or more strictly speaking, using C++ with the Common Language Infrastructure (CLI). So this article presents an example of how I implemented a C++/CLI version of a Rollup Control. There are two rollup controls in the sample provided; one is standard (i.e. with instantaneous rollup/rolldown) and one contains animated rollups (i.e. slower, smoother rolling up/down) with rollup speed control. The download source was created using Visual C++ 2008 Express Edition (and messed around with a bit in the professional edtion) For those of you that want to get straight to using the control without wading through this article, you can download the zipped solution and go to the summary section near the bottom of the page for the bare essential instructions on how to include the Rollup Control in your own application. This also applies if you have a short attention span and start getting bored reading the article. BackgroundRollup controls are also known as rollout controls. Roll-up or roll-in and roll-down or roll-out: These terms are interchangeable in this article. Rollup controls have a little history at CodeProject. There are two other older articles I know of that deal with rollups; one uses MFC, while the other uses WTL. So this is a third article on rollups, this time using C++/CLI Windows Forms. For those not familiar with rollup controls or sophisticated programs like 3dsMax, a rollup control is a useful tool for providing additional functionality to the users of your program in a very compact presentation, freeing up the screen space from a possible sea of toolbars, toolpads and “floaters” as the complexity of your application increases. A rollup control has two main features:
These two features make it possible to present functionality that could otherwise take up much more screen space than you would like to permit. Using the CodeHere is an overview of the steps we take to put a rollup control into an application:
You can place the control in a Form or in any suitable control. In the sample project one rollup control is added to the form, while the other one is placed in a tab control. Now let’s take a look at the details of this rollup control. Panels, Panels and more Panels!You guessed it…, the rollup control is
Example Use: The code snippet below will create a rollup control that contains one expandable/collapsible page of type
For a more comprehensive example, see the #include "RollupCtrl.h"
#include "RollupPageDialog.h" // include the header file of the dialog panel we
// created in the Designer
...
private: RollupCtrl^ rollupCtrl2;
...
this->rollupCtrl2 = gcnew RollupCtrl();
//
// rollupCtrl2 on Tab page
//
this->rollupCtrl2->Location = System::Drawing::Point(10, 10);
this->rollupCtrl2->Text = L"rollupCtrl2";
this->rollupCtrl2->Size = rollupCtrlSize;
this->rollupCtrl2->TabIndex = 2;
...
...
/// The DialogPanel RollupPageDialog (derived from DialogPanel) is created
/// in the Designer before the next line can happen
RollupPageDialog^ rollupPageSample = gcnew RollupPageDialog();
rollupPageSample->Text = L"rollupPageSample";
rollupPageSample->Name = L"rollupPageSample";
//give the page a reference to this form
rollupPageSample->ClientForm = this;
this->rollupCtrl2->CreatePage(rollupPageSample);
//
// rollupCtrl2 Added to Tab Page
//
this->tabPage1->Controls->Add(this->rollupCtrl2);
// Animated Rollup Page Properties.
// Set Page Rollup Speed: the bigger the number the faster the rollup speed
// Note: some values may not roll up neatly. There are no limits! So try a value
// of 200 or more at your peril?!
//
this->rollupCtrl2->RollupSpeed = 2;
//
// also you can rollup/down faster when user selects "Close All" or "Open All" from the
// context menu. The default value for this is value of the RollupSpeed property
//
this->rollupCtrl2->RollupSpeedAll = 100;
//
// turn on animated rolling
//
this->rollupCtrl2->AnimatedRoll = true;
this->rollupCtrl2->ResumeLayout(false);
All we have to do now to actually see something in the control is to create and add the How to Create the Contents of a Rollup Page in the DesignerThere are a number of ways to create your rollup page contents. Here is the one provided in the sample solution: To design a rollup page in Visual C++ 2008 Express Edition, do the following:
Now, when you view the That concludes the basic information about the rollup control. The next section contains information about some extraneous issues that arose during the creation of the rollup control that may be of interest. Points of InterestThe instructions for using the rollup control that has just been described are simple compared to the issues that arose during its development. Some of those are described below, as well as some other points of interest. Rollup Page Content Creation AlternativesThe use of the
Some Visual Surface Options
Hopefully the main point to take away from these options is that it is easy to modify the supplied demo source in a way that best suits you. Some Model Interface OptionsFirst, let’s just take a brief look at what the //give the page a reference to this form
rollupPageSample->ClientForm = this;
In the demo code there is only one method our rollup page(s) are interested in: void UpdateInfo(String^ msg1, String^ msg2)
It’s a (bad?) generic name for a function, but it is for a generic example (so stands as such). I would expect you to be more meaningful with your method name choices. If the Other options:
If I had to declare my approach to design patterns in general, such as MVC/MVP/MVA mentioned above, it would be best described as egalitarian. Egalitarian?: for example, design patterns like MVC are great tools because they provide solutions to problems that are so generic to software design that a general pattern really does articulate related development issues very sussinctly (maybe this sentence could have been more sussinct!). A design pattern should be used for what it is, a generic tool. It is a generic tool to be applied to your specific design needs as you see fit. So, when I see the mention of the misuse and abuse of design patterns, I cannot help thinking such discussions have a lot more to do with the personal needs of the discussion participants than with the actual design pattern topic. This phenomenon is even more evident if you observe the group dynamics at play when you are part of a team of developers. ContextMenuRight click in the ScrollbarThe RollupCtrl scrollbar used is the default one that windows provides, and not the smaller, tighter, ‘better’, owner painted ones I normally seen in rollup controls. Maybe it should be changed? But I’m not going to change it. Mouse Cursors with .NETHow well does the .NET framework support custom Mouse Cursors? It handles them very poorly apparently according to this old link (circa 2005). There seems to be a few suggested solutions, most of them don’t seem to work in the general case, except maybe for the last suggestion in the link. I went with the simplest solution and hung it out in a folder somewhere to be loaded at run time each time it’s needed. For example, the code below shows that when the mouse enters the viewing area it changes to the Pan.Cur (picture of a hand) cursor to indicate scrolling by dragging is ‘active’. Note that it seems as if thePan.Cur file is loaded in each instance! This certainly isn’t an ideal situation. void RollupCtrlPage::RollupCtrlPage_MouseEnter(Object^ sender, System::EventArgs^ /*e*/)
{
if(bHasFocus == false)
bHasFocus = ((RollupCtrl^)(this->Parent))->ContainsMouse();
if(bHasFocus)
{
this->Cursor = gcnew System::Windows::Forms::Cursor("Pan.Cur");
this->Focus();
}
}
Even though this doesn’t seem to cause any degradation in the performance of the application today, it might one day. So if anyone has any information that is more up-to-date, or that you think we can benefit from, that is about handling custom cursors more efficiently, lets us know (or if I get around to finding and using a better method myself I’ll give you an update). Smooth Flicker Free Animated Rollup of Pages (Eliminating a Minor Irritation that causes Big Problems)One of the lasting impressions pre .NET MFC has left with me is that its behaviour can be temperamental, idiosyncratic and even downright eccentric. .NET and Forms Controls also has its fair share of idiosyncrasies, but to a lesser degree than MFC (or so it seems so far). This eccentric or unexpected behaviour can quickly arise when you start creating elements or features that step out the boundaries of stock standard, ordinary use of controls. For beginners, this eccentric or unexpected behaviour is also usually a sign that it is time to join the ranks of intermediate level programmers: Perhaps leading to painting your own controls, or at the very least, to finding other API calls that will provide you with greater control over your programs behaviour in order to achieve your goal. Enter the flickering control problem. Flickering controls seems to be a hot topic in some circles, probably because it is usually one of the first unexpected behaviours that arises when beginners attempt the unordinary. And its biggest impact is its unerring ability to make the best application look and feel amateurish. If you do enough research into the subject you will discover the major cause of flickering is drawing over the same pixel twice. And the solution is just as simple: just make sure you do not draw over the same pixel twice. So, the problem and the solution seem well defined. However, the method used to solve the problem is not so well defined. The good thing about this is that you are free to use any method you like to eliminate flickering. But this freedom calls for wisdom. Without a wise choice you could end up writing a lot more code unnecessarily: There are a number of very well known strategies ranging from double buffering with simple one line flag/property settings to more complex GDI+ off screen device context use, plus managing all the rectangles, clipping and painting ourselves. Some strategies can be used at the .NET level, while others require access to the underlying Win32 API. As you may have guessed by now, my first attempt at implementing something as unordinary as smoothly animated rollup pages produced some flickering at times (surprise,surprise…not). So here’s a brief of how flickering was eliminated: But firstly, I am a lazy programmer: I avoid writing monotonous, repetitive and redundant code. Secondly, I’m pretty dumb too: I don’t even pretend to know anything (ok…that’s not true, I do pretend sometimes); I am always searching for better ways of doing things. So, it is with this attitude that I attempted to eliminate flickering from the rollup control. The last thing I wanted to do was write mountains of redundant painting code or mashal some Win32 into my application just to remove the flickering. I tried the usual suspects like double buffering properties and flags, all to no avail. So, I just thought I would try something different before getting serious with painting the controls myself. I know that I am drawing over the same pixel twice during the rollup animation, but where? And if I slowed down the animation enough I could actually see the two different positions the controls were being drawn at. So I went looking for any code that were likely to update the position of controls more than once in the same method. Here it is, in RollupCtrlPage.cpp: /// Moves the page relative to the Rollup Control
/// Called on all pages at a time to simulate scrolling
/// of the canvas panel
///
void Scroll(int yDelta)
{
this->Location = System::Drawing::Point(0, y-yDelta);
Update();
}
///
/// recalculate the absolute position of the page on the canvas panel
///
void ReCalcLayout(int yAdjustment)
{
y += yAdjustment;
this->Location = System::Drawing::Point(0, y); //this line is omitted to remove
//flickering!
}
These were the only methods that modified the page location (apart of initialization code) and they are ultimately called in the this->Location = System::Drawing::Point(0, y);
from Is this a better way to eliminate flickering, than doing all the painting ourselves? That’s up to you. I consider myself lucky (at being lazy) to eliminate the flickering without going a little deeper and painting controls myself, as any serious programmer would attest I should have done(I am hoping it doesn’t flicker when you run the sample, because I’ll deserve all the criticism I get for not painting controls myself: full of confidence aren’t I ). So, as a warning: ‘don’t try this at home kiddies’, it’s a good example of bad programming practice. Do the right thing: Paint your own controls when you start doing things out of the ordinary like animated rollups (and if you want to avoid the scorn of the ‘serious programmer’). UserControl Inheritance and /clr AnomalyUsing managed and unmanaged code in your project (with the /clr property selected) can be problematic if you inherit from “This is an expected behavior given a known CLR limitation. The same problem happens for user controls and inherited forms. The workaround is to compile the mixed-mode code as a DLL not as an EXE.” WenYuan Wang [MSFT] - 18 Jun 2007 04:35 GMT, Microsoft Online Community Support at this link. So if you do your research it’s not an anomaly, but expected behaviour. There are two other workarounds I have used:
So, there are 3 options there to choose from as a solution to workaround the behaviour produced by the User Control inheritance and /clr anomaly. You will find other points of interest as comments in the example source code. Many of the comments are targetted directly towards the readers of this article and thus, would not normally exist. So, I hope the comments are more of a help than a hindrance. SummaryI wish every article had this section; the summary; for the times you’re in the mood for just the basic info; skip the article, and get the code up and running ASAP. Here is an overview of the steps we take to put a rollup control into our application:
You can place the rollup control in a Form or in any other suitable control. In the sample project one rollup control is added to the form, while the other one is placed in a tab control. To review some example code, scroll up to the first code block in the article (containing an example of steps 2,4,5 and 6) or for a more comprehensive example see the And Finally…Finally, you may recall my secondary interest in the article was to find out how much more easily a rollup control would be to implement in C++/CLI compared to older technology, such as pre NET MFC (i.e. recall the: ‘see how far we have come’ in our progression towards programming nirvana). Well, without counting the lines, there seemed to be a lot less code to write (which is not always a good thing, for example, people that aim to impress by deliberately writing terse and cryptic code can be needlessly difficult to work with). And if we ignore the bulk of the standard initialization code (auto-generated and hand written) there definitely is a lot less code to write. A lot less code implies it should be faster to implement, and the less code you write, the less chance there is of producing errors (That’s how our programming theory works, right?). But the main plus is that the code we need to write is easy to understand (this is very important for maintenance, and hopefully beneficial to article reading coders like you and me to read). So, needless to say, I am suitably impressed. PS. A Few Words about Smoothly Animated ControlsDuring the course of developing the rollup control, the continual testing and use of the smoothly animated pages had a suprisingly profound effect on me (it’s pretty sad when a UI control can have that effect on a person!). They just ‘feel’ so much better to use than the standard instantaneous rollup control. If you try out the sample, at times you might notice a slight jittering or rumbling/wavering effect in an animated page as its rolling up (it only seems to be evident when closing a page and the scrollbar button is located at the bottom i.e. maximum value, of the scrollbar control). I even liked that enough to leave it [as a feature!?](Of course, you can try eliminating it if you don’t like it). I hope you get as much enjoyment out of using the rollup control as I did in making it. I cannot remember if I actually have ever seen or used smoothly animated type controls like this outside of a video game (so, if you know of any windows apps that do have them, let us know). It’s going to be difficult for me not to use these animated type controls in the future. Then again, I suspect it might just be a novelty that will eventually wear off.
|
|||||||||||||||||