Generate a window of any shape from a bitmap file

Source: Internet
Author: User

Http://hi.baidu.com/aidfan/blog/item/89547c4336566a1d9213c67a.html

There are a lot of software interface is very beautiful, not only the client area of the window is very fine, even the shape of the window is "grotesque", such as Office 2000 assistant, Media Player 7, mediaring talk and so on, Even Winamp is no longer a standard rectangular window after applying certain skins, and it is also an irregular window.
So how do we do this when we're programming?
Among the many Windows API functions, there is a function called SetWindowRgn that can be used to adjust the shape of the window to arbitrary shapes, all of which are "grotesque" windows in the software. The SETWINDOWRGN has three parameters, and the prototype is as follows (you can also see the Winuserapi and WINAPI in the Winuser.h file).
int SetWindowRgn (
HWND hwnd,//Handle of the window to be adjusted
HRGN HRGN,//zone handle
BOOL Bredraw//whether to repaint the window immediately
); Returns a value other than 0 if successful, otherwise 0
The member function of the CWnd class in MFC SetWindowRgn only the first argument is missing.
So, the rest of the job is to create an area.
Creating a zone is not difficult, and there are many ready-made API functions to invoke. It's just that Jane's simple method can only create a relatively simple area. Such functions are:
1. Create an area of an ellipse
HRGN CreateEllipticRgn (
int Nleftrect,//x-coordinate of the upper-left corner of the bounding rectangle
The y-coordinate of the upper-left corner of the int ntoprect,//bounding rectangle
int Nrightrect,//The x-coordinate of the lower-right corner of the bounding rectangle
The y-coordinate of the lower-right corner of the int nbottomrect//bounding rectangle
);
2. Create a rectangular region
HRGN CreateRectRgn (
int Nleftrect,//x-coordinate of the upper-left corner of the bounding rectangle
The y-coordinate of the upper-left corner of the int ntoprect,//bounding rectangle
int Nrightrect,//The x-coordinate of the lower-right corner of the bounding rectangle
The y-coordinate of the lower-right corner of the int nbottomrect//bounding rectangle
);
3. Create rounded oval regions
HRGN CreateRoundRectRgn (
int Nleftrect,//x-coordinate of the upper-left corner of the bounding rectangle
The y-coordinate of the upper-left corner of the int ntoprect,//bounding rectangle
int Nrightrect,//The x-coordinate of the lower-right corner of the bounding rectangle
The y-coordinate of the lower-right corner of the int nbottomrect//bounding rectangle
int Nwidthellipse,//height of rounded ellipse
int nheightellipse//fillet ellipse width
);
4. Create an area of any shape
HRGN Extcreateregion (
CONST XFORM *lpxform,//pointer to morph data
DWORD ncount,//data in size, in bytes
CONST rgndata *lprgndata//Data pointer
);
If the creation fails, all functions return NULL.
The use of the first three functions is straightforward, and the fourth function is somewhat more complex. The Extcreateregion function can create an area from a series of rectangles, which are the set of all rectangles. Such a feature can be implemented by creating the same rectangular area and merging them with the COMBINERGN function, but Extcreateregion has better performance. In general, we only specify the latter two parameters, and the first parameter is set to a null value. The RGNDATA structure is defined as follows (WINGDI.H)
typedef struct _RGNDATA {
Rgndataheader RDH;
Char buffer[1];
} rgndata, *prgndata, near *nprgndata, far *lprgndata;
Among them, the rgndataheader structure is defined as:
typedef struct _RGNDATAHEADER {//RDH
DWORD dwsize; Size of the structure itself
DWORD IType; Type, must be Rdh_rectangles (value 1)
DWORD ncount; Number of rectangles
DWORD nrgnsize; Buffer size to accept rectangle data
RECT Rcbound; The size of the bounding rectangle of the area
} Rgndataheader, *prgndataheader;
After you specify these basic data, you can fill in the rectangle's data, and then you can create the zone by calling the Extcreateregion function as a pointer to the rgndata* type.
Now, the key to the problem is just how to specify the data for the rectangle. The simplest way to specify this is to use fixed data, as shown in the following example:
Rgndata Rd;
rd.rdh.dwSize = sizeof (Rgndataheader);
Rd.rdh.iType = 1;
rd.rdh.nRgnSize = 0;
Rd.rdh.nCount = 2;
SetRect (&rd.rdh.rcbound, 0, 0, 1000, 1000);
LPRECT LPRECT = (LPRECT) &rd. Buffer;
:: SetRect (&lprect[0], 0, 0, 250, 20);
:: SetRect (&lprect[1], 20, 20, 300, 40);
HRGN HRGN =:: Extcreateregion (NULL, sizeof (Rgndataheader) + (sizeof (RECT) * 2), &RD);
But there is no practical value in creating a simple region, a more general idea is to draw the area you want to create in a bitmap, and then read the information from the bitmap to create the area so that you can create any shape of the area, you can create any shape of the window, and modify the shape is very convenient, Just modify the bitmap. The special shape of the window generally has a background image, we will set the background image after a transparent color (the window shape does not contain the part), it can be double benefit. Transparent color can generally take magenta, its RGB value is 255, 0, 255
The optimization algorithm that transforms a bitmap into a collection of rectangles is not easy to implement. In general, a feasible method is to scan a bitmap by line, merging non-transparent color and successive pixel points into a rectangle. , each rectangle has only one pixel high. From our point of view, this approach is to use a line of horizontal lines to show the image. This algorithm is simple and simple, time complexity and spatial complexity can be estimated, the bitmap is very complex in the case of the gap with the optimal algorithm is not small, but the bitmap is simpler (such as: a set of rectangles) in the case than the optimal algorithm performance would like many times (in that case, you can use the CREATERECTRGN function, Call the Combinergn merge area again).
The information about how to read the image from a bitmap is no longer detailed.
Build an MFC. exe project with Visual C + + named Shapewnd, with the Type dialog box and the rest taking the default values. Modifies the style of the Idd_shapewnd_dialog resource to no title bar, pop-up window, no bounds. Generate two more files, named Bmp2rgn.h and Bmp2rgn.cpp, and add them to the project, which can be found in the details below. Modify the ShapeWndDlg.cpp file, add the processor of the WM_CREATE message with the Class Wizard and modify its contents as follows:
int cshapewnddlg::oncreate (lpcreatestruct lpcreatestruct)
{
if (cdialog::oncreate (lpcreatestruct) = =-1)
return-1;

Adjust the window ' s region
Static HRGN HRGN;
HRGN = Creatergnfrombitmap (Idb_shape, RGB (255, 255, 255)); Pure white
SetWindowRgn (HRGN, TRUE);

return 0;
}
Then modify the OnPaint function as follows:
void Cshapewnddlg::onpaint ()
{
if (Isiconic ())
{
AppWizard generated code
CPAINTDC DC (this); Device context for painting

SendMessage (Wm_iconerasebkgnd, (WPARAM) DC. GETSAFEHDC (), 0);

Center icon in client rectangle
int cxicon = GetSystemMetrics (Sm_cxicon);
int cyicon = GetSystemMetrics (Sm_cyicon);
CRect rect;
GetClientRect (&rect);
int x = (rect. Width ()-Cxicon + 1)/2;
int y = (rect. Height ()-Cyicon + 1)/2;

Draw the icon
dc. DrawIcon (x, y, M_hicon);
}
Else
{
Customized Code
Paint the bitmap on the dialog
CPaintDC Dcdlg (this);
CDC Dcmem;
CBitmap bitmap;
CRect rect;

GetWindowRect (rect);
Bitmap. LoadBitmap (Idb_shape);
Dcmem.createcompatibledc (&DCDLG);
CBitmap * Poldbitmap = Dcmem.selectobject (&bitmap);
Dcdlg.bitblt (0,0,rect. Width (), Rect. Height (), &dcmem,0,0,srccopy);
Dcmem.selectobject (POLDBITMAP);
}
}
Create a new or import bitmap with the ID of Idb_shape, which contains the image that is the shape of the last window.
Finally, add a line to the header of the ShapeWndDlg.cpp file:
#include "Bmp2rgn.h"
Compile the project, you can see similar to the effect of the first text.
Contents of the Bmp2rgn.h file
Bmp2rgn.h:the header File
//

