|
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)
|
|
|
|
|
Please let us all know where on SourceForge we can find the new project... Thinking about adding resizing to my App, based on a skinnable dialog...
|
|
|
|
|
As far as I know the skin-able version has not been published yet, but you should ask its author, not me.
As for my templated version, it's on SourceForge in the same repository of all my "Resizable" articles (see ResizableLib). The CVS branch is TEMPLATIZE , but it's not complete yet.
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)
|
|
|
|
|
I know I'm too late, and Don, you'll not be interested in this, but I had similar needs recently. Here is how I did that (it may help someone else).
1. Remove WS_THICKFRAME style from CResizableDialog::OnCreate (line 82 in ResizableDaialog.cpp)
2. Set ShowSizeGrip( FALSE );, you may prefer to do that in the end of CResizableDialog::OnCreate
3. Handle NCHITTEST as following.
LRESULT CResizableDialog::OnNcHitTest(CPoint point)
{
UINT ret = CDialog::OnNcHitTest(point);
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
if ( rect.right - 10 < point.x && rect.bottom - 10 < point.y )
{
return HTBOTTOMRIGHT;
}
else if ( rect.right - 10 < point.x )
{
return HTRIGHT;
}
else if ( rect.left + 10 > point.x )
{
return HTLEFT;
}
else if ( rect.top + 10 > point.y )
{
return HTTOP;
}
else if ( rect.bottom - 10 < point.y )
{
return HTBOTTOM;
}
else if ( ret == HTCLIENT )
{
return HTCAPTION;
}
return ret;
}
Thats it, now inherit your class with CResizableDialog, and you don't need the boarders or thick frames to resize.
HTH,
Regards,
Ejaz.
|
|
|
|
|
I installed the latest sdk from ms. It was necessary to
add the lib and include directories to the project setup as extra directories in the project setup to get Visual Studio to know they are there. I was able to get past the undeclared identifier error by including this
#if !defined (WC_STATIC)
#define WC_STATIC TEXT("Static")
#endif
#if !defined (WC_LISTBOX)
#define WC_LISTBOX TEXT("ListBox")
#endif
#if !defined (WC_BUTTON)
#define WC_BUTTON TEXT("Button")
#endif
If I did not include the #defines, I still got the undeclared identifier error. If I include them without the #if, then I got a duplicate definition error.
Now I am getting
msvcrtd.lib(MSVCRTD.dll) : error LNK2005: __setmbcp already defined in libcmtd.lib(mbctype.obj)
LINK : warning LNK4098: defaultlib "mfc42d.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
LINK : warning LNK4098: defaultlib "mfcs42d.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
LINK : warning LNK4098: defaultlib "msvcrtd.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
Debug/WSP.exe : fatal error LNK1169: one or more multiply defined symbols found
I have been through all the other messages and do not see where anybody else is having this problem.
Suggestions?
Thanks for your continued interest in this work.
Gleason
|
|
|
|
|
Gleason wrote:
If I did not include the #defines, I still got the undeclared identifier error. If I include them without the #if, then I got a duplicate definition error.
Well, that's weird. Maybe you just needed a Rebuild All, to recompile the precompiled header (included everywhere). If you have the latest SDK you shouldn't need the #defines. Try to look for them in the SDK headers (winuser.h)
Anyway I was thinking about adding something like that in stdafx.h, so people that don't have the latest headers can still compile the lib.
Gleason wrote:
LINK : warning LNK4098: defaultlib "mfc42d.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
LINK : warning LNK4098: defaultlib "mfcs42d.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
LINK : warning LNK4098: defaultlib "msvcrtd.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
This probably means that you're using the wrong combination of runtime libs in your project and the library. I set up 4 build configurations (Debug, Debug Static, Release, Release Static) in ResizableLib. I know that if you have the same configurations in your project it should link without propblems. Or if you have VC++ 7 you can associate the configurations that you want built together.
Jsut check your project settings in the General tab (which MFC lib to use) and the C/C++ tab (code generation, runtime lib). They should match the settings in the associated configuration in ResizableLib. In VC++ 6 that means the configurations having the same name, as far as I know.
Gleason wrote:
Thanks for your continued interest in this work.
Yes, I'm still interested in this project. Especially if I can successfully make a port for WTL/MFC/SDK. There is still something to learn from this. And I hate bugs, so whenever people find one I have to fix it. I just hope I had more time for this.
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)
|
|
|
|
|
>Well, that's weird. Maybe you just needed a Rebuild All,
Yes, I have learned that trick. No good this time.
>LINK : warning LNK4098: defaultlib "mfc42d.lib" conflicts with use of other >libs; use /NODEFAULTLIB:library
>LINK : warning LNK4098: defaultlib "mfcs42d.lib" conflicts with use of other >libs; use /NODEFAULTLIB:library
>LINK : warning LNK4098: defaultlib "msvcrtd.lib" conflicts with use of other >libs; use /NODEFAULTLIB:library
This probably means that you're using the wrong combination of runtime libs in your project and the library.
Win32Debug for both.
I am using Visual Studio V6, sp 5.
I took your hint and made sure that the project settings in both projects are the same. I put the _AFXDLL_ tag in my project and put the additional include directory for the sdk in yours. That made it so I no longer need the #defindes. And the error is gone. Now I am just getting one warning:
LINK : warning LNK4098: defaultlib "MSVCRT" conflicts with use of other libs; use /NODEFAULTLIB:library
Since it is a warning, the code will compile. It runs too. I am not sure if I can ignore this warning or not, but for the present, it looks like maybe I can.
Thanks for your help.
Gleason
|
|
|
|
|
Well, this is my setup: the latest SDK should have a script you have to run to add the SDK directories to VC++ options. That's the way it should be, unless you wanted it another way, maybe for legacy projects.
Anyway, if you use the VC++ options you don't need to add the directories to the project settings.
Gleason wrote:
LINK : warning LNK4098: defaultlib "MSVCRT" conflicts with use of other libs; use /NODEFAULTLIB:library
This is different from before. Now it's looking for the non-debug version of runtime libs, so you must have a different setting somewhere. It was MSVCRTD before, now it's MSVCRT (relase version).
Gleason wrote:
Since it is a warning, the code will compile. It runs too. I am not sure if I can ignore this warning or not, but for the present, it looks like maybe I can.
I don't know how the linker resolves the ambiguity, maybe it just takes the first lib encountered. I would try to fix that though, even if it builds and run correclty. It's a possible source of very nasty bugs, hard to find because you'll probably forget about this warning and look for the cause somewhere else.
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)
|
|
|
|
|
>Well, this is my setup: the latest SDK should have a script >you have to run to add the SDK directories to VC++ options.
The MS website based sdk installer has an option to configure the environment. It added sdk directories to the path and added a few environment variables.
>I don't know how the linker resolves the ambiguity, maybe >it just takes the first lib encountered.
This linker message removes the warning:
/NODEFAULTLIB:msvcrt.lib
So now it compiles without warning.
I see that if I try to use a non microsoft activex, I get
an assertion error at line 44 of resizeablelayout.cpp.
// child window must be valid
This happens with the addanchor function.
It compiles and runs fine if I use an old microsoft legacy
idc_button. The button is not visible if I run the add anchor function on it. I suspect a little tweeking will take care of that, but I need to be able to use this for newer non microsoft components. Can I do that?
Gleason
|
|
|
|
|
Gleason wrote:
This linker message removes the warning:
/NODEFAULTLIB:msvcrt.lib
Ok, let's be specific. I have Platform SDK February 2003 in my Start menu, and under Visual Studio Registration you can find the scrip I was referring to (Register PSDK with Visual Studio), that automatically adds the necessary directory to your VC++ options (menu Tools > Options > Directories in VC6). With the SDK directories in the global options you don't need to add them to every project. I find this very convenient, unless you have reasons to do otherwise.
Gleason wrote:
The MS website based sdk installer has an option to configure the environment. It added sdk directories to the path and added a few environment variables.
Well, I usually prefer to check that every library reference is correct instead of forcing the linker to use something it didn't expect. Anyway, that's your choice.
Gleason wrote:
an assertion error at line 44 of resizeablelayout.cpp.
// child window must be valid
This happens with the addanchor function.
Use the AddAnchor overload that accepts a HWND instead of a control ID. For most, if not all, ActiveX controls the GetDlgItem() function, that I call in the overloaded AddAnchor, returns NULL. Just use the associated member variable instead of its ID.
Hope this helps,
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)
|
|
|
|
|
my Start menu, and under Visual Studio Registration you can find the scrip I was referring to (Register PSDK with Visual Studio), that automatically adds the necessary directory to your VC++ options (menu Tools > Options > Directories in VC6).
Yes, I saw the option in the start menu. I did try to use it several times. I did not know about the tool>options location, but I see that the registration function did not add the sdk directories to the list. I can do that manually.
>Just use the associated member variable instead of its ID.
The member variable gets the same assertion error.
Gleason
|
|
|
|
|