Qt 模仿QQ截图 动态吸附直线

最近在学Qt。学东西怎么能不动手。

就写了些小程序。看QQ截图能够动态吸附直线的功能挺有意思,所以就模仿了一个。

先上效果图

界面很简单。。呵呵


移动鼠标,会把鼠标所在最小矩形选中。把没有选中的地方给模糊化,以示我们选中的区域很清楚。


还可以选中窗口中控件的区域。


小菜单


截图效果


编程思路:

1.动态找到鼠标所在区域的矩形,肯定是要获得桌面上每个窗口以及其子控件的大小位置属性。

想获得这些属性Qt貌似没有提供相关的API,只能用windows的API  EnumWindows 和 EnumChildWindows枚举出所有的窗口的位置坐标和大小属性保存在 一个vector中。

2.有了位置和大小(保存在一个Rect中就行了)就好办了。重写Qt的鼠标移动事件,自己定义了一个结构体

struct MyRect 
{
	QRect myRect_;	//矩形
	int distance;	//鼠标当前点到 所有边的距离之和,用于比较
};
每当鼠标移动就把每个包含鼠标当前点的矩形保存到myRect_中并且计算他的大小distance。

然后找到最小的distance对应的矩形。这个就是上图我们要显示的矩形了。

3.该怎么处理??Qt你们都晓得把。

我是通过QPixmap类的grabWindow 获得整个屏幕,然后 组合绘图 变色整个屏幕。

当鼠标移动到某个区域时 把这个区域 清晰显示。即上图效果。

4.保存图片QPixmap的save即可。


说了这么多了上代码把。

CPP。

#include "imagewidget.h"
#include <QPainter>
#include <QColor>
#include <QMessageBox>
#include <QByteArray>
#include <QBuffer>
#include <QPainter>
#include <QDesktopWidget>
#include <QPen>


#include <Windows.h>
#include <vector>



std::vector<QRect> allWindowRect;		//用于存储所有的窗口
std::vector<HWND> allWindowHwnd;		//用于存储所有的窗口句柄
std::vector<MyRect> myRectRestlt;		// 找到所有包含 鼠标当前移动点的矩形,并保存其到各边的距离之和。


//声明回调函数
bool CALLBACK MyEnumWindowsProc(HWND hwnd,LPARAM lParam);

ImageWidget::ImageWidget(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	//用于获取窗口大小
	QDesktopWidget *dtw = QApplication::desktop(); 
	//获得 整个屏幕
	pixmap_ = pixmap_.grabWindow(QApplication::desktop()->winId(),0,0,dtw->width(),dtw->height());

	isPressed = false;
	isDragging = false;

	captureMenu_ = new CaptureMenu();

	//打开鼠标 跟踪
	setMouseTracking(true);

	//关联 用于保存文件名
	connect(captureMenu_,SIGNAL(toSaveFile(QString)),this,SLOT(slotGetFileName(QString)));

	//遍历窗口 获得各个窗口的大小
	::EnumWindows((WNDENUMPROC)MyEnumWindowsProc,0);
}

ImageWidget::~ImageWidget()
{
}
void ImageWidget::paintEvent(QPaintEvent *event)
{
	QPainter painter(this);
	pixmap_ = pixmap_.scaled(width(),height(),Qt::KeepAspectRatio);


	//pixmap_没有 alpha通道 添加通道
	QPixmap temp(pixmap_.size());
	temp.fill(Qt::transparent);

	QPainter p(&temp);
	p.setCompositionMode(QPainter::CompositionMode_Source);
	p.drawPixmap(0, 0, pixmap_);
	p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
	p.fillRect(temp.rect(), QColor(50, 50, 50, 100)); //把图片调 暗 以显示截图全屏
//	pixmap_ = temp;


	//水印????
	painter.drawPixmap(0,0,temp);
	QPen penWather;
	penWather.setWidth(10);
	penWather.setBrush(QColor(125,125,125,125));
	painter.setPen(penWather);
	QString tempStr;
	tempStr = QString(tr("开始按钮X:%1 Y:%2 移动中的X:%3 Y:%4")).arg(pStart_.x()).arg(pStart_.y()).arg(pMove_.x()).arg(pMove_.y());
	painter.drawText(100,100,tempStr);

	//显示 截图拖动的区域
	QPen pen;
	pen.setWidth(5);
	pen.setColor(QColor(0,255,255,127));
	painter.setPen(pen);

	if (isDragging)
	{
		painter.drawPixmap(pStart_.x(),pStart_.y(),pixmap_,pStart_.x(),pStart_.y(),pMove_.x()-pStart_.x(),pMove_.y()-pStart_.y());
		painter.drawRect(pStart_.x()-2,pStart_.y()-2,pMove_.x()-pStart_.x()-2,pMove_.y()-pStart_.y()-2);
	}
	else 
	{
		painter.drawPixmap(miniRect.myRect_.left(),miniRect.myRect_.top(),pixmap_,miniRect.myRect_.left(),miniRect.myRect_.top(),miniRect.myRect_.width(),miniRect.myRect_.height());
		painter.drawRect(miniRect.myRect_.left()-2, miniRect.myRect_.top()-2, miniRect.myRect_.width()-2, miniRect.myRect_.height()-2);
	}
}
void ImageWidget::mousePressEvent(QMouseEvent *event)
{
	pStart_.setX(event->x());
	pStart_.setY(event->y());
	
	isPressed = true;
}

