Linux 学习记录49(QT篇)

本文详细介绍了在Linux环境下使用QT进行编程时的事件处理机制,包括事件的概念、如何处理事件,以及键盘鼠标事件的处理函数。此外,还讲解了QT中的定时器功能,包括两种实现方式,并给出代码示例。最后,文章探讨了基于QT构建TCP服务器的基本步骤和通信模型,展示了如何处理客户端连接和数据传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux 学习记录49(QT篇)

在这里插入图片描述

一、事件处理机制

1. 什么是事件

事件是由窗口系统或者自身产生的,用以响应所发生的各类事情,比如用户按下并释放了键盘或者鼠标、窗口因暴露而需要重绘、定时器到时而应有所动作,等等从某种意义上讲,事件比信号更原始,甚至可以认为大多数信号其实都是由事件产生的。比如一个下压式按钮首先感受到的是鼠标事件在进行必要的处理以产生按钮下沉继而弹起的视觉效果之后,才会发射 clicked()信号

2. 如何处理事件

mywnd(自定义类) -继承-> Qwidget -继承-> Qobject

(1. 当事件发生时

当事件发生时,首先被调用的是oobject类中的虚函数event()
其 OEvent型参数标识了具体的事件类型

bool QObject:: event (QEvent* e)
       {
           if (e == mouseEvent)
           {
               void QWidget::mousePressEvent (QMouseEvent* e)
               void QWidget:: mouseReleaseEvent (QMouseEvent* e)
           }
           if(e == keyEvent){
               void QWidget::keyPressEvent (QMouseEvent* e)
               void QWidget:: keyReleaseEvent (QMouseEvent* e)
           }
       }

(2. QObject类的子类

作为QObject类的子类, QWidget类覆盖了其基类中的
   event()虚函数,并根据具体事件调用具体事件处理函数
       void QWidget::mousePressEvent (QMouseEvent* e)
       void QWidget::mouseReleaseEvent (QMouseEvent* e)
       void QWidget::keyPressEvent (QMouseEvent* e)
       void QWidget:: keyReleaseEvent (QMouseEvent* e)
       void QWidget::paintEvent (QPaintEvent* e):

而这些事件处理函数同样也是虚函数,也可以被 QWidget类
的子类覆盖,以提供针对不同窗口部件类型的事件处理

组件的使用者所关心的往往是定义什么样的槽处理什么样的信号,
而组件的实现者更关心覆盖哪些事件处理函数

3. 事件处理函数由来

QObject类 提供了那些可以重写的虚函数
    [virtual] bool QObject::event(QEvent *e) 
            // 参数:事件的类型

QWidgets类, 提供了那些可以重写的虚函数
    [override virtual protected] bool QWidget::event(QEvent *event)
    
    [virtual protected] void QWidget::keyPressEvent(QKeyEvent *event)
    [virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event)
    [virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
    [virtual protected] void QObject::timerEvent(QTimerEvent *event)

QPainter类 ---> 画家类
     void SimpleExampleWidget::paintEvent(QPaintEvent *)
     {
         QPainter painter(this);
         painter.setPen(Qt::blue);
         painter.setFont(QFont("Arial", 30));
         painter.drawText(rect(), Qt::AlignCenter, "Qt");
     }

4. 鼠标和键盘事件

    [virtual protected] void QWidget::keyPressEvent(QKeyEvent *event)
    [virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event)
    [virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
Qt 键值键盘按键
Qt::Key_Return回车键
Qt::Key_Enter换行键
Qt::Key_Enter制表符键
Qt::Key_EscapeEsc键
Qt::Key_Space空格键
Qt::Key_Delete删除键
Qt::Key_Backspace退格键
Qt::Key_Up向上箭头键
Qt::Key_Down向下箭头键
Qt::Key_Left向左箭头键
Qt::Key_Right向右箭头键
Qt::Key_RightF1至F35键

5. 键盘按键示例

头文件中:
class login : public QMainWindow
{
    Q_OBJECT

private slots:

public:
    login(QWidget *parent = nullptr);
    ~login();
    /*定义键盘按下时的处理函数*/
    void keyPressEvent(QKeyEvent* event);

private:
    Ui::login *ui;
};
==================================================
.cpp文件中
/*函数声明*/
void login::keyPressEvent(QKeyEvent* event)
{
    switch(event->key())
    {
        case Qt::Key_Return :{
            当按下回车时执行的代码块
        }break;
        case 'A' :{
            当按下A时执行的代码块
        }break;
    }
}

二、定时器

1. 定时器事件

在qt中,定时器能够实现,让系统每隔给定的时间,自动去调用某个函数
定时器的实现有两种方式:分别是基于对象版和基于事件处理版本
基于对象版本的定时器(QTimer)
基于事件处理函数

1、使用QTimer类实例化一个定时器对象
2、调用该对象的成员函数start(sec),启动时给定超时时间
3、如果定时器给定的时间到位,那么该定时器,就会自动发射一个timeout的信号
4、将该信号与自定义的槽函数绑定在一起,以后会每隔sec时间后,系统会自动调用自定义的槽函数
5、当执行到成员函数stop函数时,才会关闭该定时器
====================================================
基于事件处理函数:
1、无需实例化对象,直接调用自己类中的startTimer(msec),启动一个定时器,并返回该定时器的id
2、系统会每隔msec时间后,自动调用自己类中的timerEvent函数,该函数是虚函数,需要自己进行重写,在该函数中可以使用timerId函数来确定是哪个定时器到位
3、调用自己的killTimer函数来终止一个定时器

2. 代码实现

==================头文件
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    //重写定时器事件处理函数
    void timerEvent(QTimerEvent *e);
private slots:
    void on_objStartBtn_clicked();
    void timeout_slot();           //自定义处理timeout的信号函数的槽函数
    void on_eventBtn_clicked();
private:
    Ui::Widget *ui;
    //定义一个定时器变量,当做成员变量,因为有多个按钮会用到
    QTimer *obj_timer;
    //定义一个定时器的id
    int event_timer;
};
======================源文件
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //给定时器实例化对象
    obj_timer = new QTimer(this);
    //将定时器发射的timeout信号与自定义的槽函数进行连接
    connect(obj_timer, &QTimer::timeout, this, &Widget::timeout_slot);
}
Widget::~Widget()
{
    delete ui;
}
//对象按钮对应的槽函数
void Widget::on_objStartBtn_clicked()
{
    if(ui->objStartBtn->text() == "启动")
    {
        //执行启动一个定时器
        obj_timer->start(1000);    //启动定时器,每隔1000毫秒后,该定时器会自动发射timeout的信号
        //将按钮文本内容改为"关闭"
        ui->objStartBtn->setText("关闭");
    }else
    {
        //执行关闭一个定时器
        obj_timer->stop();
        //将按钮文本内容改为"启动"
        ui->objStartBtn->setText("启动");
    }
}

//处理timeout信号的槽函数的定义
void Widget::timeout_slot()
{
    //设置文本对齐方式
    ui->objLab->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter;);
    //调用事件类中的静态成员函数获取当前的系统时间
    QTime sys_time = QTime::currentTime();
    //调用成员函数,将时间转换为字符串
    QString t = sys_time.toString("hh:mm:ss");
    //将时间展示到ui界面的lab上
    ui->objLab->setText(t);
}

3. 自制文本闹钟

如有需要在本文顶部获取(含源码)
在这里插入图片描述

三、绘制事件(QPaintEvent)

  1. 绘制事件是qt提供的二维图形引擎,能够让用户绘制各种图形,例如:适量文字、绘制图形、图像。。。
  2. 绘制事件处理函数触发情况:窗口第一次展示、窗口最小化、最大化、窗口从覆盖状态显示出来、手动拖动窗口调大小、调用update函数
  3. 绘制事件,依赖于画家类(QPainter)实现相关绘制工作
    所需头文件:<QWidget> <QPainter>

1. 代码实现

头文件======================
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QPainter>           //画家类
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    //重写绘制事件
    void paintEvent(QPaintEvent *event) override;
private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
源文件======================
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}
Widget::~Widget()
{
    delete ui;
}
//绘制事件处理函数的定义
void Widget::paintEvent(QPaintEvent *event)
{
    //实例化一个画家
    QPainter p(this);
    //给画家安排画笔
    p.setPen(QColor("pink"));
    //给画家安排字体
    p.setFont(QFont("隶书", 40, 10));
    //使用画家绘制文本内容
    p.drawText(this->rect(), Qt::AlignCenter, "好好学习,天天向上");
    //定义一个画笔
    QPen pen(Qt::DashDotDotLine);
    pen.setWidth(15);
    pen.setColor(QColor("blue"));
    p.setPen(pen);          //给画家换一支画笔
    p.setBrush(QBrush(QColor("yellow")));
    //设置 画家的起笔坐标
    //p.translate(this->width()/2, this->height()/2);
    //设置画家的坐标系偏移角度
    //p.rotate(45);
    //用画笔画一个椭圆
    p.drawEllipse(QPoint(0,0), 200,300);
    //绘制图片
    p.drawPixmap(this->rect(), QPixmap("D:/23041QT/day4/04paintEvent/duck.png"));
}

