鼠标(4)

本文介绍了一个改进的程序,允许用户在客户区任意画矩形,并在释放鼠标按钮时自动填充矩形。通过使用SetCapture和ReleaseCapture函数解决了鼠标超出窗口边界的限制。

看看这个简单的程序(还需要改进)

#include<windows.h>
#include<windowsx.h>
#define DIVISIONS 5

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

int WINAPI WinMain(
  HINSTANCE hInstance,      // handle to current instance
  HINSTANCE hPrevInstance,  // handle to previous instance
  LPSTR lpCmdLine,          // command line
  int nCmdShow              // show state
)
{
	static TCHAR szAppName[]=TEXT("leidemingzi");
	HWND hwnd;
	MSG msg;
	WNDCLASS wndclass;

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

	if(!RegisterClass(&wndclass))
	{
		MessageBox(NULL,TEXT("the program require window NT"),TEXT("just tip"),MB_ICONERROR);
		return 0;
	}

	hwnd=CreateWindow(
	   szAppName,  // registered class name
	  TEXT("this is title"), // window name
	  WS_OVERLAPPEDWINDOW,        // window style
	  CW_USEDEFAULT,                // horizontal position of window
	  CW_USEDEFAULT,                // vertical position of window
	  CW_USEDEFAULT,           // window width
	  CW_USEDEFAULT,          // window height
	  NULL,      // handle to parent or owner window
	  NULL,          // menu handle or child identifier
	  hInstance,  // handle to application instance
	  NULL        // window-creation data
);

	ShowWindow(hwnd,nCmdShow);
	UpdateWindow(hwnd);

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

	return msg.wParam;
}