void ImageWidget::mouseMoveEvent(QMouseEvent *event)
{
	if (isPressed)		//如果按下 鼠标 开始 区域截图
	{
		isDragging = true;
		pMove_.setX(event->x());
		pMove_.setY(event->y());
	}
	else			//如果没有按下鼠标 开始自动寻找合适窗口  //、应该改为 找到距离最近的 矩形块 。。。!!!!!!
	{
		//每次移动都清空
		myRectRestlt.clear();
		for (std::vector<QRect>::iterator it = allWindowRect.begin()+1;it != allWindowRect.end();it++)
		{
			if (it->contains(event->x(),event->y()))
			{
				calculateRectDistance(*it);
			}
		}
		MyRect tempMinRect;
		for(std::vector<MyRect>::iterator it = myRectRestlt.begin();it != myRectRestlt.end();it++)
		{
			if (it->distance < tempMinRect.distance)	//找到最小的矩形
			{
				tempMinRect = *it;		//
			}
		}
		miniRect = tempMinRect;
	}
	update();
}
void ImageWidget::mouseReleaseEvent(QMouseEvent *event)
{
	//记录 结束点
	if (isDragging)
	{
		pEnd_.setX(event->x());
		pEnd_.setY(event->y());
	}
	else
	{
		pStart_.setX(miniRect.myRect_.left());
		pStart_.setY(miniRect.myRect_.top());
		pEnd_.setX(miniRect.myRect_.right());
		pEnd_.setY(miniRect.myRect_.bottom());
	}

	isPressed = false;
	//isDragging = false;

	//新建菜单窗口
	captureMenu_->move(event->x()-152,event->y());
	captureMenu_->setWindowFlags(Qt::FramelessWindowHint);
	captureMenu_->exec();

	//退出窗口
	close();
	//发射 信号给截图软件窗口 可以显示
	emit beVisible();

}
//回调函数
bool CALLBACK MyEnumWindowsProc(HWND hwnd,LPARAM lParam)
{
	if (::IsWindow(hwnd) && ::IsWindowVisible(hwnd))
	{
		RECT tempRect;
		QRect tempQRect;
		::GetWindowRect(hwnd,&tempRect);
		
		tempQRect.setTopLeft(QPoint(tempRect.left,tempRect.top));
		tempQRect.setBottomRight(QPoint(tempRect.right,tempRect.bottom));
	

		allWindowRect.push_back(tempQRect);
		allWindowHwnd.push_back(hwnd);

		::EnumChildWindows(hwnd,(WNDENUMPROC)MyEnumWindowsProc,0);
	}
	return true;
}
void ImageWidget::slotGetFileName(QString filename)
{
	pixmapSave_ = pixmap_.copy(pStart_.x(),pStart_.y(),pEnd_.x()-pStart_.x(),pEnd_.y()-pStart_.y());
	//保存截图
	QByteArray bytes;//用于存放2进制数据
	QBuffer buffer(&bytes);	//设置缓存
	buffer.open(QIODevice::ReadOnly);
	pixmapSave_.save(filename,"PNG",1);

}
void ImageWidget::calculateRectDistance(QRect rect)
{
	int dis = rect.width() + rect.height();
	MyRect tempMyRect;
	tempMyRect.myRect_ = rect;
	tempMyRect.distance = dis;
	//添加进入
	myRectRestlt.push_back(tempMyRect);
}

。H

#ifndef IMAGEWIDGET_H
#define IMAGEWIDGET_H

#include <QWidget>
#include "ui_imagewidget.h"
#include <QPixmap>
#include <QPoint>
#include <QMouseEvent>
#include <capturemenu.h>
#include <QRect>

struct MyRect 
{
	QRect myRect_;	//矩形
	int distance;	//鼠标当前点到 所有边的距离之和,用于比较
};

class ImageWidget : public QWidget
{
	Q_OBJECT

public:
	ImageWidget(QWidget *parent = 0);
	~ImageWidget();

	void paintEvent(QPaintEvent *event);
	//重写 鼠标按下 事件,记录截图起始点
	void mousePressEvent(QMouseEvent *event);
	//重写 鼠标松下 事件,记录截图结束点
	void mouseReleaseEvent(QMouseEvent *event);
	//重写 鼠标移动 事件,当拉动截图区域时 改变截图区域为正常图片(非蒙尘)
	void mouseMoveEvent(QMouseEvent *event);
	//用于计算 鼠标当前点到各个边的距离之和
	void calculateRectDistance(QRect rect);
private:
	Ui::ImageWidget ui;
	QPixmap pixmap_;	//用于显示 截的整个屏幕
	QPixmap pixmapSave_; //用于 保存截图

	QPoint pStart_;	//记录开始截图位置
	QPoint pEnd_;	//记录结束截图位置
	QPoint pMove_;	//记录移动中的坐标
	bool isPressed;	//是否按下按钮
	bool isDragging;	//是否用户拖选

	MyRect miniRect;	//最小矩形

	CaptureMenu *captureMenu_;	//截图结束时的菜单
	QString fullPath;	//保存文件名以及 路径

	public slots:
		void slotGetFileName(QString filename);

signals:
		void beVisible();  //给 截图软件发射可见 信号
};

#endif // IMAGEWIDGET_H

贴了2个最重要的文件。

应届生刚入职在实习,公司让学Qt,学了半个月,代码写的不好的地方或者大家有更好的做法希望大家多多指教,注释很详细。


下载:http://download.csdn.net/detail/kfbyj/6713861



  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值