本文关注点 不再截屏 而是截屏选取工具
1 首先肯定是个透明窗口,且置顶 并且是工具窗口(任务栏不显示窗口图标)
窗口样式
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;
}
通过,设置透明界面、鼠标实时形状、鼠标移动拉伸操作,就完成了选取窗口的主要功能