GdiplusFlat(10)自绘Edit Control边框的实现(附Edit Control垂直居中问题)

本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处: http://blog.csdn.net/zuishikonghuan/article/details/47419731

在上几篇中,我们说到了通过GdipCreateFromHDC函数将HDC(设备上下文句柄)装换成GDI+的Graphics对象,讲到了画笔和画刷的使用,演示了何利用GDI+Flat来画图片和画文字,讲到了双缓冲绘图和DC复制,并说了用GdiplusFlat来绘制按钮的两种方法。

这篇我们来说说自绘Edit Control边框的实现。

还是和以前一样,我们必须自己声明GDI+Flat函数,自己定义GDI+Flat的数据结构。自己动手,丰衣足食。~~

首先说一说Edit Control垂直居中的问题。

正常情况下,即使是单行Edit,也不能垂直居中(左图):

GdiplusFlat(10)自绘Edit Control边框的实现(附Edit Control垂直居中问题)_第1张图片GdiplusFlat(10)自绘Edit Control边框的实现(附Edit Control垂直居中问题)_第2张图片

经过优化以后,就可以垂直居中了,如右图。

具体代码如下,edit是Edit Control的句柄。

首先需要给Edit Control添加ES_MULTILINE多行风格(具体见我以前一篇关于Edit Control的博文)

TEXTMETRIC tm;
GetTextMetrics(GetDC(edit), &tm);//获取字体信息
RECT rect;
GetClientRect(edit, &rect);//获取edit矩形
OffsetRect(&rect, 0, (100 - tm.tmHeight)/2);//移动矩形
rect.bottom = rect.top + tm.tmHeight;//设置RECT的底边坐标
SendMessage(edit, EM_SETRECT, 0, (LPARAM)&rect);//设置矩形

可能有人会不明白rect.bottom = rect.top + tm.tmHeight;这一句是干嘛用的,其实,如果Edit Control比较高,不添加这一句虽然文字也居中了,但是不要忘了我们添加了ES_MULTILINE风格,虽然没有接受回车的风格,但是竟然可以换行直到控件底部,这是不能容忍的,所以这一句把矩形限制在了这一行,只要我们不加ES_AUTOVSCROLL风格,就不用再担心这个问题了。

好了,先来看看效果:

(1)

(2)

还不错吧。。完整源码:

(注意:自绘Edit Control边框可以但是不需要使用双缓冲绘图解决,而且使用双缓冲反而会损失效率,至于说原因我就不用说了吧。双缓冲不是万能的,它能解决很多问题,但不一定所有的情况都适合)

(1)源码:

#include "stdafx.h"
#include <gdiplus.h>
#include <gdiplusflat.h>
#pragma comment(lib,"gdiplus.lib")//very important

#include <windows.h>
#include <windowsx.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")

#pragma comment(lib,"Msimg32.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* linebrush;
int* image;
//HDC mdc;

//*************************************************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

WNDCLASS wc;
const TCHAR* AppName = TEXT("MyWindowClass1");
HWND hwnd1;

BOOL Track;
WNDPROC lastproc;

HWND edit;

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(NULL, AppName, TEXT("窗口标题"), style, 50, 50, 500, 500, 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);

	//显示、更新窗口
	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 Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int xPos, yPos;
	switch (uMsg){
	case WM_NCPAINT:
		HDC hdc;
		int graphics;
		hdc = GetWindowDC(hwnd);//获取完整窗口(包括非客户区)DC句柄
		GdipCreateFromHDC(hdc, &graphics);//创建Graphics对象
		GdipCreatePen1(ARGB(255, 79, 202, 255), 3, 2, &pen);//创建画笔
		GdipDrawRectangle(graphics, pen, 0, 0, 120, 20);//画矩形
		GdipDeletePen(pen);//销毁画笔
		ReleaseDC(hwnd, hdc);
		return 0;
		break;
	}
	return CallWindowProc(lastproc, hwnd, uMsg, wParam, lParam);//让原来的窗口回调函数处理其他消息
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg){
	case WM_CREATE:
		//mdc = CreateCompatibleDC(0);
		//BITMAPINFO bitmapinfo;
		//RtlZeroMemory(&bitmapinfo, sizeof(BITMAPINFO));

		//bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		//bitmapinfo.bmiHeader.biWidth = 120;
		//bitmapinfo.bmiHeader.biHeight = 25;
		//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);

		edit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"), TEXT("Edit Control"), WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL | ES_MULTILINE, 20, 20, 121, 21, hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
		SendMessage(edit, WM_SETFONT, (WPARAM)GetStockObject(17), 0);
		lastproc = (WNDPROC)SetWindowLongPtr(edit, GWL_WNDPROC, (LONG)&Proc);//子类化

		TEXTMETRIC tm;
		GetTextMetrics(GetDC(edit), &tm);//获取字体信息
		RECT rect;
		GetClientRect(edit, &rect);//获取edit矩形
		OffsetRect(&rect, 0, (21 - tm.tmHeight) / 2);//移动矩形
		rect.bottom = rect.top + tm.tmHeight;//设置RECT的底边坐标
		SendMessage(edit, EM_SETRECT, 0, (LPARAM)&rect);//设置矩形
		return 0;
		break;
	case WM_DESTROY://窗口已经销毁
		//DeleteDC(mdc);
		PostQuitMessage(0);//退出消息循环,结束应用程序
		return 0;
		break;
	case WM_LBUTTONDOWN:
		//让无边框窗口能够拖动(在窗口客户区拖动)
		PostMessage(hwnd, WM_SYSCOMMAND, 61458, 0);
		break;
	default:
		break;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);//其他消息交给系统处理
}