void DrawBoxOutLine(HWND hwnd,POINT ptBeg,POINT ptEnd)//定义个画矩形的函数
{
	HDC hdc;
	hdc=GetDC(hwnd);

	SetROP2(hdc,R2_NOT);//设置画笔
	SelectObject(hdc,GetStockObject(NULL_BRUSH));//不使用画刷
	Rectangle(hdc,ptBeg.x,ptBeg.y,ptEnd.x,ptEnd.y);//画矩形

	ReleaseDC(hwnd,hdc);
}

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
)
{
	static BOOL fBlocking,fValidBox;
	static POINT ptBeg,ptEnd,ptBoxBeg,ptBoxEnd;
	HDC hdc;
	PAINTSTRUCT ps;

	switch(uMsg)
	{
		case WM_LBUTTONDOWN:
			ptBeg.x=ptEnd.x=GET_X_LPARAM(lParam);//获取开始坐标
			ptBeg.y=ptEnd.y=GET_Y_LPARAM(lParam);

			DrawBoxOutLine(hwnd,ptBeg,ptEnd);//画矩形,其实不要这句也行

			SetCursor(LoadCursor(NULL,IDC_CROSS));//把鼠标设置成为十字形状

			fBlocking=TRUE;//设标志为真
			return 0;

		case WM_MOUSEMOVE:
			if(fBlocking)//判断是否按下鼠标左键
			{
				SetCursor(LoadCursor(NULL,IDC_CROSS));//设置鼠标为十字形状

				DrawBoxOutLine(hwnd,ptBeg,ptEnd);//画矩形

				ptEnd.x=GET_X_LPARAM(lParam);//不断的获取移动后的坐标(矩形的右下方坐标)
				ptEnd.y=GET_Y_LPARAM(lParam);

				DrawBoxOutLine(hwnd,ptBeg,ptEnd);//不断的画矩形
			}
			return 0;

		case WM_LBUTTONUP:
			if(fBlocking)//判断是否先有按下鼠标
			{
				DrawBoxOutLine(hwnd,ptBeg,ptEnd);//画出矩形

				ptBoxBeg=ptBeg;
				ptBoxEnd.x=GET_X_LPARAM(lParam);//获取终点坐标
				ptBoxEnd.y=GET_Y_LPARAM(lParam);

				SetCursor(LoadCursor(NULL,IDC_ARROW));//设置鼠标为正常状态

				fBlocking=FALSE;//设置标志为假
				fValidBox=TRUE;

				InvalidateRect(hwnd,NULL,TRUE);//使矩形区域无效,触发WM_PAINT事件

			}
			return 0;

		case WM_CHAR:
			if(fBlocking & (wParam=='\x1B'))//是否为ESC键
			{
				DrawBoxOutLine(hwnd,ptBeg,ptEnd);
				SetCursor(LoadCursor(NULL,IDC_ARROW));

				fBlocking=FALSE;//设置标志为假
			}
			return 0;

		case WM_PAINT:
			hdc=BeginPaint(hwnd,&ps);
			if(fValidBox)
			{
				SelectObject(hdc,GetStockObject(BLACK_BRUSH));//设置黑色画刷
				Rectangle(hdc,ptBoxBeg.x,ptBoxBeg.y,ptBoxEnd.x,ptBoxEnd.y);//填充矩形
			}

			if(fBlocking)
			{
				SetROP2(hdc,R2_NOT);
				SelectObject(hdc,GetStockObject(NULL_BRUSH));
				Rectangle(hdc,ptBeg.x,ptBeg.y,ptEnd.x,ptEnd.y);
			}

			EndPaint(hwnd,&ps);
			return 0;

		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}


在客户区可以任意画矩形,然后自动用黑色画刷去填充,但是鼠标不能超过窗口边界,否则,你自己调试吧

下面这个是改进版的:只在上面的函数增加了三行.

使用了SetCapture和ReleaseCapture函数

#include <windows.h>
#include <windowsx.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("BlokOut2") ;
     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_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Mouse Button & Capture Demo"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

void DrawBoxOutline (HWND hwnd, POINT ptBeg, POINT ptEnd)
{
     HDC hdc ;
     
     hdc = GetDC (hwnd) ;
     
     SetROP2 (hdc, R2_NOT) ;
     SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
     Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
     
     ReleaseDC (hwnd, hdc) ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static BOOL  fBlocking, fValidBox ;
     static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd ;
     HDC          hdc ;
     PAINTSTRUCT  ps ;
     
     switch (message)
     {
     case WM_LBUTTONDOWN :
          ptBeg.x = ptEnd.x = GET_X_LPARAM (lParam) ;
          ptBeg.y = ptEnd.y = GET_Y_LPARAM (lParam) ;
          
          DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
          
          SetCapture (hwnd) ;//新增加的
          SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
          
          fBlocking = TRUE ;
          return 0 ;
          
     case WM_MOUSEMOVE :
          if (fBlocking)
          {
               SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
               
               DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
               
               ptEnd.x = GET_X_LPARAM (lParam) ;
               ptEnd.y = GET_Y_LPARAM (lParam) ;
               
               DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
          }
          return 0 ;
          
     case WM_LBUTTONUP :
          if (fBlocking)
          {
               DrawBoxOutline (hwnd, ptBeg, ptEnd) ;
               
               ptBoxBeg   = ptBeg ;
               ptBoxEnd.x = GET_X_LPARAM (lParam) ;
               ptBoxEnd.y = GET_Y_LPARAM (lParam) ;
               
               ReleaseCapture () ;//新增加的
               SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
               
               fBlocking = FALSE ;
               fValidBox  = TRUE ;
               
               InvalidateRect (hwnd, NULL, TRUE) ;
          }
          return 0 ;
          
     case WM_CHAR :
          if (fBlocking & (wParam == '\x1B'))     // i.e., Escape
          {
               DrawBoxOutline (hwnd, ptBeg, ptEnd) ;

               ReleaseCapture () ;//新增加的
               SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
               
               fBlocking = FALSE ;
          }
          return 0 ;
          
     case WM_PAINT :
          hdc = BeginPaint (hwnd, &ps) ;
          
          if (fValidBox)
          {
               SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ;
               Rectangle (hdc, ptBoxBeg.x, ptBoxBeg.y,
                               ptBoxEnd.x, ptBoxEnd.y) ;
          }
          
          if (fBlocking)
          {
               SetROP2 (hdc, R2_NOT) ;
               SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
               Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
          }
          
          EndPaint (hwnd, &ps) ;
          return 0 ;
          
     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}



可以处理鼠标超过边界的问题了:

采用PyQt5框架与Python编程语言构建图书信息管理平台 本项目基于Python编程环境,结合PyQt5图形界面开发库,设计实现了一套完整的图书信息管理解决方案。该系统主要面向图书馆、书店等机构的日常运营需求,通过模块化设计实现了图书信息的标准化管理流程。 系统架构采用典型的三层设计模式,包含数据存储层、业务逻辑层和用户界面层。数据持久化方案支持SQLite轻量级数据库与MySQL企业级数据库的双重配置选项,通过统一的数据库操作接口实现数据存取隔离。在数据建模方面,设计了包含图书基本信息、读者档案、借阅记录等核心数据实体,各实体间通过主外键约束建立关联关系。 核心功能模块包含六大子系统: 1. 图书编目管理:支持国际标准书号、中国图书馆分类法等专业元数据的规范化著录,提供批量导入与单条录入两种数据采集方式 2. 库存动态监控:实时追踪在架数量、借出状态、预约队列等流通指标,设置库存预警阈值自动提醒补货 3. 读者服务管理:建立完整的读者信用评价体系,记录借阅历史与违规行为,实施差异化借阅权限管理 4. 流通业务处理:涵盖借书登记、归还处理、续借申请、逾期计算等标准业务流程,支持射频识别技术设备集成 5. 统计报表生成:按日/月/年周期自动生成流通统计、热门图书排行、读者活跃度等多维度分析图表 6. 系统维护配置:提供用户权限分级管理、数据备份恢复、操作日志审计等管理功能 在技术实现层面,界面设计遵循Material Design设计规范,采用QSS样式表实现视觉定制化。通过信号槽机制实现前后端数据双向绑定,运用多线程处理技术保障界面响应流畅度。数据验证机制包含前端格式校验与后端业务规则双重保障,关键操作均设有二次确认流程。 该系统适用于中小型图书管理场景,通过可扩展的插件架构支持功能模块的灵活组合。开发过程中特别注重代码的可维护性,采用面向对象编程范式实现高内聚低耦合的组件设计,为后续功能迭代奠定技术基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值