Related Articles
Howard Dierking talks to the inventor of C++, Bjarne Stroustrup, about language zealots, the evolution of programming, and what’s in the future of programming. Howard Dierking MSDN Magazine April 2008 ... Read more!
Windows Imaging Component (WIC) is an extensible framework for encoding, decoding, and manipulating images. See how to use WIC to encode and decode different image formats. Kenny Kerr MSDN Magazine April 2008 ... Read more!
This month we explain how pseudo variables and format specifiers provide a wealth of information for use in debugging. Kenny Kerr MSDN Magazine December 2008 ... Read more!
Kenny Kerr sings the praises of the new Visual C++ 2008 Feature Pack, which brings modern conveniences to Visual C++. Kenny Kerr MSDN Magazine May 2008 ... Read more!
Michael Howard outlines some of the buffer overrun defenses available in Visual C++ 2005 and beyond. Michael Howard MSDN Magazine March 2008 ... Read more!
Also by this Author
Paul DiLascia MSDN Magazine November 2005 ... Read more!
This month Paul DiLascia teaches readers the right way to create dynamic dialogs, explains satellite DLLs and discusses language resource DLLs. Paul DiLascia MSDN Magazine September 2006 ... Read more!
Paul DiLascia MSDN Magazine May 2005 ... Read more!
Paul DiLascia MSDN Magazine January 2006 ... Read more!
What's the deal with const functions, and lots more on the reasoning behind the design of the C++/CLI. Paul DiLascia MSDN Magazine February 2007 ... Read more!
Popular Articles
This article introduces 10 development tools that can increase your productivity, give you a better understanding of .NET, and maybe even change the way that you develop applications. The tools covered include NUnit to write unit tests, Reflector to examine assemblies, FxCop to police your code, Regulator to build regular expressions, NDoc to create code documentation and five more. James Avery MSDN Magazine July 2004 ... Read more!
The MVP pattern helps you separate your logic and keep your UI layer free of clutter. This month learn how. Jean-Paul Boodhoo MSDN Magazine August 2006 ... Read more!
Kenny Kerr sings the praises of the new Visual C++ 2008 Feature Pack, which brings modern conveniences to Visual C++. Kenny Kerr MSDN Magazine May 2008 ... Read more!
We introduce you to the benefits of building composite applications with the Composite Application Guidance for WPF from Microsoft patterns & practices. Glenn Block MSDN Magazine September 2008 ... Read more!
Now you can perform efficient, sophisticated text analysis using regular expressions in SQL Server 2005. David Banister MSDN Magazine February 2007 ... Read more!
|
This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
| .gif) | | Prevent Users from Performing Normal GUI Operations | | Paul DiLascia | Download the code for this article: CQA0102.exe (57KB) Browse the code for this article at Code Center: NoSize
| I'm working on a Visual C++® SDI project where I have two splitter windows (form views) within my main frame. Is there a way to keep the user from moving and resizing the frame window and child windows while maintaining a title bar in each? Ross Giumara I feel so sorry for users sometimes; programmers are always trying to protect users from themselves, preventing this or that normal GUI operation. It annoys me to no end when some program prevents me from sizing the window or using cut or paste or otherwise inflicts its bizarre behavior upon me. My first instinct is to move these apps to the Recycle Bin. But who am I to judge? Perhaps there are circumstances when it's wise to disallow moving and sizing. Maybe you're writing a nuclear control program for the President. Whatever. The simplest way to disallow sizing is to create a window without WS_THICKFRAME. How can the user size the window if there's no frame to grab it by? But if you turn WS_THICKFRAME off, you'll still get a window with a caption, which the user can grab to move the window. To disallow moving as well as sizing, you have to turn off WS_CAPTIONâ"but then your app has no title! Oops. You certainly want the President to know he's using the Nuclear Command Program, not the space wars game. How do you escape this perplexing dilemma? How can you have your caption and disallow moving, too? And what if you don't want a thin frame anyway? What if you want a fat frame with no sizing? In fact, you can have your cake and eat it, too. You can have a window with thick frames and a caption, and still disallow moving and sizing. The trick is to handle WM_NCHITTEST. Windows® sends this obscure message to find out specifically where the mouse is when it's in one of the nonclient screen areas. Nonclient areas areâ"as even the newest newbie could guessâ"any part of the window that's not part of the client area. This includes the menu, caption, and borders. Normally, you never have to mess with nonclient stuff, or even know it exists. But sometimesâ"now is goodâ"you have to roll up your sleeves and get into the gritties. When the user clicks the mouse in your app's caption bar, Windows sends WM_NCHITTEST. The default window procedure examines the mouse coordinates and returns one of the specialized hit-test codes listed in Figure 1. For example, if the mouse is in the caption, the default window proc returns HTCAPTION. If the mouse is in the left or right border, the default proc returns HTLEFT or HTRIGHT, respectively. These codes tell Windows to begin its moving or sizing chores. You can prevent moving and sizing by overriding ON_NCHITTEST. Instead of returning HTCAPTION or HTLEFT or HTRIGHT, you can return...what? At first you might try HTNOWHERE; but if you do you'll discover a problem: if another window overlaps your window and you click your window's caption bar, nothing happens. And I mean nothingâ"Windows doesn't even activate your app. Sigh. Well, how about HTTRANSPARENT? Same thing. Both HTTRANSPARENT and HTNOWHERE leave your frame in a state of existential ambiguity. The correct value to return is HTBORDER, the same value the default window proc returns when the user clicks on the border of a window without a thick (sizeable) frame. Pretty clever, eh? If you return HTBORDER, Windows activates your window without initiating any move/size operations. Naturally, I wrote a little app called NoSize to demonstrate how it works in real life. Figure 2 shows the CMainFrame class, which is where all the action is. The key function is CMainFrame::OnNcHitTest. It maps all the "bad" hit-test codes to HTBORDER.
UINT CMainFrame::OnNcHitTest(CPoint point)
{
// get vanilla code
UINT hit = CFrameWnd::OnNcHitTest(point);
// disallow these codes: map to HTBORDER
static char DisallowCodes[] = {
HTLEFT,HTRIGHT,HTTOP,...,
HTSIZE,HTCAPTION };
return strchr(DisallowCodes, hit)) ? HTBORDER: hit;
}
The actual version in Figure 2 contains useful TRACE diagnostics that will help you see what's going on. With the magic lines shown previously, users can't move or size your window.
.gif) Figure 3 Menu
Or can they? Do you really know how many ways there are to move or size a window? What about the min/max buttons in the caption bar? What about the Move and Size commands in the system menu (see Figure 3)? Don't tell me you forgot. It turns out imposing your sizing will is not so easy! Fortunately, the rest is straightforward. To turn off the min/max/restore buttons in the title bar, all you have to do is adjust the window style in PreCreateWindow.
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// no min/max buttons in caption!
cs.style &= ~(WS_MINIMIZEBOX|WS_MAXIMIZEBOX);
return CFrameWnd::PreCreateWindow(cs);
}
To remove the offending commands from the system menu, you need a few lines in CMainFrame::OnCreate:
static UINT BadCommands[] = {
SC_SIZE, SC_MOVE,
SC_MINIMIZE, SC_MAXIMIZE, SC_RESTORE, 0
};
CMenu *pSysMenu = GetSystemMenu(FALSE);
for (int i=0; BadCommands[i]; i++) {
pSysMenu->RemoveMenu(BadCommands[i], MF_BYCOMMAND);
}
Now the system menu looks like Figure 4.
.gif) Figure 4 New Menu
You might think that after all this, your app is pretty safe from any freethinking user who might attempt to move or size her window, but there's yet another loophole, yet another way users can size their windows. In Windows, there's always some twist somewhere. If you built your app using MFC, you probably have a status bar with size handlesâ"you know, those grippy little lines that make a triangle in the lower right corner of your window (see Figure 5). All the user has to do is drag those little babies to change the window size.
.gif) Figure 5 Status Bar with Size Handles
So how can you, with your totalitarian mindset, disallow this? Here's how:
// In CMainFrame::OnCreate
ModifyStyle(WS_THICKFRAME,0);
// no thick frame
m_wndStatusBar.Create(...);
ModifyStyle(0,WS_THICKFRAME);
// restore thick frame
Here you turn off the thick frame before you create the status bar, then turn it back on again afterwards. When you create your status bar, MFC looks at the window style to determine whether the status bar should get the size handles. I couldn't find any way to turn off the size handles once the status bar has been created, so the only thing left to do is fool MFC from the outset. Why not? Figure 6 shows the resultâ"a status bar with no size handles.
.gif) Figure 6 Status Bar without Size Handles
Whew! OnNcHitTest, min/max buttons, system menu, MFC status bar fakeout.� Now your window absolutely, positively can't be moved or sized. Just don't be surprised if customers call you to complain or delete your app from their computers!
I have an MFC app that uses a splitter window, but I don't want to let the user move the splitter. How can I prevent the user from moving the splitter bar? Fascist Programming Wizard Heyâ"What's with all these prevent-the-user questions? Are people getting snippy just because we've had some trouble electing a President? Well, the truth is I just knew after that last question and seeing Ross's app has splitter windows, that someone would ask me how to prevent sizing them, so I made up this question to save the stress on my Inbox.
.gif) Figure 7 Adjustable Splitter Bar
Fortunately, preventing the user from moving a splitter is easy. There are two things you must do. First, you have to prevent sizing with the mouse; second, you have to replace the sizing cursor (see Figure 7) with the normal arrow (see Figure 8). The whole thing can be done by overriding two functions:
// override: don't allow resize
void CMySplitterWnd::OnLButtonDown(UINT, CPoint)
{
return; // no passez-vous GO, no collectez-vous $200
}
// override: don't allow setting cursor
void CMySplitterWnd::OnMouseMove(UINT, CPoint)
{
return; // ditto
}
This is the kind of code I really like: code that does nothing. Normally, when you click the mouse on the splitter bar, the splitter goes into its drag shtickâ"as evidenced by the following lines from MFC:
// (in WinSplit.cpp)
void CSplitterWnd::OnLButtonDown(UINT, CPoint pt)
{
if (m_bTracking)
return;
StartTracking(HitTest(pt));
}
To prevent tracking, all you have to do is override OnLButtonDown to do nothing. Similarly, when the user moves the mouse over the splitter bar, CSplitterWnd::OnMouseMove sets the cursor to the one that looks like a capacitor in a circuit diagram (see Figure 7); to prevent this, just short-circuit the capacitor (forgive me, I couldn't resist) by overriding and returning.
.gif) Figure 8 No Sizing Allowed
There's a third function that lets users adjust the splitter bar: CSplitterWnd::DoKeyboardSplit. This function is provided to implement the Window | Split command, which lets users adjust the splitter using the keyboard. There shouldn't be any need to override DoKeyboardSplit, however, since you're the one writing the app. If you don't want users to move the splitter, don't put a Window | Split command in your menu!
| Paul DiLascia is the author of Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992) and a freelance consultant and writer-at-large. He can be reached at askpd@pobox.com or http://www.dilascia.com. | From the February 2001 issue of MSDN Magazine
|
|