|
Sorry about the delayed response; I had taken steps to avoid that problem (making window position remembering an option, defaulting to off), and didn't have a chance to find out a non-working registry key until now. Here's what the contents are of it:
-32000,-32000,-31287,-31475,1,0
I looked at all the source and header files of the ResizableLib code I'm using and couldn't find any version numbers; I was using the latest stable version (at least within a few weeks) at the time of my last post.
|
|
|
|
|
Could it be a problem with multi-monitor systems only? If you attach a secondary monitor, move the window on it, close the application, remove the monitor and then open the app again, it may happen that your window looks like minimized, but it's actually out of the visible part of the screen.
Someone reported this issue and that it doesn't happen with bRectOnly=FALSE.
If you could confirm this I could think about a fix for the next (upcoming) version.
Otherwise it may be another bug. The fifth field in the registry key you reported should be 2 for SW_SHOWMINIMIZED. It may be that I'm saving the wrong position with bRectOnly=TRUE.
Thanks,
Paolo
------ Temporary patch ------
BOOL CResizableState::SaveWindowRect(LPCTSTR pszSection, BOOL bRectOnly)
{
CString data;
WINDOWPLACEMENT wp;
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
wp.length = sizeof(WINDOWPLACEMENT);
if (!GetResizableWnd()->GetWindowPlacement(&wp))
return FALSE;
RECT& rc = wp.rcNormalPosition;
if (bRectOnly)
{
data.Format(PLACEMENT_FMT, rc.left, rc.top,
rc.right, rc.bottom, SW_SHOWNORMAL, 0);
}
else
{
data.Format(PLACEMENT_FMT, rc.left, rc.top,
rc.right, rc.bottom, wp.showCmd, wp.flags);
}
return AfxGetApp()->WriteProfileString(pszSection, PLACEMENT_ENT, data);
}
BOOL CResizableState::LoadWindowRect(LPCTSTR pszSection, BOOL bRectOnly)
{
CString data;
WINDOWPLACEMENT wp;
data = AfxGetApp()->GetProfileString(pszSection, PLACEMENT_ENT);
if (data.IsEmpty())
return FALSE;
ZeroMemory(&wp, sizeof(WINDOWPLACEMENT));
wp.length = sizeof(WINDOWPLACEMENT);
if (!GetResizableWnd()->GetWindowPlacement(&wp))
return FALSE;
RECT& rc = wp.rcNormalPosition;
if (_stscanf(data, PLACEMENT_FMT, &rc.left, &rc.top,
&rc.right, &rc.bottom, &wp.showCmd, &wp.flags) == 6)
{
if (bRectOnly)
{
wp.showCmd = SW_SHOWNORMAL;
wp.flags = 0;
return GetResizableWnd()->SetWindowPlacement(&wp);
}
else
{
return GetResizableWnd()->SetWindowPlacement(&wp);
}
}
return FALSE;
}
It was actually a bug in the Load/SaveWindowRect functions. This is the fix, that will be included in the next version.
Paolo
|
|
|
|
|
I was just thinking to myself yesterday while I kicked and screamed at trying to get my stinking controls to stretch and grow the way I need them to that I really miss this class! MFC was my bread and butter for years and there are times when I really miss it. This class, to this day, remains the most heavily used piece of shared code I've ever downloaded.
Nowadays I'm 99.9% .NET (a pretty even mix of VB.NET and C#) with a little bit of old ATL COM still thrown into the mix on occasion and I'd give ANYTHING to have this project converted into a proper layout manager for Winforms for use in VB.NET and C#. The new features in Winforms for Docking and Anchoring are really great and do the job more often than not with very little effort... but there are so many times when they fall way short and I never came across a scenario with CResizableDialog that would not allow me to lay out my controls in the manner I frequently need to (more than 1 or 2 controls on a "line").
At any rate, if you do ever make the switch, PLEASE consider writing this for .NET.
|
|
|
|
|
Matt Philmon wrote:
This class, to this day, remains the most heavily used piece of shared code I've ever downloaded.
Well, that's great. And thank you very much for showing your appreciation.
Matt Philmon wrote:
At any rate, if you do ever make the switch, PLEASE consider writing this for .NET.
Well, I must say that I still prefer the old VC++ 6.0 to the new .NET version and I'm not ready for the "switch" yet. What's more, the next version of this class library will be based on templates and I don't know to what extent I could use them on the .NET platform, if not at all. But, since MFC compatibility will be achieved with some adapter classes (and some specific for MFC) I suppose that there could be a way to build some .NET components with C++. Anyway, right now I wouldn't even know where to start.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Paolo
Very useful implementation. However, I had the need to use an ActiveX Control (Component One's FlexGrid) in the dialog which caused an ASSERT failure when AddAnchor is called. Tested this with VideoSoft's Flexgrid with a similar result.
Is this known issue?
Thanks,
Alex
|
|
|
|
|
Please review the older posts about ActiveX controls, both in this and the ResizableLib article.
Basically, you need to pass a HWND to the ActiveX control in the AddAnchor call.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Thanks Paolo,
Found the solution as you indicated.
Much appreciated,
Alex
|
|
|
|
|
I've been using this for a while but I've found another class that I'd like to use for skinning the dialogs which also requires a find and replace of all the CDialog instances.
Is there a way to get them both working at the same time or a different way of doing it that might work?
If not, does anyone know how to get rid of the border if you set the dialog border property to resizable? If I'm using a transparent, or non-rectangular image for the dialog, I'd like to add a grip somewhere on the skin and hide the border.
Thanks,
Don
|
|
|
|
|
WolfSupernova wrote:
Is there a way to get them both working at the same time or a different way of doing it that might work?
Use CResizableDialog as a base class for the skin dialog class (replace it in the source files) and then use the latter for your dialog.
I'm aware of this kind of problems, and that's another reason for generalizing the library in the next version. (Not soon to come, unfortunately).
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Hmmm... I think I screwed up.
Here's what I did. The skin class in question is here if that helps. http://www.codeproject.com/dialog/cdialogsk.asp?target=cdialogsk
I included the library and replaced all instances of "CDialogSK" (previously CDialog) in my .h and .cpp files, with "CResizableDialog".
Then, I went through the CDialogSK.h and .cpp files and replaced all instances of "CDialog" with "CResizableDialog".
Was that right? After doing so, I got a gazillion compile errors, the first one starting with:
CDialogSK: illegal member initialization: 'CResizableDialog' is not a base or member.
Sorry for the trouble.
Thanks again,
Don
|
|
|
|
|
WolfSupernova wrote:
Then, I went through the CDialogSK.h and .cpp files and replaced all instances of "CDialog" with "CResizableDialog".
This is correct. Now CDialogSK inherits from CResizableDialog.
WolfSupernova wrote:
I included the library and replaced all instances of "CDialogSK" (previously CDialog) in my .h and .cpp files, with "CResizableDialog".
This is incorrect. CYourDialog should still inherit from CDialogSK, that now is also a "resizable" dialog.
Be sure to follow the steps in the article for CDialogSK, about how to make it a resizable dialog. Then you can use it as both a skin-able and resizable dialog.
If you still get compiler errors, quote the source code the error is referring to in your post.
HTH,
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Okay, cool. That worked. Now I just have one more little problem and I promise I'll leave you alone. Thanks for responding so quickly by the way.
Is there any way to get rid of the border? That's the same problem I had before just using the skin class by itself and changing the border to "resizing". By using your library, I was hoping there'd be no border and I'd see the size grip, but I got a border and no grip instead. And obviously I don't want a border around a transparent or non-rectangular skin.
Okay, two questions. Is there a way to change the image for the grip?
Thanks again,
Don
|
|
|
|
|
Oops. Maybe it's not working. I only have one button control on the dialog in the top right corner and it won't allow me to resize it any smaller, which indicated that it was working, but it's not moving on resize after I added the anchor.
AddAnchor(IDC_BUTTON_EXIT, TOP_RIGHT);
|
|
|
|
|
Be sure you replaced every occurence of CDialog with CResizableDialog, especially in the OnSize handler and the message map implementation.
Then you may want to modify the OnEraseBkgnd handler to enable clipping (for anti-flickering). You can use the old CResizableLayout::ClipChildren(CDC* pDC) function before starting drawing on the DC. This won't work with XP themes enabled.
Or you can get the latest code from CVS at SourceForge (main branch):
http://cvs.sourceforge.net/viewcvs.py/resizablelib/ResizableLib/[^]
(Ignore the ResizableCombo stuff and files you don't need - but check dependencies)
And then use the new code as follows:
BOOL CDialogSK::OnEraseBkgnd(CDC* pDC)
{
ClipChildren(pDC, FALSE);
ClipChildren(pDC, TRUE);
return TRUE;
}
It's important that you don't call the base class implementation in OnEraseBkgnd, or you'll have flickering.
And if you use a non-rectangular shape, don't forget to update the window region whenever the window is resized. This may be a cause of flickering, I'm not sure. You'll have to find a suitable message handler for that... maybe WM_NCCALCSIZE.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Thanks Paolo,
I figured out what was wrong with the anchoring. I had an ON_SIZE message handler for a WebBrowser control and when I took that out, the anchoring worked (kind of, it's a little slow moving into place), but now my WebBrowser control won't resize properly of course. I've always had to handle that one independently in the past. I've tried other resizing classes, but they don't play well with it either.
Anyway, I downloaded the latest files from sourceforge and did as you suggested. It doesn't appear to be flickering too bad but I still can't get rid of the border. I tried removing ModifyStyle(WS_THICKFRAME) but then it won't resize, so I'm right back to square one.
I was hoping there was a way to set the border width/hight to "0" or something but there doesn't seem to be a way to do that. If you or anyone else has a suggestion, I'd love to hear it!
Thanks again for your help,
Don
|
|
|
|
|
To eliminate the border the only option is removing the WS_THICKFRAME style, and maybe also WS_BORDER and WS_CAPTION.
And you're right, it won'r resize anymore after you do that, unless you implement the resizing feature yourself. Modify the CResizableGrip class and call ::PostMessage(hDlg, WM_SYSCOMMAND, SC_SIZE, 0) when the WM_LBUTTONDOWN is received. The place to do that is in the CSizingGrip::WindowProc() function. The hDlg argument is the dialog HWND , that you can get with GetParent() (obviously you can use the returned CWnd* directly).
That should enable the resizing, but I'm not sure.
If you want to change the grip icon you need to handle WM_PAINT as well, and draw whatever you like the most. Have a look at the transparent drawing routines, maybe you can just load your own bitmap instead of letting the control draw the grip, and nothing more. It should be easy.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Okay, I see where you're going with this. Unfortunately, there's already a WM_LBUTTONDOWN handler being used in the skin class, to let the user drag the dialog around the desktop when they click on a non-transparent part of the bitmap.
<br />
void CDialogSK::OnLButtonDown(UINT nFlags, CPoint point) <br />
{<br />
if (m_bEasyMove)<br />
PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y)); <br />
<br />
CResizableDialog::OnLButtonDown(nFlags, point);<br />
}<br />
I just posted a message in Abhinaba's article to see if he could join in on this conversation and provide a little insight. I think this dialog that we have going here(no pun intended) could be useful to others as well.
Don
|
|
|
|
|
WolfSupernova wrote:
Unfortunately, there's already a WM_LBUTTONDOWN handler being used in the skin class
I was talking about the grip class, that is CResizableGrip::CSizeGrip . You may add the code I was suggesting as an additional option, that you may add to the CreateSizeGrip() function.
This would not interfere with the WM_LBUTTONDOWN handler in the dialog class.
WolfSupernova wrote:
I think this dialog that we have going here(no pun intended) could be useful to others as well.
Yeah, definitely. You may call that CResizableDialogSK , or CResizableSkinDialog , or whatever you like.
But the enhancement to the grip class, I think I can add it to the next version of ResizableLib, just in case one would want to have a resizable window without a resizable border, or no border at all.
I may also release a version 1.4 of the library, with the latest fixes and these additions, while waiting for the more complex templated version (in another CVS branch). I wanted to do this but, as always, time is against us.
I may however make a quick release and warn about possible incompatibilities, bugs and unfinished features (even if I don't like to publish unfinished or intermediate work).
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Good point. This probably deserves it's own article! After we get this all hashed out, I'll put one together, time permitting, and giving you both full credit and links of course. In this case, maybe we should take this offline so we don't keep filling up your message board!
In terms of the WM_LBUTTONDOWN, I tried that but nothing happened because the grip (in this case) resides in the transparent part of the bitmap, so the event is caught and discarded before CResizableGrip::CSizeGrip has a chance to process it.
|
|
|
|
|
Hmmm. What I just said wasn't true. I took out his event handler and the CSizeGrip WM_LBUTTONDOWN is still not picking it up.
I added a message box just to see if it was doing anything and never saw it with the left-click. Then, I tried WM_RBUTTONDOWN, and still no luck. Here's where I put it.
case WM_DESTROY:
// perform clean up
if (m_bTransparent)
SetTransparency(FALSE);
break;
case WM_LBUTTONDOWN:
// Left Mouse Button
MessageBox("clicked",NULL,MB_OK);
::PostMessage(m_hWnd, WM_SYSCOMMAND, SC_SIZE, 0);
break;
case WM_PAINT:
|
|
|
|
|
WolfSupernova wrote:
Hmmm. What I just said wasn't true. I took out his event handler and the CSizeGrip WM_LBUTTONDOWN is still not picking it up.
Your code is correct, but I know why it doesn't work. My fix for the "focus problem" on the grip control includes returning DLGC_STATIC for WM_GETDLGCODE messages. Try removing that... I'll think about another fix if that works, or try experimenting with other return values.
It may also be the WM_SETFOCUS message, but the mouse messages should be posted to the control anyway, even if it refuses the focus.
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Hi Paolo,
I've tried this and a few other things and no luck, but I think I may be onto something. I've added a couple of buttons to my dialog with these functions.
void CSkinDialog_DemoDlg::OnBnClickedShowBorder()
{
CRect rect;
GetClientRect(&rect);
CResizableDialog::ModifyStyle(0,WS_THICKFRAME);
InvalidateRect(rect,TRUE);
SetWindowPos(this,-1,-1,rect.right+1,rect.bottom+1, SWP_NOMOVE|SWP_NOZORDER);
}
void CSkinDialog_DemoDlg::OnBnClickedHideBorder()
{
CRect rect;
GetClientRect(&rect);
CResizableDialog::ModifyStyle(WS_THICKFRAME,0);
InvalidateRect(rect,TRUE);
SetWindowPos(this,1,1,rect.right-1,rect.bottom-1, SWP_NOMOVE|SWP_NOZORDER);
}
This allows me to set it to resizable and show the border, and then set it back to not resizable and hide the border.
What I'm trying to do is make it a mouse-over event on the grip, so it's visible when the mouse is over the grip and dissapears when it's off, which should suffice although I haven't seen it in action yet. I think rather than the WM_LBUTTONDOWN, this could possibly be called from WM_NCHITTEST where you're setting the cursor type, but I'm having a little trouble with it. I don't get the same results calling it from CResizableGrip. Any ideas? Am I going down the wrong path?
Thanks again for all of your help.
Cheers,
Don
|
|
|
|
|
Ok, I got some time on the weekend to try this out.
First, if you want no border at all you have to give up the caption either:
ModifyStyle(DS_MODALFRAME|WS_BORDER|WS_CAPTION, 0);
ModifyStyleEx(WS_EX_DLGMODALFRAME, 0);
Then, I tried to enable resizing using the grip (the only one left):
case WM_LBUTTONDOWN:
GetParent()->PostMessage(WM_SYSCOMMAND, SC_SIZE);
break;
case WM_SETCURSOR:
SetCursor(AfxGetApp()->LoadStandardCursor(
IsRTL() ? IDC_SIZENESW : IDC_SIZENWSE));
return TRUE;
As you can see the problem was in the WM_NCHITTEST handler that, returning a non-client code, somehow prevented the window to get the mouse click message. Good to know...
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|
Perfect! I'm going to name my first three kids after you.
I KNEW it was GetParent(). I was just using it wrong.
Thanks a lot Paolo, sincerely. There's still a lot of work to do with this, as all of the skinning classes out there (the free ones) are pretty simple and only account for a background image, and don't take into account the resizing. I'd also like to incorporate the "snapping" effect as well.
So, since I'm going to have to do all this for my application anyway, I've decided not only to write an article on CP, but to start a skinning library project on sourceforge. If you can think of any ways of tailoring this for these purposes, other than what we've already tackled here, maybe some functionality that the skinning library won't need, or whatever, please let me know. I'd like to include your library in there with it. My email address is don.earnest@supernovasoft.com.
Thanks again!
Don
|
|
|
|
|
WolfSupernova wrote:
Perfect! I'm going to name my first three kids after you.
Ok, but vary the name a bit or you're not gonna be able to call them.
WolfSupernova wrote:
There's still a lot of work to do with this, as all of the skinning classes out there (the free ones) are pretty simple and only account for a background image, and don't take into account the resizing. I'd also like to incorporate the "snapping" effect as well.
You're right. They seem to think you would never want to resize a skin'ed window. The hard part would probably be the non-rectangular shape, but you may want to have a look at these GDI functions: BeginPath , EndPath , CloseFigure , PathToRegion , and of course SetWindowRgn .
Using those function you can create non-rectangular shapes, even with holes, just by using GDI drawing functions. It may also be possible, but I'm not sure, to use a metafile to create the path, and so the window region. Or you may create a 'script' file to issue drawing/path commands to render the region (something like SVG PATH elements). But maybe this is going too far...
WolfSupernova wrote:
I've decided not only to write an article on CP, but to start a skinning library project on sourceforge.
That's great. And of course I'd be happy to modify the classes in ResizableLib to accomodate any need by your skinning library. As I said in previous posts, I'm rewriting the library to use templates, and that would definitely help you in the process, but although I have the CResizableDialog class transformed and working, the rest of the classes are not ready yet, and I won't have much time for that now, 'cause I'm also writing my thesis.
So I don't know what would be the best strategy now. It also depends on your timing: if you need this in short time, you can just use the old style library, that I'm wishing to maintain anyway (mostly bug-fixes, no new features), and have your project done.
Then, when I'll have more time, I could finish the template version and you could just port your code to the new version of the library. It shouldn't be much work initially, 'cause I'm keeping backward compatibility using some adapter classes.
If you want to switch the conversation to email, my address is in the source code. I just though it would be interesting for other people to know, but now it looks like we've come to the end.
No, wait... to a new beginnning!
Cheers,
Paolo
------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
|
|
|
|
|