四、基于QT的TCP服务器

1. 基于tcp的通信原理

在这里插入图片描述

2. qt提供的通信模型

在这里插入图片描述

(1. 代码实现

所需头文件: <QTcpServer> <QTcpSocket> <QVector>
需要在obj文件加上 network 如下
在这里插入图片描述

QTcpServer *ser;    //定义服务器指针
QVector<QTcpSocket *> clisok;//定义客户端容器,将连接上来的客户端套接字储存
/*定义服务器*/
ser = new QTcpServer(this);
/*从文本中获取端口号并转化为 无符号整形*/
quint16 port = set_port->text().toUInt();
/*连接服务器*/
if(ser->listen(QHostAddress::Any,port))
{
    QMessageBox::information(this,"成功","打开服务器成功");
}
else
{
    QMessageBox::information(this,"失败","打开服务器失败");
}
/*因为连接上服务器后会发送一个连接的信号,所以将该信号与处理该信号的自定义槽函数连接*/
信号:&QTcpServer::newConnection
connect(ser,&QTcpServer::newConnection,this,&Tcpserver::newconnection_slots);
自定义槽函数:
/*当有新客户端连接*/
void Tcpserver::newconnection_slots()
{
    //获取最新连接的套接字
    QTcpSocket *newfd = ser->nextPendingConnection();
    //把该套接字放入到套接字容器中,append追加,push_back尾插
    clisok.push_back(newfd);
    //一个服务器和多个客户端已经建立连接,如果有客户端向服务器发来数据,
    //那么该客户端就会自动发射一个readyRead的信号
    //我们可以将该信号连接到自定义的槽函数中处理相关逻辑
    当接收到客户端信息时触发信号:&QTcpSocket::readyRead
    connect(newfd,&QTcpSocket::readyRead,this,&Tcpserver::readyRead_slots);
}
//处理readyRead信号对应的槽函数
void Tcpserver::readyRead_slots()
{
    //删除无效的客户端:比如断开的,但是套接字却保存着
    for(int i=0;i<clisok.size();i++)
    {
        //clisok[i]表示任意一个客户端
        if(clisok[i]->state() == 0)
        {
            //等于0,无效连接,删除
            clisok.removeAt(i);     //将当前客户端移除该容器
        }
    }

    //判断是那个客户端发来的数据
    for(int i=0;i<clisok.size();i++)
    {
        //判断发来的套接字中是否有数据待读
        if(clisok[i]->bytesAvailable() != 0)
        {
            //读取当前套接字中的数据
            QByteArray msg = clisok[i]->readAll();

            //把读取的数据放到ui界面上
            text->addItem(QString::fromLocal8Bit(msg));

            //把获取的数据广播给所有客户端
            for(int j=0;j<clisok.size();j++)
            {
                clisok[j]->write(msg);
            }
        }
    }
}

(2. 自制的TCP服务器

如有需要在本文顶部获取(含源码)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值