#ifndef _bmp2rgn_h__included
#define _bmp2rgn_h__included

#define ALLOC_UNIT 100

HRGN Creatergnfrombitmap (UINT uidbitmap,//The bitmap ' s ID
COLORREF crtransparent = RGB (255, 0, 255));//Transparent color, default to Megenta

#endif//_bmp2rgn_h__included
Contents of the Bmp2rgn.cpp file
Bmp2rgn.cpp:implementation file
//

#include "stdafx.h"
#include "Bmp2rgn.h"

#ifdef _DEBUG
#define NEW Debug_new
#undef This_file
static char this_file[] = __file__;
#endif

HRGN Creatergnfrombitmap (UINT uidbitmap,//The bitmap ' s ID
COLORREF crtransparent//Transparent color, default to Megenta
)
{
CDC MEMDC;
Memdc.createcompatibledc (NULL);

CBitmap bitmap;
BITMAP BM;
Bitmap. LoadBitmap (UIDBITMAP);
Bitmap. Getbitmap (&BM);

Bitmapinfoheader Bmih = {sizeof (bitmapinfoheader),
Bm.bmwidth, Bm.bmheight, 1, bi_rgb, 0, 0, 0, 0, 0};

VOID * pbits;
Hbitmap Hdib =:: CreateDIBSection (MEMDC.M_HDC, (Bitmapinfo *) &bmih, dib_rgb_colors, &pbits, NULL, 0);
Hbitmap holdbmp = (HBITMAP):: SelectObject (MEMDC.M_HDC, Hdib);

CDC DC;
dc. CreateCompatibleDC (&MEMDC);

Get how many bytes per row (rounded-to-bits)
BITMAP Dib;
:: GetObject (Hdib,sizeof (BITMAP), &dib);
while (dib.bmwidthbytes% 4)
{
dib.bmwidthbytes++;
}

Copy the bitmap into the memory DC
Hbitmap HOLDBMP2 = (HBITMAP):: SelectObject (DC.M_HDC, bitmap.m_hobject);
Memdc.bitblt (0, 0, bm.bmwidth, bm.bmheight, &DC, 0, 0, srccopy);

Alloc some memory using the Alloc_unit
DWORD maxrect = Alloc_unit;
HANDLE Hdata =:: GlobalAlloc (gmem_moveable, sizeof (Rgndataheader) + (sizeof (RECT) * maxrect));

Fill in the fields, just follow the rules
Rgndata *prgndata = (Rgndata *):: GlobalLock (Hdata);
prgndata->rdh.dwsize = sizeof (Rgndataheader);
Prgndata->rdh.itype = Rdh_rectangles; Rdh_rectangles EQs 1
Prgndata->rdh.ncount = prgndata->rdh.nrgnsize = 0;
:: SetRect (&prgndata->rdh.rcbound, 0, 0, Maxlong, Maxlong);

Get the r,g,b value of the transparent color
BYTE r0 = Getrvalue (crtransparent);
BYTE G0 = Getgvalue (crtransparent);
BYTE B0 = Getbvalue (crtransparent);

Scan each bitmap row from bottom to top
byte *prow = (BYTE *) Dib.bmbits + (dib.bmheight-1) * dib.bmwidthbytes;
for (int y = 0; y x0)
{
Add the rectangle of (x0, y)-(x, y+1)
if (prgndata->rdh.ncount >= maxrect)//If need more rectangles
{
Reallocate memory
:: GlobalUnlock (Hdata);
Maxrect + = Alloc_unit;
Hdata =:: GlobalRealloc (Hdata, sizeof (Rgndataheader) + (sizeof (RECT) * maxrect), gmem_moveable);
Prgndata = (Rgndata *):: GlobalLock (Hdata);
}
Rect *lprect = (rect *) &pRgnData->Buffer;
:: SetRect (&lprect[prgndata->rdh.ncount], x0, y, X, y+1);
prgndata->rdh.ncount++;
}
}//For X
PRow-= dib.bmwidthbytes; Go one row Upper
}//For Y

Create a region consisted of the rectangles
HRGN HRGN =:: Extcreateregion (NULL, sizeof (Rgndataheader) + (sizeof (RECT) * maxrect), prgndata);
:: GlobalFree ((hglobal) prgndata);

Do some cleaning up work
:: SelectObject (DC.M_HDC, HOLDBMP2);
::D eleteobject (:: SelectObject (MEMDC.M_HDC, holdbmp));
dc. DeleteDC ();
Memdc.deletedc ();
Bitmap. DeleteObject ();
return HRGN;
}
Because the resulting window does not have a title bar, there is no way to drag it. So, to reload the window's onnchittest function, judge the point parameter, return htcaption as needed to implement the drag (because the window boundary is none, so the result of double-clicking is not maximized), In practice, it is possible to determine where the mouse area returns different custom values for use by other parts of the program.
The simplest onnchittest function can be written like this:
UINT cshapewnddlg::onnchittest (CPoint point)
{
return htcaption;
}

http://blog.csdn.net/witch_soya/article/details/6853619

Generate a window of any shape from a bitmap file

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.