07. Qt中的事件
QT中的事件
1、QT事件
1.1、事件介绍
- 事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的通称。在Qt中使用 一个对象来表示一个事件,它继承自QEvent类。
- 常见事件:鼠标事件、键盘事件、定时事件、上下文菜单事件、关闭事件、拖放事件、绘制事件。
1.2、事件的处理
- 重载相关的Event函数
- 重新实现事件的paintEvent(),mousePressEvent()等事件处理函数。这是最常用也的一种方法,不过它 只能用来处理特定部件的特定事件。例如实现拖放操作,就是用的这种方法。
- 安装事件过滤器
- 在对象上安装事件过滤器。使用事件过滤器可以在一个界面类中同时处理不同子部件的不同事件。
2、键盘事件
- QKeyEvent
- QKeyEvent类用来描述一个键盘事件。当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键 盘输入焦点的部件。
- 在Qt助手中,查找一下Qt::Key,这里会有的一些Qt::Key_Escape表示空格,Qt::Key_Left←键等等
2.1找到keyPressEvent
-
需要包含头文件才能用,下面是从头文件中拿出来的
-
protected: bool event(QEvent *event) Q_DECL_OVERRIDE; virtual void mousePressEvent(QMouseEvent *event);//鼠标按下 virtual void mouseReleaseEvent(QMouseEvent *event);//鼠标释放 virtual void mouseDoubleClickEvent(QMouseEvent *event);//鼠标双击 virtual void mouseMoveEvent(QMouseEvent *event);//鼠标移动 #ifndef QT_NO_WHEELEVENT virtual void wheelEvent(QWheelEvent *event); //滚轮 #endif virtual void keyPressEvent(QKeyEvent *event);//按键按下 virtual void keyReleaseEvent(QKeyEvent *event);//按键释放 virtual void enterEvent(QEvent *event);//进入 virtual void leaveEvent(QEvent *event);//离开 virtual void paintEvent(QPaintEvent *event);//绘制 virtual void moveEvent(QMoveEvent *event);//离开
-
这里父类是怎么定义的虚函数,和声明的我们就怎么实现它
-
//自己的类中去定义,然后实现 protected: virtual void keyPressEvent(QKeyEvent *event);//按键按下
-
2.1.1判断某个键按下
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->key()==Qt::Key_X)
{
qDebug()<<"X按下";
}
}
2.1.2组合键操作
- 在Qt助手中搜索Qt::KeyboardModifier
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->modifiers()==Qt::ControlModifier)//判断是不是ctrl按下
{
if(event->key()==Qt::Key_X)//接着判断是不是x按下
{
qDebug()<<"ctrl+X";
}
}
else if(event->key()==Qt::Key_X)
{
qDebug()<<"X按下";
}
}
3、鼠标事件
- QMouseEvent类用来表示一个鼠标事件,当在窗口部件中按下鼠标或者移动鼠标指针时,都会产生鼠 标事件。利用QMouseEvent类可以获知鼠标是哪个键按下了,还有鼠标指针的当前位置等信息。通常是 重定义部件的鼠标事件处理函数来进行一些自定义的操作。
- QWheelEvent类用来表示鼠标滚轮事件,在这个类中主要是获取滚轮移动的方向和距离。在滚轮事件 处理函数中,使用QWheelEvent类的delta()函数获取了滚轮移动的距离,每当滚轮旋转一下,默认的是 15度,当滚轮向远离使用者的方向旋转时,返回正值;当向着靠近使用者的方向旋转时,返回负值。这 样便可以利用这个函数的返回值来判断滚轮的移动方向。
3.1鼠标单击事件
Qt::LeftButton //左
Qt::RightButton //中
Qt::MidButton //右
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
{
qDebug()<<"左键按下";
}
}
3.2鼠标释放事件
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
{
qDebug()<<"左键释放";
}
}
3.3鼠标双击事件
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
if(event->button()==Qt::LeftButton)
{
qDebug()<<"左键双击";
}
}
3.4鼠标移动事件
-
setMouseTracking(true); //这个默认是为false,需要设置为true,这样才能实时获取鼠标位置,要不然只有在按下的时候才能获取到
-
void Widget::mouseMoveEvent(QMouseEvent *event) { qDebug()<<event->x()<<event->y(); qDebug()<<event->pos();//相对于窗口的坐标 qDebug()<<event->globalPos();//相对于屏幕的坐标 }
-
3.5滚轮事件
void Widget::wheelEvent(QWheelEvent *event)
{
static int x=0;
x+=event->delta();//还是±120
if(event->delta()>0)
{
qDebug()<<"滚轮往前"<<x;
}
else
{
qDebug()<<"滚轮往后"<<x;
}
}
4、事件过滤器
- 就是说有事件产生,在这个控件上只处理什么事件
- 在左边输入abcd那么是不会输入到里面去的,会被事件过滤器去获取
4.1安装事件过滤器
ui->textEdit->installEventFilter(this);
4.2事件的过滤器实现
//声明函数
virtual bool eventFilter(QObject *watched, QEvent *event);
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
if(watched==ui->textEdit)//通过watched来监视控件
{
if(event->type()==QEvent::KeyPress)//是不是按键按下
{
QKeyEvent *keyEvent=static_cast<QKeyEvent*>(event);//强转
qDebug()<<keyEvent->key();//输出按下的键
return true;
}
else
return false;
}
return Widget::eventFilter(watched,event);//这个函数需要一直在监视所以这里是一个递归
}
-
如果是其他的控件,也是同样的做法
-
再添加了一个pushbutton,如果添加信号和槽,按下就输出一个按下,没加过滤器之前 添加过滤器
-
bool Widget::eventFilter(QObject *watched, QEvent *event) { if(watched==ui->textEdit) { if(event->type()==QEvent::KeyPress)//是不是按键按下 { QKeyEvent *keyEvent=static_cast<QKeyEvent*>(event); qDebug()<<keyEvent->key(); return true; } else return false; } //在后面接着判断看这个监视的是不是pushbutton if(watched==ui->pushButton) { if(event->type()==QEvent::MouseButtonPress) { qDebug()<<"过滤器输出了"; return true; } else return false; } return Widget::eventFilter(watched,event); }
-
5、定时器
- QTimerEvent类用来描述一个定时器事件。对于一个QObject的子类,只需要使用int QObject::startTimer ( int interval )函数来开启一个定时器,这个函数需要输入一个以毫秒为单位的整数 作为参数来表明设定的时间,它返回一个整型编号来代表这个定时器。当定时器溢出时就可以在 timerEvent()函数中获取该定时器的编号来进行相关操作。
- QTimer类来实现一个定时器,它提供了更高层次的编程接口,比如可以使用信号和槽,还可以设置只 运行一次的定时器。
5.1QTimerEvent定时器
5.1.1、设置定时器
int id1;
int id2;
int id3;
int id4;
5.1.2、设置时间
id1=startTimer(1000);//1000毫秒
id2=startTimer(2000);
id3=startTimer(3000);
id4=startTimer(4000);
5.1.3、函数实现
virtual void timerEvent(QTimerEvent *event);
void Widget::timerEvent(QTimerEvent *event)
{
if(event->timerId()==id1)
{
qDebug()<<"id1";
}
if(event->timerId()==id2)
{
qDebug()<<"id2";
}
if(event->timerId()==id3)
{
qDebug()<<"id3";
}
if(event->timerId()==id4)
{
qDebug()<<"id4";
}
}
5.2QTimer定时器
5.2.1设置定时器
QTimer t1;
QTimer t2;
5.2.2设置时间
t1.start(1000);//1000毫秒
t2.start(2000);
5.2.3关联信号和槽
-
槽函数,指的是这个时间到了要执行什么函数
-
private slots: void qDebugSlot1(); void qDebugSlot2();
-
void Widget::qDebugSlot1() { qDebug()<<"t1"; } void Widget::qDebugSlot2() { qDebug()<<"t2"; }
-
connect(&t1,SIGNAL(timeout()),this,SLOT(qDebugSlot1())); connect(&t2,SIGNAL(timeout()),this,SLOT(qDebugSlot2()));
-
6、随机数种子
-
在使用qrand()函数产生随机数之前,一般要使用qsrand()函数为其设置初值,如果不设置初值,那么 每次运行程序,qrand()都会产生相同的一组随机数。为了每次运行程序时,都可以产生不同的随机数, 我们要使用qsrand()设置一个不同的初值。
-
qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));//设置随机数种子
-
int rand = qrand() % 300;//获取随机数
-
7、拖拽事件
-
就是可以直接拖放文件到程序中打开,比如:拖入一个文本到程序中,把这个文本里面的内容都获取到 程序上
-
//包含头文件,用的wideget窗口 #include <QDragEnterEvent> #include <QDropEvent> #include <QMimeData>
-
//重新 protected: virtual void dragEnterEvent(QDragEnterEvent *event); //拖拽事件 virtual void dropEvent(QDropEvent *event); //放下事件
-
void Widget::dragEnterEvent(QDragEnterEvent *event) { //判断小部件上有没有事件 if(event->mimeData()->hasUrls()) { //事件给过去 event->acceptProposedAction(); } else { //忽略 event->ignore(); } }
-
void Widget::dropEvent(QDropEvent *event) { const QMimeData*mimeData=event->mimeData(); if(!mimeData->hasUrls()) { return; } QList<QUrl> urlList=mimeData->urls();//有多少个文件被拖过来 for(int i=0;i<urlList.size();i++)//遍历 { qDebug()<<urlList.at(i).toLocalFile(); } QFile file(urlList.at(0).toLocalFile());//获取第一个文件的内容 file.open(QIODevice::ReadOnly); QByteArray ba; ba=file.readAll(); ui->plainTextEdit->setPlainText(QString::fromLocal8Bit(ba)); }
-
最关键的,要接受这个拖拽事件
this->setAcceptDrops(true); //接受拖拽事件 这个指的是窗口的, //在这个窗口上面有一个多行纯文本控件 ui->plainTextEdit->setAcceptDrops(false); //注意这里是为false,真是打开不的,如果是其他的控件也为false,如果不行那就换为true,因为这个可能会设置失败
-
QMenu *popMenu; //右键弹出式菜单 QAction *adjustTimeAction; //右键弹出式菜单中的内容 调整功能1 QAction *adjustDateAction; //功能2 QAction *quitAction; //退出 popMenu = new QMenu(this); popMenu->setStyleSheet(QStringLiteral("background-color: rgb(99, 99,99);")); adjustTimeAction = new QAction(this); adjustTimeAction->setText(("功能1")); adjustDateAction = new QAction(this); adjustDateAction->setText(("功能2")); quitAction = new QAction(this); quitAction->setText(("退出")); connect(quitAction, SIGNAL(triggered(bool)),this, SLOT(close())); //关联退出的Action void Widget::contextMenuEvent(QContextMenuEvent *event) { //右键会触发这个事件 popMenu->clear(); popMenu->addAction(adjustTimeAction); popMenu->addAction(adjustDateAction); popMenu->addSeparator();//添加线 popMenu->addAction(quitAction); //popMenu->exec(); //堵住 popMenu->exec(QCursor::pos()); }
-
8、截图软件
-
类似QQ的快捷键截图,当然我们这里只实现截图快捷键为 ALT+Z
-
关键代码
-
MyMessage mm; //消息对象 ,这个为自己定义的对象,用来发送全屏 退出消息
-
HHOOK myhook; //钩子句柄 myhook = SetWindowsHookEx(WH_KEYBOARD_LL,keyBoardProc,GetModuleHandle(0),0); //设置钩子获取全局下按键消息
-
//回调函数,负责处理全局下的按键消息 LRESULT keyBoardProc(int nCode, WPARAM wParam, LPARAM lParam) { PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam; if (nCode >= 0) { if (wParam == WM_SYSKEYDOWN) { if(p->vkCode=='Z') { mm.sendScreenSLot(); } } else if(wParam==WM_KEYDOWN) { if(p->vkCode==VK_ESCAPE) { mm.sendExitScreenSLot(); } } } return CallNextHookEx(myhook, nCode, wParam, lParam); }
-
void Widget::mousePressEvent(QMouseEvent *event) { if(event->button()==Qt::LeftButton) { begPos=event->globalPos(); } }
-
void Widget::mouseReleaseEvent(QMouseEvent *event) { if(event->button()==Qt::LeftButton) { endPos=event->globalPos(); } }
-
void Widget::mouseMoveEvent(QMouseEvent *event) { update(); endPos=event->globalPos(); }
-
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); //截图区域的rect结构 QRect Srect(begPos.x(),begPos.y(),endPos.x()-begPos.x(),endPos.y()- begPos.y()); painter.drawRect(Srect); painter.fillRect(Srect,Qt::SolidPattern); }
-
void Widget::keyPressEvent(QKeyEvent *event) { if(event->key()==Qt::Key_Return) { QScreen *screen=QGuiApplication::primaryScreen(); QPixmap pix=screen->grabWindow(0,begPos.x(),begPos.y(),endPos.x()- begPos.x(),endPos.y()-begPos.y()); pix.save("1.png"); showNormal(); setWindowOpacity(1); } }
-
void Widget::screenShotSlot() //截屏 { showFullScreen();//最大化窗口 setWindowOpacity(0.3);//透明度0.3 }
-
void Widget::exitScreenSlot() //退出截图 { showNormal(); //还原窗口 setWindowOpacity(1); //透明度1 }
-