duilib 实现截屏选取功能分析

☆樱花仙子☆ 提交于 2020-08-15 11:05:02

 

 

本文关注点 不再截屏 而是截屏选取工具

 

1 首先肯定是个透明窗口,且置顶 并且是工具窗口(任务栏不显示窗口图标)

窗口样式

<?xml version="1.0" encoding="utf-8"?>
<Window shadowattached="false">
    <Box >
		<VBox name="track_box" margin="200,200,200,200" bkimage="file='screen_border.png' corner='30,30,30,30'" >
			<HBox height="auto" margin="15,15,15,0" >
				<Control name="track_NW" width="17" height="17" bkimage="screen_point.png" />
				<Control />
				<Control name="track_T" width="17" height="17" bkimage="screen_point.png" />
				<Control />
				<Control name="track_NE" width="17" height="17" bkimage="screen_point.png" />
			</HBox>
			<Control />
			<HBox height="auto" margin="15,0,15,0" >
				<Control name="track_L" width="17" height="17" bkimage="screen_point.png" />
				<Control />
				<Control name="track_R" width="17" height="17" bkimage="screen_point.png" />
			</HBox>
			<Control />
			<HBox height="auto" margin="15,0,15,15" >
				<Control name="track_SW" width="17" height="17" bkimage="screen_point.png" />
				<Control />
				<Control name="track_B" width="17" height="17" bkimage="screen_point.png" />
				<Control />
				<Control name="track_SE" width="17" height="17" bkimage="screen_point.png" />
			</HBox>
		</VBox>
    </Box>
</Window>

 

 

screen_border.png

 

screen_point.png

 

在窗口初始化过程中,将窗口置顶

void ScreenCaptureTool::InitWindow()
{
	m_pRoot->AttachBubbledEvent(ui::kEventClick, nbase::Bind(&ScreenCaptureTool::OnClicked, this, std::placeholders::_1));

	track_box_ = (ui::Box*)FindControl(L"track_box");
	track_NW_ = FindControl(L"track_NW");
	track_T_ = FindControl(L"track_T");
	track_NE_ = FindControl(L"track_NE");
	track_L_ = FindControl(L"track_L");
	track_R_ = FindControl(L"track_R");
	track_SW_ = FindControl(L"track_SW");
	track_B_ = FindControl(L"track_B");
	track_SE_ = FindControl(L"track_SE");

	RECT rcWindow;

	screen_width_ = GetSystemMetrics(SM_CXVIRTUALSCREEN);
	screen_height_ = GetSystemMetrics(SM_CYVIRTUALSCREEN);

	screen_x_ = GetSystemMetrics(SM_XVIRTUALSCREEN);
	screen_y_ = GetSystemMetrics(SM_YVIRTUALSCREEN);

	rcWindow.left = screen_x_;
	rcWindow.top = screen_y_;
	rcWindow.right = screen_x_ + screen_width_;
	rcWindow.bottom = screen_y_ + screen_height_;
	track_rect_.left = 100;
	track_rect_.top = 100;
	track_rect_.right = screen_width_ - 100;
	track_rect_.bottom = screen_height_ - 100;

	POINT pt = { 0, 0 };
	ResizeTrackRect(pt);

	LONG windowLongEx = GetWindowLong(m_hWnd, GWL_EXSTYLE);

	SetWindowLong(m_hWnd, GWL_EXSTYLE, windowLongEx | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);

	SetPos(ui::UiRect(screen_x_, screen_y_, screen_x_ + screen_width_, screen_y_ + screen_height_), false, SWP_NOACTIVATE, HWND_TOPMOST);

}

 

这样子,初始化后,可以显示选取窗口了,但是还没添加移动 拖拽功能

 

2 鼠标在不同位置显示不同状态 比如 移动状态 比如拉伸状态

 

  定义一些 枚举状态  ,表示鼠标当前的操作

  表示 选取操作时,对应的一些行为,比如移动SIZEALL  向左拉伸SIZELEFT 拉伸SIZENE

          NOTRACK 表示 不跟踪鼠标,不进行操作