(2)源码:

#include "stdafx.h"
#include <gdiplus.h>
#include <gdiplusflat.h>
#pragma comment(lib,"gdiplus.lib")//very important

#include <windows.h>
#include <windowsx.h>
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")

#pragma comment(lib,"Msimg32.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* linebrush;
int* image;

//HDC mdc;

//*************************************************************
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

WNDCLASS wc;
const TCHAR* AppName = TEXT("MyWindowClass1");
HWND hwnd1;

BOOL Track;
WNDPROC lastproc;

HWND edit;

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(NULL, AppName, TEXT("窗口标题"), style, 50, 50, 500, 500, 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);

	//显示、更新窗口
	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;

}

void WINAPI draw(HDC hdc, unsigned int argb){
	int graphics;
	GdipCreateFromHDC(hdc, &graphics);//创建Graphics对象
	GdipCreatePen1(argb, 3, 2, &pen);//创建画笔
	GdipDrawRectangle(graphics, pen, 0, 0, 120, 20);//画矩形
	GdipDeletePen(pen);//销毁画笔
}

LRESULT CALLBACK Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	int xPos, yPos;
	switch (uMsg){
	case WM_NCPAINT:
		HDC hdc;
		hdc = GetWindowDC(hwnd);//获取完整窗口(包括非客户区)DC句柄
		draw(hdc, ARGB(255, 79, 202, 255));
		ReleaseDC(hwnd, hdc);
		return 0;
		break;
	case WM_SETFOCUS://获取焦点
		hdc = GetWindowDC(hwnd);//获取完整窗口(包括非客户区)DC句柄
		draw(hdc, ARGB(255, 163, 73, 164));
		ReleaseDC(hwnd, hdc);
		break;
	case WM_KILLFOCUS://失去焦点
		hdc = GetWindowDC(hwnd);//获取完整窗口(包括非客户区)DC句柄
		draw(hdc, ARGB(255, 79, 202, 255));
		ReleaseDC(hwnd, hdc);
		break;
	}
	return CallWindowProc(lastproc, hwnd, uMsg, wParam, lParam);//让原来的窗口回调函数处理其他消息
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg){
	case WM_CREATE:
		//mdc = CreateCompatibleDC(0);
		//BITMAPINFO bitmapinfo;
		//RtlZeroMemory(&bitmapinfo, sizeof(BITMAPINFO));

		//bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		//bitmapinfo.bmiHeader.biWidth = 120;
		//bitmapinfo.bmiHeader.biHeight = 25;
		//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);

		edit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"), TEXT("Edit Control"), WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL | ES_MULTILINE, 20, 20, 121, 21, hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
		SendMessage(edit, WM_SETFONT, (WPARAM)GetStockObject(17), 0);
		lastproc = (WNDPROC)SetWindowLongPtr(edit, GWL_WNDPROC, (LONG)&Proc);

		TEXTMETRIC tm;
		GetTextMetrics(GetDC(edit), &tm);//获取字体信息
		RECT rect;
		GetClientRect(edit, &rect);//获取edit矩形
		OffsetRect(&rect, 0, (21 - tm.tmHeight) / 2);//移动矩形
		rect.bottom = rect.top + tm.tmHeight;//设置RECT的底边坐标
		SendMessage(edit, EM_SETRECT, 0, (LPARAM)&rect);//设置矩形

		edit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"), TEXT("Edit Control"), WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL | ES_MULTILINE, 20, 60, 121, 21, hwnd, (HMENU)2, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
		SendMessage(edit, WM_SETFONT, (WPARAM)GetStockObject(17), 0);
		return 0;
		break;
	case WM_DESTROY://窗口已经销毁
		DeleteDC(mdc);
		PostQuitMessage(0);//退出消息循环,结束应用程序
		return 0;
		break;
	case WM_LBUTTONDOWN:
		//让无边框窗口能够拖动(在窗口客户区拖动)
		PostMessage(hwnd, WM_SYSCOMMAND, 61458, 0);
		break;
	default:
		break;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);//其他消息交给系统处理
}





你可能感兴趣的:(Win32,windows,api,GDI+,gdiplus)