在QT的控件或者窗口当中,如果对于当前鼠标或者键盘的功能需要自己定义,可以重写父类当中对应虚函数,主要包括以下几个:
//键盘按键按下
virtual void keyPressEvent(QKeyEvent *event);
//键盘按键抬起
virtual void keyReleaseEvent(QKeyEvent *event);
//鼠标离开
virtual void leaveEvent(QEvent *event);
//鼠标双击
virtual void mouseDoubleClickEvent(QMouseEvent *event);
//鼠标移动
virtual void mouseMoveEvent(QMouseEvent *event);
//鼠标按下
virtual void mousePressEvent(QMouseEvent *event);
//鼠标抬起
virtual void mouseReleaseEvent(QMouseEvent *event);
//鼠标滚轮事件
virtual void wheelEvent(QWheelEvent *event);
使用鼠标移动时,需要在构造函数中开启鼠标追踪
this->setMouseTracking(true);
键盘响应代码:
void Widget::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_W:
qDebug()<<"模型前进...";
break;
case Qt::Key_S:
qDebug()<<"模型后退...";
break;
case Qt::Key_A:
qDebug()<<"模型向左...";
break;
case Qt::Key_D:
qDebug()<<"模型向右...";
break;
default:
break;
}
}
void Widget::keyReleaseEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_W:
qDebug()<<"模型停止前进...";
break;
case Qt::Key_S:
qDebug()<<"模型停止后退...";
break;
case Qt::Key_A:
qDebug()<<"模型停止向左...";
break;
case Qt::Key_D:
qDebug()<<"模型停止向右...";
break;
default:
break;
}
}
鼠标按键响应事件:
void Widget::enterEvent(QEvent *event)
{
Q_UNUSED(event);
qDebug()<<"鼠标进入...";
}
void Widget::leaveEvent(QEvent *event)
{
Q_UNUSED(event);
qDebug()<<"鼠标离开...";
}
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
//判断鼠标按键类型
if(event->button() == Qt::LeftButton){
qDebug()<<event->pos();
qDebug()<<"鼠标双击...";
}
}
在QMouseEvent中有两种获取鼠标位置的函数,相关解释如下:
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
//判断鼠标按键类型
if(event->button() == Qt::LeftButton){
qDebug()<<event->pos();//输出的是鼠标在相对于本控件左上角的位置
qDebug()<<event->globalPos();//输出的是鼠标相对于整个显示器窗口左上角的位置
qDebug()<<"鼠标双击...";
}
}
案例:鼠标拖动图片移动
相关位置计算辅助记忆:
在Qt中显示一张图片,是使用QLabel控件来装载QPixmap图像源,如果图片控件需要支持鼠标的拖拽移动,需要自己定义一个控件,然后重新其父类的鼠标控制相关函数。
所以,先定义一个C++的类,继承QLabel,重写其 mousePressEvent 和 mouseMoveEvent 类,相关代码如下:
ImageLabel.h:
#ifndef IMAGELABEL_H
#define IMAGELABEL_H
#include
#include
#include
#include
class ImageLabel : public QLabel
{
Q_OBJECT
public:
explicit ImageLabel(const QPixmap &pix,QWidget* parent = nullptr);
//重写虚函数
virtual void mousePressEvent(QMouseEvent* event) override;
virtual void mouseMoveEvent(QMouseEvent* event) override;
//重写键盘控制函数
virtual void keyPressEvent(QKeyEvent* event) override;
private:
QPoint mousePressPos;//鼠标点击位置
int mSpeed;//控制移动速度
signals:
};
#endif // IMAGELABEL_H
ImageLabel.cpp:
#include "imagelabel.h"
#include
ImageLabel::ImageLabel(const QPixmap &pix, QWidget *parent)
{
//设置图像源
this->setPixmap(pix);
//设置父控件
this->setParent(parent);
//设置图像比例填充
this->setScaledContents(true);
this->mSpeed = 10;
//处理键盘事件需要先获取焦点
this->setFocusPolicy(Qt::StrongFocus);
}
void ImageLabel::mousePressEvent(QMouseEvent *event)
{
//记录鼠标开始点击时的初始位置向量
mousePressPos = event->pos();
}
void ImageLabel::mouseMoveEvent(QMouseEvent *event)
{
//求鼠标移动偏移量(向量)
QPoint deltaMove = event->pos() - mousePressPos;
//此时鼠标移动了,但是控件本身位置还没有加上偏移量,还未移动
//求窗口新位置(当前位置 + 偏移量)
this->move(this->pos() + deltaMove);
}
void ImageLabel::keyPressEvent(QKeyEvent *event)
{
qDebug()<<"123";
switch (event->key()) {
case Qt::Key_W:{
QPoint pos = this->pos() + QPoint(0,-1) * mSpeed;
this->move(pos);
break;
}
case Qt::Key_S:{
QPoint pos = this->pos() + QPoint(0,1) * mSpeed;
this->move(pos);
break;
}
case Qt::Key_A:{
QPoint pos = this->pos() + QPoint(-1,0) * mSpeed;
this->move(pos);
break;
}
case Qt::Key_D:{
QPoint pos = this->pos() + QPoint(1,0) * mSpeed;
this->move(pos);
break;
}
}
}
然后再在主窗口中使用自定义类创建图片控件即可:
//使用label在窗口上添加一个图片
QPixmap piximg(":/imgs/images/tt.png");
ImageLabel *imgLab = new ImageLabel(piximg,this);
imgLab->move(50,100);//定义初始位置
效果展示:
鼠标键盘移动自定义控件
如果想每间隔一段时间就去做某件事情,可以重写定时器事件函数,实例代码如下:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
//重写父类的定时器虚函数
virtual void timerEvent(QTimerEvent* event) override;
private:
//声明两个变量,用于接收定时器的ID号
int playerTimerID;
int monsterTimerID;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//开启玩家定时器
playerTimerID = this->startTimer(1000);
//开启怪物定时器
monsterTimerID = this->startTimer(2000);
//除了使用startTimer外,也可以使用QTimer类定义定时器对象实现
}
Widget::~Widget()
{
}
void Widget::timerEvent(QTimerEvent *event)
{
if(event->timerId() == this->playerTimerID){
qDebug()<< "玩家定时器被触发...";
}
if(event->timerId() == this->monsterTimerID){
qDebug()<< "怪物定时器被触发...";
}
}
Qt中的绘图事件函数可以绘制各种图像,比如图片或者自定义的形状等,需要重写父类的paintEvent函数,示例代码如下:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
//重写父类的绘图事件函数
virtual void paintEvent(QPaintEvent* event) override;
private:
//声明一个画家(在一个画布中是可以设置多个画家的)
QPainter* mPainter;
//绘制更新定时器
QTimer* mTimer;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include
#include
#include
#include
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
//初始化画家
mPainter = new QPainter(this);
mTimer= new QTimer(this);
mTimer->start(100);
//绘画事件有一个update()函数,当画布发生了新的绘制时,应该调用这个函数让画布更新,这里采用定时器进行刷新
connect(mTimer,&QTimer::timeout,[this](){this->update();});
}
Widget::~Widget()
{
}
void Widget::paintEvent(QPaintEvent *event)
{
/*画家准备工作*/
//创建画笔
QPen pen(QColor(0,0,125));
//给画家添加画笔
mPainter->setPen(pen);
//开启绘制
mPainter->begin(this);//即使有多个画家存在,这个开始函数也只需要其中一个画家调用一次就行了
//开始绘制直线
mPainter->drawLine(0,0,100,100);
//绘制矩形
mPainter->drawRect(100,100,200,50);
//绘制椭圆
mPainter->drawEllipse(150,150,50,25);
//绘制图片
QImage img(":/imgs/imgs/girl.jpg");
mPainter->translate(100,200);//画家平移
mPainter->rotate(45.0);//画家旋转
mPainter->drawImage(QRect(0,0,100,100),img);
mPainter->drawImage(QRect(0,0,200,200),img,QRect(200,0,200,200));//指定绘制区域位置
/*
第一个参数:(0,0)代表图片的左上角,(200,200)设定图片的大小
第二个参数:图片源
第三个参数:(200,0)指定在整张图片上选择的开始绘制点,(200,200)指绘制的尺寸
*/
//结束绘制
mPainter->end();
}