enum
{
	NOTRACK = 0,
	SIZEALL,
	SIZELEFT ,
	SIZERIGHT,
	SIZETOP ,
	SIZEBOTTOM ,
	SIZENE,
	SIZENW ,
	SIZESE,
	SIZESW ,
}
void ScreenCaptureTool::SetHitTestCursor(int hit_type)
{
	HCURSOR cursor = LoadCursor(NULL, IDC_ARROW);
	switch (hit_type)
	{
	case SIZEALL:		cursor = LoadCursor(NULL, IDC_SIZEALL); break;
	case SIZETOP:
	case SIZEBOTTOM:	cursor = LoadCursor(NULL, IDC_SIZENS); break;
	case SIZELEFT:
	case SIZERIGHT:		cursor = LoadCursor(NULL, IDC_SIZEWE); break;
	case SIZESE:
	case SIZENW:		cursor = LoadCursor(NULL, IDC_SIZENWSE); break;
	case SIZESW:
	case SIZENE:		cursor = LoadCursor(NULL, IDC_SIZENESW); break;
	}
	SetCursor(cursor);
}

根据鼠标所在位置,判断鼠标应该呈现的形状

int ScreenCaptureTool::CheckPtType(POINT pt)
{
	int type = NOTRACK;
	{
		ui::UiRect rect = track_box_->GetPos();
		if (PtInRect(&rect, pt))
		{
			type = SIZEALL;
			if (PtInRect(&track_NW_->GetPos(), pt))
			{
				type = SIZENW;
			}
			else if (PtInRect(&track_T_->GetPos(), pt))
			{
				type = SIZETOP;
			}
			else if (PtInRect(&track_NE_->GetPos(), pt))
			{
				type = SIZENE;
			}
			else if (PtInRect(&track_L_->GetPos(), pt))
			{
				type = SIZELEFT;
			}
			else if (PtInRect(&track_R_->GetPos(), pt))
			{
				type = SIZERIGHT;
			}
			else if (PtInRect(&track_SW_->GetPos(), pt))
			{
				type = SIZESW;
			}
			else if (PtInRect(&track_B_->GetPos(), pt))
			{
				type = SIZEBOTTOM;
			}
			else if (PtInRect(&track_SE_->GetPos(), pt))
			{
				type = SIZESE;
			}
		}
	}
	return type;
}

 

在鼠标移动时,设置不同的鼠标形状

//不跟踪时,根据鼠标位置,设置不同形状

//跟踪时,根据当前操作,设置选取窗口新位置

LRESULT ScreenCaptureTool::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	POINT pt;
	pt.x = GET_X_LPARAM(lParam);
	pt.y = GET_Y_LPARAM(lParam);
	if (track_state_ != NOTRACK)
	{
		POINT pt_move;
		pt_move.x = pt.x - point_offset_.x;
		pt_move.y = pt.y - point_offset_.y;
		ResizeTrackRect(pt_move);
		point_offset_.x += pt_move.x;
		point_offset_.y += pt_move.y;
		bHandled = FALSE;
		SetHitTestCursor(track_state_);
	}
	else
	{
		int type = CheckPtType(pt);
		if (type != NOTRACK)
		{
			SetHitTestCursor(type);
		}
	}
	return 0;
}

3 鼠标操作 比如进行移动 拉伸

 主要是鼠标按下 移动 弹起三个事件的响应

 1)鼠标按下时,记录当前鼠标位置

                            记录当前鼠标要进行的是何操作

LRESULT ScreenCaptureTool::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	point_offset_.x = GET_X_LPARAM(lParam);
	point_offset_.y = GET_Y_LPARAM(lParam);
	int type = CheckPtType(point_offset_);
	if (type != NOTRACK)
	{
		track_state_ = type;
		bHandled = FALSE;
		SetHitTestCursor(track_state_);
	}
	return 0;
}

 

