Qt中处理鼠标事件的两种方法
这是最终要实现的效果,当鼠标在红色,绿色方块上按下并拖动时,这两会随之移动
红色采用事件过滤器;
绿色采用重写自定义控件。
目录
方法一:事件过滤器
先创建lbl_2并设计其颜色大小:
lbl_2=new QLabel(widget);
lbl_2->setFrameShape(QFrame::Box);
lbl_2->setFixedSize(100,100);
lbl_2->setStyleSheet("background-color:red");
为lbl_2安装事件过滤器:
lbl_2->installEventFilter(this);
事件过滤器
需要注意的是,在这里需要将QEvent类型的event转化为QMouseEvent
因为Qt中的事件对象QEvent是一个通用的事件对象,包含了许多类型的事件,但它并不提供事件的具体细节。
而QMouseEvent获取有关鼠标事件的信息;
例如在这里我们可以访问
globalPos()
:鼠标事件的全局位置,即鼠标在屏幕上的坐标。pos()
:鼠标事件的位置,即鼠标在目标对象(lbl_2
)内的相对坐标。
bool press_move_release::eventFilter(QObject *watch, QEvent *event)
{
if(watch==lbl_2)//当监督对象为lbl_2时
{
//如果事件为鼠标按下
if(event->type()==QEvent::MouseButtonPress)
{
QMouseEvent* mouseevent=static_cast<QMouseEvent*>(event);
presspos=mouseevent->globalPos();
wndpos=lbl_2->pos();
}
//如果事件是鼠标移动
else if(event->type()==QEvent::MouseMove)
{
qDebug()<<"mousemove";
QMouseEvent* mouseevent=static_cast<QMouseEvent*>(event);
QPoint now=wndpos+(mouseevent->globalPos()-presspos);
lbl_2->move(now);
}
//如果事件是鼠标释放
else if(event->type()==QEvent::MouseButtonRelease)
{
qDebug()<<"1";
}
}
}
插入:鼠标跟踪
以上的事件过滤器默认状态下需要鼠标保持按下的状态下,系统才会调用mousemoveEvent事件
鼠标跟踪它允许应用程序捕获和响应鼠标指针的移动,即使没有鼠标按钮按下。默认情况下,鼠标跟踪通常是禁用的,这意味着只有在鼠标按钮按下时才会触发鼠标事件。启用鼠标跟踪后,应用程序将在鼠标移动时收到相应的事件,而无需按下鼠标按钮。
this->setMouseTracking(true);
在这里我们无需调用鼠标跟踪就可以达到我们想要的效果,而鼠标跟踪的使用我们稍后会在自定义控件里讲到。
方法二:自定义控件
自定义控件直接应用程序中创建用户界面元素,允许完全控制事件处理
在这里我们创建了一个名为mc的控件,并让他继承QLabel类
用了鼠标按下,移动,释放三个事件
mc::mc(QWidget *parent): QLabel {parent}
{
//鼠标跟踪
this->setMouseTracking(true);
}
//鼠标按下
void mc::mousePressEvent(QMouseEvent *event)
{
qDebug()<<"mousepress";
//记录按下时鼠标坐标
mousepos=event->globalPos();
//记录按下时方块坐标
wndpos=this->pos();
qDebug()<<wndpos;
qDebug()<<mousepos;
}
//鼠标移动
void mc::mouseMoveEvent(QMouseEvent *event)
{
qDebug()<<"mousemove";
//方块原来坐标+(现在鼠标坐标与原来鼠标坐标的差)
this->move(wndpos+event->globalPos()-mousepos);
}
//鼠标释放
void mc::mouseReleaseEvent(QMouseEvent *event)
{
}
鼠标跟踪:
自定义不像事件过滤器,这三个函数是独立的,也就是说当鼠标移动至方块上时就会触发mouseMoveEvent事件,导致方块抖动。
而这时候关掉鼠标跟踪,也就意味着只有在鼠标按钮按下时才会触发鼠标事件。
从而达到我们需要的按下拖动效果。
globalpos与pos
在处理方块拖动后的位置,我们用到了鼠标按下时的坐标,鼠标按下时方块的坐标,鼠标拖动后的坐标。
在这里我们用到了鼠标按下时的坐标与鼠标拖动后的坐标的差,这即为方块应该移动的方向距离。
而在这里globalpos和pos却有不同
如果我们用globalpos来表示二者之差:
//鼠标按下
void mc::mousePressEvent(QMouseEvent *event)
{
qDebug()<<2;
//记录按下时鼠标坐标
mousepos=event->globalPos();
//记录按下时方块坐标
wndpos=this->pos();
qDebug()<<wndpos;
qDebug()<<mousepos;
}
//鼠标移动
void mc::mouseMoveEvent(QMouseEvent *event)
{
qDebug()<<"mousemove";
//方块原来坐标+(现在鼠标坐标与原来鼠标坐标的差)
this->move(wndpos+event->globalPos()-mousepos);
}
代码正常运行,也达到了想要的效果
而用pos来表示却:
//鼠标按下
void mc::mousePressEvent(QMouseEvent *event)
{
qDebug()<<2;
//记录按下时鼠标坐标
mousepos=event->pos();
//记录按下时方块坐标
wndpos=this->pos();
qDebug()<<wndpos;
qDebug()<<mousepos;
}
//鼠标移动
void mc::mouseMoveEvent(QMouseEvent *event)
{
qDebug()<<"mousemove";
//方块原来坐标+(现在鼠标坐标与原来鼠标坐标的差)
this->move(wndpos+event->pos()-mousepos);
}
方块会抖动
pos造成抖动
当使用pos()
获取鼠标事件的坐标时,会将鼠标事件的坐标转换为相对于mc
控件的局部坐标。这意味着鼠标事件的坐标是相对于mc
控件内部的,而不是全局坐标。
如果使用相对坐标来计算新的控件位置,相对坐标受到控件父级或布局的影响,可能会引起计算错误。
而全局坐标表示鼠标事件的位置在整个屏幕上的坐标,而不受控件的影响。