Home  >  Article  >  Backend Development  >  C# GDI+ Programming (5)

C# GDI+ Programming (5)

高洛峰
高洛峰Original
2016-12-17 10:09:471363browse

Call the API function to draw in the non-client area of ​​the window

There is a FromHdc function in the Graphics class of GDI+. This function can create a Graphics object based on the window device context (DC). In vc++, drawing in the window client area and non-client area It's nothing more than different calls to the GetWindowDC and GetDC functions. The former gets the entire window DC, and the latter gets the window client area DC.

Then we can call the GetWindowDC function in C# to get the entire window DC, and then load it through FromHdc, so that we can draw for the entire window.

How to call WINDOWS API in C#, or how to call functions in dynamic link library (DLL).

Similar to VC++, import the dynamic link library first, and then declare the API function, as follows:

[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);

Of course, the above is the simplest, and there are still some details that I haven’t talked about. Let’s just leave it like this for now. Just be able to use it basically. Those details will be explained in detail later.

In C#, we find that the parameter types of API functions are different, such as handles HDC and HWND in VC++. When declaring here, IntPtr was used instead. There is no way to do this, because C# does not have the concept of pointers, and when we checked the HDC and HWND type definitions, we found that they are both pointer types.

So in C#, these "handle" types are replaced by IntPtr, including area handles HRGN, HICON icons, HFONT font handles, etc.

Let’s look at an example, (continuing from the previous chapter)

Public partial class Form1: Form
{
//Import the dynamic link library and declare the function. This function is declared in the Form1 class.
                                                                                                                                                                                                                                                                                     does not do not have the same effect? ​​path = new GraphicsPath();
/ /Load PNG Pictures t Bitmap BMP = New Bitmap ("D: \ Image \ Win.png");
Public form1 () {
initializedComponent (); Area
                                                                                                                                                           Color cor = bmp.GetPixel(x, y); B int argb = cor.toargb ();
Byte [] Bargb = Bitconverter.getBytes (ARGB);
// Pixel color value is not transparent
if (bargb [3]! = 0) {
// This is this this Add the pixel area to the path
                                                                                                                                                                . //Set the window display area and create a region through the path
This.Region = new Region( PATH); i this.paint+= formpaint;
}}
Private void Formpaaint (Object SENDER, PAINTEVENTARGS E) {


OnPaintBackground (E);
// Handle is the window handle, It is an Intptr type
intptr HDC = GetWindowDC (this.Handle); new Rectangle(0, 0, bmp.Width , bmp.Height));
      }
protected override void OnPaintBackground(PaintEventArgs e)
                                                   . this.ClientRectangle);
                                                                                     How about it, the effect is good, but as soon as you drag the window, the original shape is revealed. Have you noticed the shadow under the apple? It is just to achieve this effect that it will cause some problems, or it will be a lot of trouble. It’s just that I didn’t solve it. Moving the window or maximizing the window without completely refreshing the entire window will cause this problem. This problem will be solved later.

Friends who are interested can also solve this problem.

In addition, I use a transparent brush to fill only the client area of ​​the window. If I want to fill the entire window (including the title bar), the method is the same as drawing on the entire window, get the WindowDC, and then

create a Graphics object and draw the window background.

(Digression: In vc++, the client area and non-client area have different redraw messages, WM_PAINT and WM_NCPAINT. Please pay attention to this. When refreshing the non-client area, do not redraw the client area, although it will not What goes wrong, but it affects efficiency is always bad, avoid it if you can)

Non-client area of ​​the self-drawn window (including title bar, maximize, minimize, close buttons)

Rewrite the message processing function WndProc

public partial class Form1 : Form

                                                                                     Form )

                                                                                                                                                                                                         

              MessageBox.Show("You double-clicked the title bar"); 

                                                                                                When you click the title bar, a prompt will be given, and then Then handle it by default.

To check the value corresponding to the message, you can check it in the VC++ compiler. For example, mark WM_LBUTTONDOWN and then right-click and select Go to definition to view it.


m.HWnd stores the window handle. m.LParam and m.WParam are incidental information of the message. You can refer to the explanation of WPARAM and LPARAM parameters in the CreateWindow function.



The workload of self-painting the non-client area is really too much. Here I will only give you a general idea and direction. I will do it again when I have time.

The premise is of course to calculate various data, such as whether the window has borders. If so, obtain the border width and height, and then calculate the rectangular area of ​​the four borders.

Finally, determine whether the window has the maximum and minimum attributes, and then obtain the area for the three buttons.

These data are stored in the SystemInformation class. For example, SystemInformation.CaptionButtonSize stores the size of the title bar button. Once you get the size, you can

determine the area of ​​the button, because these three buttons are all in the upper right corner of the window. Excluding the height and width of the border.

SystemInformation.CaptionHeight stores the height of the title bar, and the height and width of the border are stored in SystemInformation.BorderSize or SystemInformation.Border3DSize, which is determined according to the FormBorderStyle of the window. You can determine whether the window is maximized by MaximizeBox, which is maximized if true.

After getting the above data, it responds to various messages in the non-client area, such as left mouse button messages WM_NCLBUTTONDOWN and WM_NCLBUTTONUP.

The mouse moves the message WM_NCMOUSEMOVE, and then the self-drawing begins.

The Contains function in the Rectangle class can determine whether a point is within a rectangular area.

For more C# GDI+ Programming (5) related articles, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn