|
I assume you use MFC here.
There, the PreCreateWindow is a virtual member function of CWnd. This having said, in order to overwrite it succesfully you need to derive a class from CWnd or one of it's derivates (view/control).
Then you would, in your main program's InitInstance, create a 'new' object of your type using:
CMyDerivedCWnd* pWindow = new CMyDerivedCWnd;
When you would create the window object by calling "pWindow->Create(...)", the PreCreateWindow WILL get called by the framework.
Perhaps you have not derived from CWnd ? Perhaps you haven't overwritten your derived class's PreCreateWindow, but you just added some PreCreateWindow -function to your code ? In that case, check your function declaration. The framework will call THE PreCreateWindow of your DERIVED CLASS, and NOTHING else
Greets,
Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Thankx. I guess I misunderstood PreCreateWindow; I wanted to gain control before the window of my own main dialog will be constructed.
Btw, do you know
a) how to change font attributes IN an EXISTING CFont?
b) if I change the font size in OnSetFont, will that influence the size of the window and all controls?
because this is just what I wanted to achieve in PreCreateWindow.
|
|
|
|
|
Like I said, the PreCreateWindow allows you to fiddle with the create struct of the window. This structure contains info like the window class, window title, cursor, default brush, menu etc etc. This function is called before the Windows API call 'CreateEx' is called. This API call is responsible for actually creating the Windows window object. The framework will bind then this object (by it's handle) to the CWnd/CDialog object.
For example, in custom controls, it is common to make a check for class name in the PreCreateWindow -override. If this member is NULL, the control will register a new window class with AfxRegisterWndClass to make sure that it has a valid class (All top-level windows in MFC MUST have a valid class name). This way it doesn't bother the end user with this.
To get a complete idea of this, go check the Windows API reference on window objects. Look for things like WNDCLASS structure, RegisterWndClass function, CreateWindow and CreateWindowEx functions. These functions are called by the framework to actually create it's objects. You can, just as well, create them yourself and call the 'Attach' method of CWnd to bind your CWnd object to an existing window handle. Now, you can modify this window through the CWnd wrapper.
As for answers to your questions:
a) What you are trying to do is impossible, font-wise. After a Windows font object is created, you can't modify it. However, you _can_ modify a CFont object. It is just a wrapper for the underlying font.
To accomplish similar results, you can get the CFont-bound Windows font object's representation to a LOGFONT structure by calling the GetLogFont member method of CFont. This will fill the specified LOGFONT structure with the information about this specific font bound to this specific CFont.
Then, use the CFont's member function 'DestroyObject' to destroy the current font object, making sure that it is not selected to a device context, otherwise your program might crash/assert/throw an exception.
After you have destroyed the old object, modify the LOGFONT structure to meet your new demands. Then call 'CreateFontIndirect' of CFont and pass a pointer to the LOGFONT (use address-of) structure. This will create a new Windows font object with the specified parameters, and attach this font to the CFont object.
The general version of this routine (Get current params -> Destroy old -> Modify params -> Create new) is applicable to all GDI objects and their MFC wrappers (CPen, CBrush, CFont etc)
b) For some background info: each Windows window object (Window, dialog, control etc) has a default GDI object of each type bound to it. It has a default pen, a default brush... and a default font.
Now, the OnSetFont function of CDialog does precisely as it's description in MSDN says: it allows you to set a new default font for your dialog. This font is copied (passed) to all controls (statics, buttons etc) drawn by the dialog. So, yes, in a way. If you specify a new default font for your dialog, each control it draws will use this default font to draw it's texts. I am unsure whether the underlying framework routine will resize your controls depending on the font, but I believe that it will. The only way to make sure is to test it.
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Thanks for the explanation. However, OnSetFont receives a pointer to the CFont; it can not pass back a new CFont. I was already so far, that I displayed the current font attributes (GetLogFont) and created a new CFont - but I can't tell MFC to use this CFont.
|
|
|
|
|
Most interesting.
Apparently 'OnSetFont' didn't work as straightforward as I had understood from the MFC Reference. It seems that this handler can't be used to override the passed font object, because in doing so, the program asserts in the end. Why this happens is currently still unclear to me.
However, I've already found a few alternates, but they require you to alter the font for each and every control of your dialog box seperately. Go to your main application, and force a creation of modeless dialog box. Once the box is created, get a control ID inside it (GetDlgItem), and call this returned pointer's 'SetFont' method, issuing an address of a precreated CFont.
If a modeless dialog box is not an option, then create a dynamic CFont object in your dialog's constructor by using a LOGFONT structure with values you specify. Don't forget to zero the structure before using it. Then call 'GetDlgItem' in your dialog's WM_PAINT handler and the result's 'SetFont' to give it a new font. Remember to delete the Windows font object and release the dynamic CFont object, e.g. in your dialog class's destructor.
In all cases, remember to check your app for memory leaks, they tend to become easy with these things
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
Thanks; unfortunately, this is not a solution to my problem. I did not want to complicate things with this detail, but seemingly I should have posted this: setting the fonts is not the real issue for me; I'm doing this for several controls anyway.
The "real" issue with the default font of the dialog is, that it's size determines the pixel size of the window and all controls; the x- and y-units are deducted from the average width and height of the window's font (I remember something that the y-unit is half of the font's "em-height", and the x-unit is a quarter of the character cell width).
With changing the font, I wanted to be able to change the size of everything in the dialog; I want to offer a "calibration" to the user, to adjust the window size depending on the monitor resolution and size as well as the magnification factor. See DPI (a misnomer) in Display properties", "setting", "advanced". I don't display any bit maps, just because of the distortion they cause when displayed with different settings.
Changing the font size makes Windows to recalculate everything, proportional. Any other method would work only if the program calculated not only the sizes, but the positions of the controls as well - and that's a lot of work (and it would convert the application to a dialog wizzard :^(.
I don't give it up (yet), for I find that this should be a natural way to customize an application. I find it dreadful, when an application becomes a "miniature" on a high-resolution monitor, or it "grows" out of the monitor, controls become unaccessible, etc. at low resolution.
Anyway, thanks for your effort. I'm sorry not to have started out with the precise specification of my problem.
|
|
|
|
|
I need to update data of an MFC object declared in one thread from with in an other
thread.............. This needs to be done throug handles... as described by MSDN.............
but i am not finding the required result............ can someone please make a simple Dialog Application
........... with a worker thread to update data on the Dialog....... and send it to me....
..... so that i will be in a better position to understand where i am mistaking........ i have
already wasted lot of time over this but invain...........
Ever Welcome...
|
|
|
|
|
I am trying to make a feature for one of my programs that works somewhat like the CFileDialog, however they are not close enough that I can simply derive from that class. Can someone tell me how I can find out what files and folders are in a specific folder?
Example: C:
Folder 1: Program files
Folder 2: Windows
etc.
I need to be able to do this from any place too. So if I pick "Program Files" from C:\, I then need to be able to find out what files and folders are in it...
I am sure there is some simple easy function that does this, I just can't seem to find it.
Thanks a lot!
If you have a problem with my spelling, just remember that's not my fault. I (as well as everyone else who learned to spell after 1976) blame it on Robert A. Kolpek for U.S. Patent 4,136,395.
|
|
|
|
|
|
i have a custom control that is derived from a CWnd class. I'd like to add a button to the control, but I'm not sure if i should manually draw the button in my paint method or just include a cbutton instance. what do people normally do? if i were to include a cbutton to my control, where would i actually *create* the button and place it in my control?
thanks in advance,
|
|
|
|
|
I'm a 'purist' MFC dude, so I wouldn't mix API and MFC together (CWnd with custom painted buttons (Non-CButton's))
Short explanation:
Use CButton as a static member of your CWnd-derived class. Call it's 'Create' in your derived class's WM_CREATE handler, and leave 'WS_VISIBLE' style out. Display and position the button with SetWindowPos in your WM_PAINT handler. The 'DestroyWindow' should be called automatically for all child windows when WM_DESTROY is posted to your CWnd-derived class's window object's message queue. To make sure, call it yourself in your WM_DESTROY handler.
Detailed explanation:
First, add a static member CButton m_TheButton to your class's header file, and order your constructor to call the CButton's constructor, if necessary. You can also create a CButton pointer and use 'new' to create a dynamic button. Both solutions are fine, the latter being a bit more flexible memory-wise.
Now, your constructed class contains a constructed CButton object. To create the button control, you call this member's 'Create' function, and specify the control's properties (Is child, parent is your control / Sends messages to parent etc etc). Note that when you create the button, you don't need to make it visible. See below.
A good place to call Create for the button control would be in the WM_CREATE message handler of your parent. There, you would create the button, specifying it as non-visible (leave WS_VISIBLE out). Next, go to your WM_PAINT handler, and in there use SetWindowPos to position the control to it's correct place, giving it the correct size, and making it visible. This way, the button is 'Created' only once, but if your window gets repainted, the button will remain in it's specified position and size.
Now, if you write a message handler for WM_COMMAND and make it check if the ID is the button's ID, you can handle messages caused by the user clicking on the button. As the custom control is the parent, the WM_COMMAND messages are posted to it's queue. So, overwrite WM_COMMAND handler for your custom control.
Hope this helps. If it doesn't, I can write a small app which demonstrates "a CWnd object which has a CButton child in it's middle" for you
Note that if you need to use the custom control inside a frame window (SDI Frame, for example), then you should derive it from CCtrlView instead of CWnd. CCtrlView supports all "views which have controls inside them". The Tab Window control (Window with tabs to select different views) is a perfect example of this. CCtrlView is a parent for views such as CEditView (View with Edit control) etc.
If you need, I can write an example of this also, it's good practise
Greets,
Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
thanks for your detailed explanation. I have tried what you've described here, but it flickers alot when my control refreshes its display. i know that it's definitely the extra button on top of my existing control that's causing the flicker, and i'm not sure what to do.
CMyControl::OnPaint()
{
drawSomeStuff(); //i used Keith Rule's CMemDC in these drawing routines already
drawSomeMoreStuff();
m_button1.SetWindowsPos(&CWnd::wndTop....)
}
|
|
|
|
|
Well, I made a small miscalculation in my first reply. To explain it a bit, let's dive into the way stuff is handled in Windows.
You might already know (and if you didn't, now you do) that everything in Windows are windows. Sounds like an idiodome, but it is the fact. For example, our notorious button control is a WINDOW placed OVER a portion of parent view's area (custom control's client area).
So, you need to remake the original Create call to actually include the WS_VISIBLE style for the button. Now, after you have created the button, issue a SetWindowPos, placing the button window AFTER the control's view (first parameter to 'this'), and flagging it to SWP_HIDEWINDOW. You can ignore the size and position parameters by putting the necessary flags in the call (SWP_NOSIZE | SWP_NOMOVE, I think).
Now, when you need to show the button on your control, call it's ShowWindow with SW_SHOW flag. Note, that this call should only be made in a function which is not repeatedly called.
To clarify, consider the hiearchy we have created now. There is the custom control. It has a view. You can draw into this view (device context), displaying lines, texts, rectangles, everything you need to make it look cool. Then, you place new small window objects to represent different types of controls (Edit control, button control, hell, even a static control is a window).
This hiearchy understanding is especially relevant if you use custom-skinned windows (Common trait in custom control creation). Those could have a background image, with black rectangular holes where the controls will be. Then, they might have custom-drawn controls like bitmapped buttons, to fill those holes and fit seamlessly into the control's view.
For the code part you posted: remove the m_button1.SetWindowPos call from the WM_PAINT handler. Instead, hide it in the creation phase, and move this creation to the OnCreate-handler INSTEAD of OnCreateClient, if it is currently there.
The OnCreate-handler is called when the window representing your custom control is created. That is correct, we want to create and hide the button control when the window is being created. The OnCreateClient -handler (which is called to create the VIEW inside the window) can then display the control, if you want it to be visible as soon as the control window is shown. Remember to call the display function as the last thing in OnCreateClient, after everything else is drawn.
-Antti Keskinen
----------------------------------------------
The definition of impossible is strictly dependant
on what we think is possible.
|
|
|
|
|
I am creating a dialog based application that loads from an XML configuration file. So, you don't know at run-time how many or which type of objects will be used. The objects that can be created are custom defined using GDI+ and include labels, buttons etc. A button maybe associated with a call to initialize a dll. My need is that each item loaded from the config file will need to do several things 1) Draw themselves 2) Hit testing.
So finally, on to my question. How can I dynamically load lets say 3 buttons and 3 labels and have them do their required functions.
During testing I am doing the following steps at compile time
1) creating the objects in OnInitDialog() CLabel* pLabel = new CLabel;
2) in my draw function I am adding pLabel->Draw()
3) in LButtonDown I am adding if(pLabel->IsHit()).... do something
So, I need to somehow keep list of buttons and list of labels then in the Draw() function for example I to say while( there are buttons) Draw yourself.
How would you go about tackling this?
Hope that makes since.
|
|
|
|
|
IS there a base class for all these controls ? You need to keep a list of an object that is either a base class or a facade for the objects you want, and then loop through them to do anything with them. I'd have thought that by making the controls children of your window, they would draw themselves though.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
Christian,
I used the term control rather loosely. There is no base class for my controls.
They are just visual representations. The buttons are either bitamps or a
roundedrect for which I create a region for hit testing. So, they are not based
on any real control or window.
Actually I have looked at all of your GDI+ articles so thanks for writing them.
So, your saying keep a list of each kind of objects for example.
1) CLabel
2) CTextButton
3) CBitmapButton
If I create 3 CTextButton's
CTextButton* pTextBtn1 = new CTextButton; // arguments not shown for simplicity
CTextButton* pTextBtn2 = new CTextButton;
CTextButton* pTextBtn3 = new CTextButton;
I don't understand how to create a dynamic list of CTextButton's for looping thru.
Sorry for being so dense.
PS: As a side question how do you determine the length of text that you have drawn?
I am trying to draw some text (ie Friday, November 3, 2003 10:59 PM ) then find the
bounding rect for it so that I can invalid the rect for smooth updating. Since font
type is user configurable the size of the bounding box varies. I know how to find
the height of a font but I have not figured out how to find the width.
|
|
|
|
|
smesser wrote:
So, your saying keep a list of each kind of objects for example.
No, I'm saying keep one list of all objects, by deriving them all from a base class which defines the common functionality, such as a Draw() method.
smesser wrote:
I don't understand how to create a dynamic list of CTextButton's for looping thru.
Sorry for being so dense.
Look up my STL articles, basically you put them in a std::list or std::vector, and then use for_each to step through them and call the required method, such as Draw in OnPaint.
smesser wrote:
PS: As a side question how do you determine the length of text that you have drawn?
A HDC or CDC has a method for doing that, but I don't recall what it's called, sorry.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|
I see what your saying. I have not used STL but I guess it's time I start.
thanks for your input.
|
|
|
|
|
GetTextExtent and friends.
Steve S
|
|
|
|
|
Hi!
I write a MDI application to show large images. I also need a windows to show the overview of whole image. I dont know the best way to do it.
One thought is build a spliter window, but that will waste some space. Because the overview is small, for example 128*128, when take a vertical splitter the remaider space (640-128)*128 will be wasted.
Another is Draw the detail image and then draw the overview on left upper corner in OnDraw. But in my application, the image is draw by tile, not in once, so this method can't be accepted.
Third I think is best. A float window always on top of image views, I can show the overview in it. But i dont' know how to realize it. Is there any resource and code I can take as a reference?
Any idea?
Thank you!!
|
|
|
|
|
When I activate my window,my window will not hide the other application window.like when you activate the win2k's desktop,you can see the application
you have run.
|
|
|
|
|
How can the text, which appears on the button in the taskbar, be changed without changing the window's title bar?
|
|
|
|
|
Hi
After all those hard things that I did to make this software, I faced a stupid error which stoped me.
I have two classes, these two need each other in their definition structure. So I've included the first one's header file in the second one's and vice versa. At this point an error appeared which says:
warning C4182: #include nesting level is 362 deep; possible infinite recursion
fatal error C1076: compiler limit : internal heap limit reached; use /Zm to specify a higher limit
I know what does it say and it's completely logical but I don't know how to solve it. I need a practical advice.
Thanks...
|
|
|
|
|
In the header for each class, use a forward declaration of the other class instead of including the header, e.g.:
class MyClassB;
class MyClassA {
} Then, include the other class's header in the .cpp file.
#include "MyClassA.h"
#include "MyClassB.h"
- Mike
|
|
|
|
|
Put this in class A's header, at the top:
class B;
then include the header file in the .cpp file, do the same on the other side. Then both headers know that the other class exists, which should be all they need to know.
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
|
|
|
|