Qt操作:鼠标事件(鼠标事件坐标)+程序退出前弹出确认退出对话框(QMessageBox的使用)
程序功能
基本功能:打开一张图片,建立一张与之对应的大小一致的全黑灰度图,用鼠标在图片上选取ROI;选中ROI的同时,灰度图对应的位置填充为白色。
附加功能:用户选择ROI后在未保存灰度图的情况下点击退出程序,需对用户进行提醒是否保存当前选中的ROI
鼠标事件
鼠标坐标
相对坐标(鼠标在widget中,且对于当前的widget的坐标):x(),y()。
Qpoint windowPos() 程序窗口坐标:鼠标在程序窗口的相对位置
screenPos():屏幕坐标
QWidget::mapToGlobal(ev->Pos()):由本地坐标转换成屏幕坐标
QCursor::pos():获得鼠标的屏幕坐标
鼠标按键状态
buttons()& Qt::LeftButton :左键
Qt::RightButton :右键 Qt::MidButton:中间键
&是“与”运算
三个键可以同时发生:通过与运算可以得到按键状态
鼠标事件重载
本次任务复杂点: 如何得到当前鼠标点击的位置相对于图片的准确位置
捕获鼠标事件有两种方式(此次使用1):
1.直接使用相应的鼠标事件函数
void mousePressEvent(QMouseEvent *event)
void mouseReleaseEvent(QMouseEvent *event)
2.使用事件过滤器
相对图片位置的获取
捕获鼠标事件之前,首先获取当前图片相对于显示该图片的Qlabel的偏差(xoffset,yoffset),以及显示相对于图片像素的比例(Qlabel和图片可能大小不一致,因而需要进行一次转换)。
ui.tmp->setAlignment(Qt::AlignCenter);
ui.tmp->setPixmap(QPixmap::fromImage(imgshow).scaled(ui.tmp->size().width(),
ui.tmp->size().height()*1.1, Qt::KeepAspectRatio));
xoffset = (ui.tmp->contentsRect().width() - ui.tmp->pixmap()->rect().width()) / 2;
yoffset = (ui.tmp->contentsRect().height() - ui.tmp->pixmap()->rect().height()) / 2;
rate_label = double((ui.tmp->contentsRect().width() - 2 * xoffset)) / img.cols;
然后获得鼠标事件(使用的方式1)
void choose_ROI::mousePressEvent(QMouseEvent *event)
{
QPoint leftButtomRightPoint = event->globalPos();
leftButtomRightPoint = ui.tmp->mapFromGlobal(leftButtomRightPoint);
if (leftButtomRightPoint.x() < ui.tmp->width()&& leftButtomRightPoint.x()>0
&& leftButtomRightPoint.y() < ui.tmp->height()&&leftButtomRightPoint.y()>0)
{
//leftButtomRightPoint = ui.tmp->mapFromGlobal(leftButtomRightPoint);
left_point.x = (leftButtomRightPoint.x() - xoffset);
left_point.y = (leftButtomRightPoint.y() - yoffset);
}
}
代码分析:
event->globalPos();
获取当前鼠标相对于全局的位置
通过ui.tmp->mapFromGlobal(leftButtomRightPoint);
转化成鼠标当前所在控件上的位置
然后我这里又进行了是否点击在相应的位置上的判断(if语句)
容易得到left_point.x left_point.y
,这就是鼠标在当前Qlabel上相对于图片的位置。要进行图片的操作(比如标记ROI)只需要最后一步操作得到该位置相对于图片的绝对位置:
left_point.x = left_point.x/rate_label;
left_point.y = left_point.y /rate_label;
right_point.x = right_point.x/rate_label;
right_point.y = right_point.y /rate_label;
最后图片操作
Rect rect;
rect.x = left_point.x;
rect.y = left_point.y;
rect.width = right_point.x- left_point.x;
rect.height = right_point.y - left_point.y;
rect &= Rect(0, 0, imgROI.cols, imgROI.rows);//(防止内存错误)
imgROI(rect).setTo(255);//填充
程序退出前弹出确认退出对话框
重写void closeEvent(QCloseEvent *ev)
函数,对关闭对话框进行控制。
void choose_ROI::closeEvent(QCloseEvent *ev)
{
char buf_save[100];
sprintf(buf_save, "roi");
char buf_downFrame[100];
sprintf(buf_downFrame, "是否保存对ROI的修改?");
QString strInfo = QString::fromLocal8Bit(buf_downFrame);
string buf_downFrame1 = strInfo.toStdString();
if (ROIflag == 0 || ROIflag == 1)
{
QMessageBox::StandardButton r = QMessageBox::warning(this, " ",
buf_downFrame1.c_str(), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (r == QMessageBox::No)
{
ev->accept();
}
else
{
ev->ignore();
// svae_Roi();//这是我保存图片的函数
}
}
}
代码解析:
首先需要解决中文字符的编码问题利用QString::fromLocal8Bit()
将char 转化成Qstring,这种转化方式指定编码方式。然后将该Qstring转化成std 的string。最终显示的时候是char*类型,再调用一次.c_str()
就可以了。
然后是QMessageBox的使用,QMessageBox::warning(this, " ", buf_downFrame1.c_str(), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
中的QMessageBox::Yes | QMessageBox::No, QMessageBox::No
可以缺省。其余请直接看代码。
效果展示
说明: 红色框是选择为ROI的区域,右边ROI图像对选中的区域进行白色填充。