2)鼠标移动,如果不进行任何鼠标操作,则只设置鼠标对应形状,

                        如果进行鼠标操作,则根据操作类型和位置偏差 重置选取窗口位置

 

LRESULT ScreenCaptureTool::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	POINT pt;
	pt.x = GET_X_LPARAM(lParam);
	pt.y = GET_Y_LPARAM(lParam);
	if (track_state_ != NOTRACK)
	{
		POINT pt_move;
		pt_move.x = pt.x - point_offset_.x;
		pt_move.y = pt.y - point_offset_.y;
		ResizeTrackRect(pt_move);
		point_offset_.x += pt_move.x;
		point_offset_.y += pt_move.y;
		bHandled = FALSE;
		SetHitTestCursor(track_state_);
	}
	else
	{
		int type = CheckPtType(pt);
		if (type != NOTRACK)
		{
			SetHitTestCursor(type);
		}
	}
	return 0;
}

 

移动时,根据鼠标按下时要进行的操作,和鼠标按下时的位置,与当前移动时的位置偏差,重置选取窗口位置

		POINT pt_move;
		pt_move.x = pt.x - point_offset_.x;
		pt_move.y = pt.y - point_offset_.y;
		ResizeTrackRect(pt_move);
		point_offset_.x += pt_move.x;
		point_offset_.y += pt_move.y;

 

 

void ScreenCaptureTool::ResizeTrackRect(POINT& pt)
{
	if (track_state_ == SIZEALL)
	{
		::OffsetRect(&track_rect_, pt.x, pt.y);
	} 
	else
	{
		if (track_state_ == SIZENW || track_state_ == SIZESW || track_state_ == SIZELEFT)
		{
			if (track_rect_.right - track_rect_.left - pt.x < 100)
			{
				pt.x = track_rect_.right - 100 - track_rect_.left;
				track_rect_.left = track_rect_.right - 100;
			} 
			else
			{
				track_rect_.left += pt.x;
			}
		}
		else if (track_state_ == SIZENE || track_state_ == SIZESE || track_state_ == SIZERIGHT)
		{
			if (track_rect_.right - track_rect_.left + pt.x < 100)
			{
				pt.x = track_rect_.left + 100 - track_rect_.right;
				track_rect_.right = track_rect_.left + 100;
			}
			else
			{
				track_rect_.right += pt.x;
			}
		}
		if (track_state_ == SIZENW || track_state_ == SIZENE || track_state_ == SIZETOP)
		{
			if (track_rect_.bottom - track_rect_.top - pt.y < 100)
			{
				pt.y = track_rect_.bottom - 100 - track_rect_.top;
				track_rect_.top = track_rect_.bottom - 100;
			}
			else
			{
				track_rect_.top += pt.y;
			}
		}
		else if (track_state_ == SIZESW || track_state_ == SIZESE || track_state_ == SIZEBOTTOM)
		{
			if (track_rect_.bottom - track_rect_.top + pt.y < 100)
			{
				pt.y = track_rect_.top + 100 - track_rect_.bottom;
				track_rect_.bottom = track_rect_.top + 100;
			}
			else
			{
				track_rect_.bottom += pt.y;
			}
		}
	}
	ui::UiRect rect_box = track_rect_;
	{
		nbase::NAutoLock auto_lock(&lock_);
		capture_.SetCutMode(true, track_rect_);
	}
	rect_box.Inflate(BORDER_SIZE, BORDER_SIZE);
	rect_box.right = screen_width_ - rect_box.right;
	rect_box.bottom = screen_height_ - rect_box.bottom;
	track_box_->SetMargin(rect_box);
}

 

3)鼠标弹起时,鼠标操作完成,重置鼠标操作状态为无操作

LRESULT ScreenCaptureTool::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	if (track_state_ != NOTRACK)
	{
		bHandled = FALSE;
		track_state_ = NOTRACK;
		SetHitTestCursor(track_state_);
	}
	return 0;
}

 

 

通过,设置透明界面、鼠标实时形状、鼠标移动拉伸操作,就完成了选取窗口的主要功能

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!