Handling Windows Message with C Builder (Message)
Foreword
Although C Builder is a RAD-style development tool, the program designer does not need the details of the Windows message in most cases, as long as the mind is placed in the event of the function of the software element. However, because the Windows job system is one-on-telecon-driven system, the application on the architecture is naturally unable to be outside the system, and the Windows message processing power is still the event of C Builder. C Builder is indispensable.
It is undeniable that the event handling capacity provided by C Builder has a degree of completeness, but we must also recognize that in the VCL beautiful new world constructed in C Buider, there is still no leakage net fish. For example, the user's custom message, the processing of Winsock messages, and some of the Windows messages such as WM_NC **** series are not included in C Builder's object model.
In this article I will tell you how to handle Windows messages in C Builder and achieve the function that cannot be done in a general VCL component through this capability.
What is WINDOW message (Message)
Everyone knows that Windows is a job system with message driven. However, for the message itself, it is like a deep, only knows that it doesn't know how it happened, although C Builder encapsulates some Windows messages in the event (Event) system, but as a Windows programming designer, it is necessary to understand Windows Message system.
The so-called message is sent by the Windows job system to the program. It is a manner of communication in the system, for example, when moving a mouse, press the slice button, change the window size, and Windows will send a message to a notification program. Of course, in order to identify the content of the event, a number of messages are defined in the Windows system, such as WM_Paint, WM_CHAR, and more.
When the event occurs, Windows will determine that the event must be received by that program, and then send an event in a message to the program. Although hundreds of events have been included in the Windows system, the job system does not design different message structures for each event, but is described in a general structure, this structure is called in C Builder. TMESSAGE.
Of course, as the incident is different, the interpretation of the message is also different, and the exclusive structure is defined for various common messages in C Builder, and you can use them directly to interpret the message. These messages define in include / vcl / messages.hpp in the C Builder directory, you can decide to explain the TMESSAGE parameters or convert them into exclusive structures. Are you abstract? I will give an example. For WM_NCHITTEST messages, C Builder defines the exclusive structure of TwMnchittest, so you can get XPOS, YPOS equivalents directly. Or you can also get its value directly from the LPARAM of TMessage, and the end of your use is convenient. Carefully observe the two structures of TMessage and Tmnchittest, you will find that they are equivalent, that is, their size is consistent, so you can directly transform each other with mandatory transformation (this is a way similar to Union).
Struct tMessage
{
Cardinal MSG;
union
{
Struct
{
Word wparamlo;
Word wparamhi;
Word lparamlo;
Word lparamhi;
Word resultlo;
Word resulthi;
}
Struct
{
Long wparam;
Long lparam;
Long Result;
}
}
}
Struct twmnchittest
{
Cardinal MSG;
Long unused;
union
{
Struct
{
Windows :: TsmallPoint Pos;
Long Result;
}
Struct
{
Short xpos;
Short ypos;
}
}
}
After receiving the message, the program must handle the message. If not processed, it can be handed over to the Windows's internal processing program. If the program requires the return value, it can be transferred at this time, and Windows will This value is transmitted back to the caller. This completes the program of message delivery.
Is it complicated? not at all! Learn about the WINDOWS message system, let's see if you can use it to do something interesting!
Message use example of a user's custom title bar
Generally, the title rod of the Windows program is located above the window, and we can use the title bar to move the window. The following I will demonstrate how to use C Builder to make the title rod on the left side of the window. Figure 1:
Figure 1 title rod on the left window.
As shown in the figure above, you can see very clearly that this window is very different; its title rod is located on the left, and its color is green, and the direction of its text is from the lower 90 degrees A shape, while its function is the same as the general title rod, you can move the mouse to the point, then move the window. How is this?
Mystery of WM_NCHITTEST message
WM_NCHITTEST messages are a very special message. It is used to determine a message that is currently attribute at the current mouse, so we can use this feature, when the mouse is moved to the specified location, pass back HTCAption, so that the system is currently located on the title rod, so you can move Window. how is it? Is it very magical?
From the above, we can smoothly spoof the system smoothly as long as we intercept the WM_NCHITTEST message, then return to HTCAption, and achieve the effect of simulating the title rod in any position.
C Builder's huge gather
In order to handle the message, C Builder is defined in the Macro.
Begin_MESSAGE_MAP
Message_handler (WM_NCHITEST, TMESSAGE, ONNCHITTEST)
END_MESSAGE_MAP (TFORM)
The above monographs begin_Message_map, Message_Handler and End_Message are the gauge of C Builder definition, which is more important to message_handler; it needs to be parameters, the first parameter represents the iD, the second representative parameter, The last one is the message handler.
At first glance, this huge set seems to have a few points like MFC and OWL, it's true, but its mechanism is simpler and concise, we can see C Builder for this giant The original definition of the set:
#define begin_message_map virtual void __fastcall dispatch / {/ /
Switch ((pMessage) -> msg) /
{
#define message_handler (MSG, Type, Meth) /
Case MSG: /
Meth (* ((type *) message); /
Break;
#define end_message_map (base) Default: /
Base :: dispatch (message); /
Break; /
} /
}
It is much simpler than the terrible gather of MFC or OWL, because C Builder has completed most of the work for you. In fact, if we start the above giant set, you can get the following results:
Virtual void __fastcall dispatch (void * message)
{
Switch ((pMessage) -> msg
{
Case WM_NCHITTEST:
ONNCHITTEST (* (tMessage *) message);
Break;
DEFAULT:
TFORM :: Dispatch (Message);
Break;
}
}
how about it? After the start, it is very easy to find out that this huge gather is very easy to sell, if you play MFC's message processing mechanism, then see the above gather, compared to pediatric However, it is also due to its simple, so the advantage of C Builder is highlighted.
I briefly explain the above program: Deconsive virtual fifth named Dispatch in each TForm, which is used to handle Windows messages, in most cases, the message is called C Builder Provide a handset, so you don't need to modify it.
In other words, we can rewrite the DISPATCH function, you can use to process the specified message. The gatherings mentioned earlier simplifies this program, nothing big.
Custom title drawing
Since we want to use a custom title, you must set the TForm's Border in the program to bsnone, so your tform will not have title.
Let's draw the title stick again, we want to draw a title in the left and left, so we must handle the TForm's onpaint event, and then draw the title bar in this event. The following is handled for its event:
Void __fastcall tform1 :: formpaint (TOBJECT * SENDER)
{
Rect RC;
:: SetRect (& RC, 0, 0, ClientWidth, ClientHeight);
DrawButtonface (Canvas, RC, 1);
Canvas-> Pen-> Color = CLGREEN
Canvas-> brush-> color = clgreen;
Canvas-> Rectangle (0, 0, 20, ClientHeight);
: //
:
}
You can see, we draw a width of 20, the color is the title bar. Therefore, we handle the WM_NCHITTEST message handling a corresponding modification:
Void __fastcall tform1 :: overnchittest (tMessage & msg)
{
TPOINT PT;
Pt.x = loword (msg.lparam);
Pt.y = HiWord (msg.lparam);
Pt = ScreenToClient (Pt); Rect RC;
:: SetRect (& RC, 0, 0, 20, ClientHeight);
IF (PtinRect (& RC, PT))
Msg.result = htcaption;
Else
DefaultHandler (& MSG);
}
OnnchitTestphrops first achieve the current hostel, note that the point incorporated by the WM_NCHITTEST message is the absolute coordinate relative to the screen, so it must be converted to TFORM's relative sniffer value after obtaining this point. Then it is again determined whether or not it falls within the scope of the title rod we defined. If it comes back to the HTCAPTION value, it will be handled in the form of a configured processory DEFAULTHANDLER. This completes a title stick on the left.
Rotating the output of the text
Carefully observe the picture, you will find the direction of the title font it used, which has become a 90-rotated text in response to the turn of the title rod, how is this?
In fact, it is nothing to wear, just use the traditional SDK's drawing method to draw. Because the TFont objects in C Builder do not define the properties of the text rotation, we have to achieve this goal through the traditional GDI drawing method.
Char * msg = caption.c_str ();
Logfont fontrec;
MEMSET (& FONTREC, 0, SIZEOF (Logfont));
FontRec.lfheight = -13;
FontRec.lfweight = fw_normal;
FontRec.lfescapement = 900; // Rotate the key
LSTRCPY (FontRec.lffacename, "fine body");
HFONT HFONT = CREATEFONTINDIRECT (& FONTREC);
HFONT HOLD = :: SelectObject (canvas-> handle, hfont);
:: SetRect (& RC, 0, 0, 20, ClientHeight);
:: SetTextColor (Canvas-> Handle, RGB (255, 255, 255);
:: Textout (canvas-> Handle, 3, ClientHeight-3, MSG, LSTRLEN (MSG));
:: SelectObject (canvas-> handle, Hold);
:: DeleteObject (HFONT);
The above program I don't plan to add a detailed explanation, simply, it is a glyph that rotates 90 degrees, then painting the string on the screen in this shape, this section code is the key to you must know Canvas-> Handle That is to represent the HDC of the GDI drawing. Some of the functions you can find in the books that generally explain the traditional Windows SDK drawing.
From this, we can also get an experience: although the C Builder's fast-moving environment has replaced a large part of the traditional SDK-style design, but the necessary SDK program techniques can make you up. floor. So I suggest you look at the SDK-related books and enrich the basic knowledge when you are "good power." Maybe we can name "Becking BCB, Lookup SDK" learning attitude!
other instructions
In this system, because of the borderstyle properties of TFORM, it is BSNONE. Therefore, there is no outer frame. In order to beautify the window, I wrote a few auxiliary functions to draw the stereo frame. If you have similar needs in other programs, you can also use it.
Void Dorect (Tcanvas * Canvas, Rect, ColorRef CtopColor, ColorRef Cbottomcolor) {
Point P [3];
P [0] .x = Rect.right;
p [0] .y = Rect.top;
P [1] .x = Rect.Left;
P [1] .y = Rect.top;
P [2] .x = Rect.Left;
P [2] .y = Rect.bottom;
Canvas-> Pen-> Color = TCOLOR (CTOPColor);
Canvas-> POLYLINE (P, 3);
P [1] .x = Rect.right;
P [1] .y = Rect.bottom;
P [2] .x -;
Canvas-> Pen-> Color = TCOLOR (CBOTTOMCOLOR);
Canvas-> POLYLINE (P, 3);
}
Void Frame3D (Tcanvas * Canvas, Rect & Rect, ColorRef Ctopcolor, ColorRef Cbottomcolor, IC iCOLWIDTH)
{
Rect.bottom--; Rect.right--;
While (iColwidth> 0)
{
Icolwidth -;
DORECT (Canvas, Rect, CtopColor, CBOTTOMCOLOR);
InflateRect (& Rect, -1, -1);
}
Rect.bottom ; Rect.right ;
}
Void DrawButtonface (Tcanvas * Canvas, Rect & Rect, Int Nbevelwidth)
{
Canvas-> Brush-> color = CLBTNFACE;
Canvas-> FillRect (TRECT);
Frame3D (Canvas, Rect, :: getSyscolor (color_btnshadow), :: getsyscolor (color_windowframe), NbevelWidth;
Frame3D (Canvas, Rect, :: getSyscolor (Color_BTnHighlight), :: getSyscolor (Color_Btnshadow), NbevelWidth;
}
The most important thing in this one is DrawButtonFace, which is used to draw a stereoscopic box like Button in a rectangular range, which I use it to draw the border of TForm. You can see its visual effect by the picture.
Program improvement
As we mentioned to improve the visual effect of the BSnone window is to reach the DrawButtonFace letter written by yourself. It is not a way to solve the problem, but it has increased the complexity of the program, and I will demonstrate a use of you. Change the skill of CreateParams to achieve a similar function.
CreateParams is a virtual fifth that you can modify Windows style, because the Form that is originally defined in C Builder is a Dialog (conversation window), and the shape of the conversation window has a title stick, however If we set the outer frame as bsnone, you must draw the outfog of the fake window, otherwise it looks not good.
However, in addition to the front Dialog window in the Windows system, another POPUP-style window is also provided, but this option is not provided in C Builder. So we can actually generate WS_POPUP forms in the form of WS_POPUP, so that we don't have to write a letter from the painting frame. Its program is actually very simple, just put params.style's ws_dlgframe, change to another WS_POPUP (pop-up window). To do the above effects, you can reach as long as the AND and OR operations can be used. The following is the code code: void __fastcall tform1 :: createparams (tcreateparams & params)
{
TFORM :: CreateParams (params);
Params.Style | = WS_POPUP;
Params.Style ^ = ws_dlgframe;
}
Figure II shows the result of the rewritable program, not only the program is simple, but the appearance is better, that is because we are holding the title rod, it will not cover the outer frame as front.
Figure 2 utilizes the new rules of CreateParams skills.
Information use Examples II use material background in the program
Many people are using internet browsers such as Internet Explorer, Netscape, which will discover the material pattern on many web pages as a background, which greatly strengthens its visual effect, and uses web pages to look more beautiful. At this time, maybe you will think: How is this material background made?
In the following article, I will demonstrate how to make the above-mentioned material background effect using C Builder, so that your program can make a browser-like effect. The implementation effect of this program is like
Figure 叁 Form with material background
WM_ERASEBKGND message description
WM_ERASEBGGN is a triggered message when the Windows background will be cleared. When this message occurs, it will pass to the Windows HDC to be cleared (remember the important role in this SDK to draw it?). So we can get this HDC, then set the Canvas's Handle value to this value, so you can paint on Canvas.
Declare WM_RASEGKGN
Class TFORM1: Public TForm
{
__published: // Ide-management Components
TPANEL * PANEL1;
PRIVATE: // user declarations
Public: // user declarations
__fastcall tform1 (tComponent * Owner);
Void Virtual __fastcall onwmeraseBkGnd (TwmesebkGnd & MSG);
Begin_MESSAGE_MAP
Message_handler (WM_ERASEBKGND, TWMERASEBKGND, ONWMERASEBKGND)
END_MESSAGE_MAP (TFORM)
}
In order to intercept the WM_RASEBMGN message, we must use the gathering of the previous talked to declare, where we use C Builder to use the TwmeRaseBkGnd message structure defined by WM_ERASEBKGND as a parameter, and define a message processing function onwmerasegkgn. Of course, the message parameters it are incorporated is the aforementioned TWMERaseBkGnd &.
Fill the screen with material pattern
After completing the definition of the message handler, we must write the actual program code. In order to draw in the incoming HDC, we must New a Canvas and then get the value of the HDC from TWMERaseBkGnd. Then in order to load the material background, we must New a graphics :: Tbitmap (here, graphics :: is because there is still another Tbitmap, is located in the namespace in Windows, so you must distinguish between graphics :: Its namespace). Then we can use LoadFromFile to load the material background pattern.
After completing the above two necessary preparations, we can formally draw the material background in Canvas, first of course calculate the number of draws, then use the loopback of CANVAS to fill it full of screens . Finally don't forget to delete the items generated by New New. The following is a list of program:
Void __fastcall tform1 :: onwmesebkgnd (twmesebkgnd & msg)
{
Tcanvas * canvas = new tcanvas;
Graphics :: tbitmap * bitmap = new graphics :: tbitmap
Bitmap-> LoadFromfile ("back.bmp");
Canvas-> Handle = msg.dc;
INT CX = ClientWidth / Bitmap-> Width 1;
INT CY = ClientHeight / Bitmap-> Height 1;
For (int i = 0; i For (int J = 0; j Canvas-> DRAW (j * bitmap-> height, i * bitmap-> width, bitmap); Msg.result = true; DELETE BITMAP; Delete Canvas; } how about it? Not bad right! In fact, as long as you enrich the knowledge of Windows messages, although there are not many opportunities to use Windows messages in C Builder, but at some time, it can play small soldiers' effect, like this section. Examples are general. in conclusion In this article, I demonstrate the method of handling the message in C Builder, and simultaneously describe the skills in the background picture of the C Builder. In addition, in the Windows system, the message (Message) is ineffective, which is a component of many traditional window components to communicate with each other, so unless you can guarantee that you will never use other standard components, otherwise you It is necessary to have a message processing. So, understanding the Windows message is your indispensable skill. Only this, you can "one hundred feet, further", will not be limited by RAD.