首先说一下GDI+Flat:我有写过一个GDI+Flat的系列博客,一共有10篇,都是顺着的,这是第一篇:GdiplusFlat(1)GDI+平面API:用GDI的思想进行GDI+编程,有兴趣的可以看一看。因为本篇中的绘图函数都是用的GDI+Flat,因此我们需要自己声明函数,自己定义数据结构,只用Win32和c语言的基本数据类型。
好了,废话不多说,先上图:
测试结果:XP、Win7(Areo/Basic)、Win8.1、Win10下都能很好的工作
如果觉得标题栏和边框不好看,可以改颜色,也可以改成渐变的,还可以用图片,比如画个透明玻璃的PNG图片,如果是带阴影的玻璃的图片,就和Win7的Aero差不多了,可惜我不会PS。
源代码如下:
#include "stdafx.h"
//#include
//#include
#pragma comment(lib,"gdiplus.lib")//very important
#include
#include
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"Msimg32.lib")
#include
#pragma comment(lib,"OleAut32.lib")
//GDI+Flat
#define ARGB(a,r,g,b) ((int)(((BYTE)a)<<24)|(((BYTE)r)<<16)|(((BYTE)g)<<8)|((BYTE)b))
typedef struct _GdiplusStartupInput{
unsigned int GdiplusVersion;
unsigned int DebugEventCallback;
BOOL SuppressBackgroundThread;
BOOL SuppressExternalCodecs;
}GdiplusStartupInput;
extern "C" int WINAPI GdiplusStartup(int* token, GdiplusStartupInput *input, int *output);
extern "C" void WINAPI GdiplusShutdown(int token);
extern "C" int WINAPI GdipCreateFromHDC(HDC hdc, int* graphics);
extern "C" int WINAPI GdipDeleteGraphics(int graphics);
//画笔
extern "C" int WINAPI GdipCreatePen1(unsigned int argb_color, float width, int unit, int** pen);
extern "C" int WINAPI GdipDeletePen(int* pen);
//画矩形 画直线
extern "C" int WINAPI GdipDrawRectangle(int graphics, int* pen, float x, float y, float width, float height);
extern "C" int WINAPI GdipDrawLine(int graphics, int* pen, float x1, float y1, float x2, float y2);
//画刷
typedef struct _PointF{
float x;
float y;
}PointF;
extern "C" int WINAPI GdipCreateSolidFill(unsigned int argb_color, int** brush);
extern "C" int WINAPI GdipCreateLineBrush(PointF* point1, PointF* point2, unsigned int argb_color1, unsigned int argb_color2, int wrapMode, int** lineGradient);
extern "C" int WINAPI GdipDeleteBrush(int* brush);
//画填充矩形
extern "C" int WINAPI GdipFillRectangle(int graphics, int* brush, float x, float y, float width, float height);
//画图片
extern "C" int WINAPI GdipLoadImageFromFile(WCHAR* filename, int** image);
extern "C" int WINAPI GdipLoadImageFromStream(LPSTREAM stream, int** image);
extern "C" int WINAPI GdipGetImageDimension(int* image, float* width, float* height);
extern "C" int WINAPI GdipDrawImageRect(int graphics, int* image, float x, float y, float width, float height);
extern "C" int WINAPI GdipDisposeImage(int* image);
//画文字
typedef struct _RectF{
float x;
float y;
float Width;
float Height;
}RectF;
extern "C" int WINAPI GdipSetTextRenderingHint(int graphics, int mode);
extern "C" int WINAPI GdipSetSmoothingMode(int graphics, int smoothingMode);
extern "C" int WINAPI GdipCreateFontFamilyFromName(WCHAR* name, int* fontCollection, int** fontFamily);
extern "C" int WINAPI GdipCreateStringFormat(int formatAttributes, short language, int** format);
extern "C" int WINAPI GdipSetStringFormatAlign(int* format, int align);
extern "C" int WINAPI GdipSetStringFormatLineAlign(int* format, int align);
extern "C" int WINAPI GdipCreateFont(int* fontFamily, float emSize, int style, int unit, int** font);
extern "C" int WINAPI GdipDrawString(int graphics, WCHAR* string, int length, int* font, RectF* layoutRect, int* stringFormat, int* brush);
extern "C" int WINAPI GdipDeleteFont(int* font);
extern "C" int WINAPI GdipDeleteStringFormat(int* format);
extern "C" int WINAPI GdipDeleteFontFamily(int* fontFamily);
int token;
int* pen;
int* brush;
int* image;
void WINAPI MyDrawText(HDC hdc, LPWSTR str, LONG left, LONG top, LONG width, LONG height, BOOL iscenter, COLORREF color = 0){
int graphics;
GdipCreateFromHDC(hdc, &graphics);//创建Graphics对象
GdipCreateSolidFill(color, &brush);//创建单色画刷
GdipSetTextRenderingHint(graphics, 3);//设置Graphics对象的文本渲染模式
int* fontfamily;
GdipSetSmoothingMode(graphics, 4);//设置Graphics对象的渲染质量
GdipCreateFontFamilyFromName(L"宋体", NULL, &fontfamily);//创建一个基于指定的字体系列的FontFamily对象
int* format;
GdipCreateStringFormat(0, 0, &format);//创建一个基于字符串的格式标志和语言的 StringFormat 对象
int* font;
GdipCreateFont(fontfamily, 12, 0, 2, &font);//创建字体
RectF rect; rect = { left, top, width, height };
GdipDrawString(graphics, str, -1, font, &rect, 0, brush);//画文字
GdipDeleteFont(font);//销毁指定Font对象,释放资源
GdipDeleteStringFormat(format);//销毁指定StringFormat对象,释放资源
GdipDeleteFontFamily(fontfamily);//销毁指定FontFamily对象,释放资源
GdipDeleteBrush(brush);//销毁画刷
GdipDeleteGraphics(graphics);//销毁Graphics对象
}//参数:设备上下文句柄,要绘制的字符串,x位置,y位置,宽度,高度,是否绘制在矩形中央,argb颜色
//*************************************************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
WNDCLASS wc;
const TCHAR* AppName = TEXT("MyWindowClass1");
HWND hwnd1;
HDC mdc, mdc2;
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
//GDI+开启
GdiplusStartupInput StartupInput = { 0 };
StartupInput.GdiplusVersion = 1;
if (GdiplusStartup(&token, &StartupInput, NULL))MessageBox(0, TEXT("GdiPlus开启失败"), TEXT("错误"), MB_ICONERROR);
//这里是在构建窗口类结构
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;//窗口回调函数指针
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;//实例句柄
wc.hIcon = LoadIcon(hInstance, TEXT("ICON_1"));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);//默认指针
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = AppName;//窗口类名
//注册窗口类
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("注册窗口类失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
//创建窗口
int style = WS_OVERLAPPEDWINDOW;
hwnd1 = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST, AppName, TEXT("窗口标题"), style, 0, 0, 0, 0, 0, LoadMenu(hInstance, TEXT("MENU1")), hInstance, 0);
if (hwnd1 == NULL)
{
MessageBox(NULL, TEXT("创建窗口失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
//无边框窗口
SetWindowLong(hwnd1, GWL_STYLE, WS_OVERLAPPED | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowPos(hwnd1, HWND_TOP, 50, 50, 500, 500, SWP_SHOWWINDOW);
mdc = CreateCompatibleDC(0);//创建内存DC
BITMAPINFO bitmapinfo;
RtlZeroMemory(&bitmapinfo, sizeof(BITMAPINFO));
bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo.bmiHeader.biWidth = 500;
bitmapinfo.bmiHeader.biHeight = 500;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biBitCount = 32;
HBITMAP b, old;
b = CreateDIBSection(0, &bitmapinfo, 0, 0, 0, 0);
old = (HBITMAP)SelectObject(mdc, b);
if (old != NULL){
DeleteObject(old);
}
DeleteObject(b);
int graphics;
GdipCreateFromHDC(mdc, &graphics);//创建Graphics对象
GdipCreateSolidFill(0x80FFFFFF, &brush);//创建画刷,这是整体的背景,有透明度
GdipFillRectangle(graphics, brush, 0, 0, 500, 500);//画填充矩形
GdipDeleteBrush(brush);//销毁画刷
GdipCreatePen1(ARGB(200, 0, 157, 225), 1, 2, &pen);//创建画笔
GdipDrawRectangle(graphics, pen, 0, 0, 499, 499);//画矩形
GdipDeletePen(pen);//销毁画笔
MyDrawText(mdc, L"神奇的分层窗口", 25, 8, 0, 0, true, ARGB(254,0,0,0));//画文字,注意透明度用254
GdipLoadImageFromFile(L"D:\\1.png", &image);//创建Image对象
GdipDrawImageRect(graphics, image, 3, 3, 20, 20);//画图片
GdipDisposeImage(image);//销毁图片,释放资源
GdipCreateSolidFill(ARGB(255, 255, 255, 255), &brush);
GdipFillRectangle(graphics, brush, 5, 30, 490, 465);//这是画里面的背景
GdipDeleteBrush(brush);
GdipDeleteGraphics(graphics);//销毁Graphics对象
POINT point; point.x = 0; point.y = 0;//更新分层窗口
SIZE size; size.cx = 500; size.cy = 500;
BLENDFUNCTION blend;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = AC_SRC_ALPHA;
blend.SourceConstantAlpha = 255;
UpdateLayeredWindow(hwnd1, NULL, NULL, &size, mdc, &point, 0, &blend, ULW_ALPHA);//。。。。。。更新分层窗口
//显示、更新窗口
ShowWindow(hwnd1, nCmdShow);
UpdateWindow(hwnd1);
//消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//GDI+关闭
GdiplusShutdown(token);//可以把这个写在消息循环后面,程序退出就销毁,或者在不需要GDI+时调用,比如GDI+窗口的WM_DESTROY消息里调用
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg){
case WM_CREATE:
return 0;
break;
case WM_DESTROY://窗口已经销毁
PostQuitMessage(0);//退出消息循环,结束应用程序
return 0;
break;
case WM_LBUTTONDOWN:
//让无边框窗口能够拖动(在窗口客户区拖动)
PostMessage(hwnd, WM_SYSCOMMAND, 61458, 0);
break;
default:
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);//其他消息交给系统处理
}
这里要说明一下:
1。UpdateLayeredWindow以后就不能在WM_PAINT里绘图了,但是WM_PAINT消息依旧响应。
2。需要作图时,应该先把图画到内存DC里,然后再调用UpdateLayeredWindow
3。或者在这个窗口上面再加一个窗口,在WM_MOVING里面控制另一个窗口移动,要不然分层窗口上是不能放控件的,只能自己一个个画上去