使用GDI绘制一个类似进度条的控件(1)

最近我像学习下图形的绘制,自己是学C/C++的,所以我就把目光放在了GDI上面。基本的win32编程和基本的GDI绘制我已经了解,接下来就进行实践环节。

最简单的GDI绘制图形那就是矩形了,所以我用基本的矩形来绘制进度条,今天写的是最基本的,之后我会把相关操作写成类,代码如下(代码里面有很详细的注释,所以我就不过多介绍了)

#include <windows.h>
#include <atlstr.h> //因为wsprintf不能进行浮点型转换,所以加上这个用CString


//自绘一个进度条

//定义一个定时器宏
#define ID_TIMER 1

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int cxClient, cyClient;  //客户区的高和宽

RECT rect;



int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
	static TCHAR szAppName[] = TEXT("ProgressBar");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

	wndclass.style = CS_HREDRAW | CS_VREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = LoadIcon(NULL, IDI_INFORMATION);
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName = NULL;
	wndclass.lpszClassName = szAppName;

	RegisterClass(&wndclass);

	hwnd = CreateWindow(szAppName, L"自绘一个进度条",
		WS_OVERLAPPEDWINDOW,
		100, 200, 800, 600, NULL, NULL, hInstance, NULL
	);
	ShowWindow(hwnd, nShowCmd);
	UpdateWindow(hwnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}


	return msg.wParam;
}

void RenderProgressBar(HWND hwnd)   //重绘进度条
{
	RECT RenderRect;
	RenderRect.left = rect.left;
	RenderRect.top = rect.top;
	RenderRect.right = cxClient;
	RenderRect.bottom = rect.bottom;
	InvalidateRect(hwnd, &RenderRect, TRUE); //只是让进度条和显示文字的矩形无效就行了

}


LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdcClient;
	PAINTSTRUCT ps;

	//画笔画刷
	HBRUSH hBrush;
	HPEN  hPen,hOldPen;
	TCHAR temp[40];

	static float right;
	float tempD;
	CString str;
	

	int x;

	switch (message)
	{
	case WM_TIMER:   //定时器消息
		RenderProgressBar(hwnd);
		return 0;
	case WM_CREATE:
		SetTimer(hwnd, ID_TIMER, 100, NULL); //每隔10秒触发
		return 0;
	case WM_SIZE:
		cxClient = LOWORD(lParam); //获取客户区的大小
		cyClient = HIWORD(lParam);
		rect.left = cxClient / 2 - 300;
		rect.top = cyClient / 2;
		rect.right = cxClient / 2 - 300;
		rect.bottom = cyClient / 2 + 50;
		right = cxClient / 2 + 300;
		return 0;
	case WM_PAINT:

		hPen = CreatePen(PS_NULL, 0, 0);  //创建一个新画笔(这个画笔在绘制矩形的时候是没有边框的)
		hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);  //取得黑色的画刷

		hdcClient = BeginPaint(hwnd, &ps);
		hOldPen = (HPEN)SelectObject(hdcClient, hPen);  //取得原来的画笔并将自己创建的画笔放入hdc中
		//创建一个长600,宽50的矩形,位置在客户区中央
		Rectangle(hdcClient, cxClient / 2-300, cyClient / 2, cxClient / 2 + 300, cyClient / 2 + 50);

		
		if (rect.right <= right) //如果还没到头
		{
			

			FillRect(hdcClient, &rect, hBrush);

			tempD = (float)(rect.right - rect.left) / 600.0;

			str.Format(TEXT("进度:%.2f%%"), tempD*100.0);
			TextOut(hdcClient, right, rect.top + 25, temp, wsprintf(temp, L"%s", str.GetBuffer(str.GetLength())));
			rect.right++;
		}
		
		if (rect.right > right)//已经100%了
		{
			RECT tempRect;
			tempRect.left = rect.left;
			tempRect.top = rect.top;
			tempRect.right = rect.right-1;
			tempRect.bottom = rect.bottom;
			FillRect(hdcClient, &tempRect, hBrush);
			TextOut(hdcClient, right, rect.top + 25, temp, wsprintf(temp, L"进度:%d.00%%", 100));
		}
			

		DeleteObject(hPen);
		SelectObject(hdcClient, hOldPen);//将原来的画笔还回去
		DeleteObject(hBrush);
		EndPaint(hwnd, &ps);
		return 0;
	case WM_DESTROY:
		KillTimer(hwnd, ID_TIMER);
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, message, wParam, lParam);
}


运行如下:

 基本的进度条就这样了,之后我会将它进行改进,改成类的样子,这样的话可以自己设置宽高和进度条的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 C# 中,你可以使用 GDI+ 绘制一个管道控件并添加阀门,具体步骤如下: 1. 新建一个自定义控件类,继承 `System.Windows.Forms.Control`。 2. 重写 `OnPaint` 方法,在其中使用 GDI+ 绘制管道和阀门。 ```csharp protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; Pen pen = new Pen(Color.Black, 2); SolidBrush brush = new SolidBrush(Color.Gray); // 绘制管道 g.FillRectangle(brush, 0, 0, this.Width, this.Height); g.DrawRectangle(pen, 0, 0, this.Width - 1, this.Height - 1); // 绘制阀门 if (valveOpen) { brush.Color = Color.Red; g.FillEllipse(brush, this.Width / 2 - 10, this.Height / 2 - 10, 20, 20); } else { brush.Color = Color.Gray; g.FillEllipse(brush, this.Width / 2 - 10, this.Height / 2 - 10, 20, 20); pen.Color = Color.White; g.DrawLine(pen, this.Width / 2, this.Height / 2 - 10, this.Width / 2, this.Height / 2 + 10); } } ``` 其中,`valveOpen` 表示阀门是否打开。 3. 添加一个公共属性 `ValveOpen`,用于控制阀门的打开和关闭。 ```csharp private bool valveOpen = false; public bool ValveOpen { get { return valveOpen; } set { valveOpen = value; this.Invalidate(); } } ``` 4. 在控件的构造函数中添加鼠标点击事件,用于控制阀门的打开和关闭。 ```csharp this.MouseDown += (s, e) => { this.ValveOpen = !this.ValveOpen; }; ``` 这里使用了 Lambda 表达式注册了鼠标点击事件。 现在,你可以在窗体中使用此自定义控件,并通过设置 `ValveOpen` 属性来控制阀门的打开和关闭,从而实现管道控件的设计。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DreamXY12

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值