2-事件与绘画

1、事件

1.1 简介

  • QT程序是事件驱动的,程序的每个动作都是由内部某个事件所触发。
  • QT事件的发生和处理成为程序运行的主线,存在于程序整个生命周期。
    常见的QT事件类型如下:
  • 定时器事件、键盘事件、鼠标事件、绘图事件、
  • 拖放事件、滚轮事件、焦点事件、进入和离开事件
  • 移动事件、大小改变事件、显示和隐藏事件、窗口事件
    QT将系统产生的消息转化为QT事件,QT事件被封装为对象,所有的QT事件均继承抽象类QEvent,用于描述程序内部或外部发生的动作,任意的QObject对象都具备处理QT事件的能力。
    在这里插入图片描述

1.2 事件的产生

  • 操作系统事件
    • QT事件产生后会被立即发送到相应的QWidget对象
    • 相应的QWidget中的event(QEvent*)进行事件处理
    • event(QEvent*)根据事件类型调用不同的事件处理函数
    • 在事件处理函数中发送QT预定义的信号
    • 调用信号关联的槽函数
      事件到来->QObject:event()-QWidget----获取不同的事件类型
      鼠标事件:virtual void mousePressEvent(QMouseEvent *event)
  • Qt应用程序自己产生
    • QApplication::postEvent() – 异步
      例如:QWidget::update()
    • QApplication::sendEvent() – 同步
      例如:QWidget::repaint()

1.3 事件的处理

重写特定事件处理函数

  • 在Qt中,事件被封装成对象,所有的事件对象类型都继承自抽象类QEvent
  • 当事件发生时,首先被调用的是QObject类中的虚函数event(),其参数(QEvent)标识了具体的事件类型
  • 在Qt桌面应用(Qt Widgets Application)开发中,QWidget类覆盖了其基类中的event()虚函数,并根据具体事件调用具体事件处理函数:
    -void QWidget::mousePressEvent(QMouseEvent* e); //鼠标按下事件
    -void QWidget::mouseReleaseEvent(QMouseEvent* e); //鼠标抬起事件
    -void QWidget::mouseMoveEvent(QMouseEvent* e);// 鼠标移动事件
    -void QWidget::paintEvent(QPaintEvent* e);//绘图事件
  • 在自定义窗口事件处理函数的过程中,我们可以继承QWidget或者其子类,在自定义的窗口子类中重写事件处理函数,当事件发生的时候,执行的事件处理函数将是我们自定义的版本。

1.4 定时器事件

Qt通过两套机制为应用程序提供定时功能
1) 定时器事件,由QObject提供
2) 定时器信号,由QTimer提供

  • 通过定时器事件实现定时器
    int QObject:startTimer(int interval);// 启动定时器,返回定时器ID,以后每隔interval毫秒触发一次
    void QObject::timerEvent(QTimerEvent*);//定时器事件处理函数
    void QObject::killTimer(int id);//关闭参数id所标识的定时器

1.5 用定时器实现电子时钟和计时器

1: 设计UI

IcdNumber:
	objectname:m_ladH
	digitCount:2
IcdNumber:
	objectname:m_ladM
	digitCount:2
IcdNumber:
	objectname:m_ladS
	digitCount:2
IcdNumber:
	objectname:m_lcdE
	digitCount:12
pushbutton:
	objectname:m_btnStart
	default:v
	text:开始
pushbutton:
	objectname:m_btnReset
	text:复位

2:实现电子时钟,依赖定时器信号,在TimerDialog.h中定义定时器相关的成员变量、声明相关的函数定义

#include <QTimer>
#include <QTime>
...
private slots:
    // 定时器信号对应的函数
    void on_m_clock_timeout();
private:
    QTimer m_clock;// 声明定时器
...

3: 书写定时器信号槽函数,定义信号和槽的连接

TimerDialog::TimerDialog(QWidget *parent): QDialog(parent), ui(new Ui::TimerDialog){
    ui->setupUi(this);
    // 建立信号和槽的连接
    connect(&m_clock,SIGNAL(timeout()),this,SLOT(on_m_clock_timeout()));
    m_clock.start(1000);   // 每隔1000ms触发一次定时器事件
}
// 定时器信号的槽函数
void TimerDialog::on_m_clock_timeout(){
    // 获取当前时间
    QTime now = QTime::currentTime();
    ui->m_ladH->display(QString::number(now.hour()));
    ui->m_ladM->display(QString::number(now.minute()));
    ui->m_ladS->display(QString::number(now.second()));
}

以上就能实现在ui上显示电子时钟
4:实现计时器功能,生成开始、复位按钮的槽函数

// 开始按钮槽函数
void TimerDialog::on_m_btnStart_clicked(){}
// 复位按钮槽函数
void TimerDialog::on_m_btnRest_clicked(){}

5: 使用计时器,每1ms触发一次定时器事件,需要重写定时器事件函数

void TimerDialog::timerEvent(QTimerEvent *){}

6: 在TimerDialog.h中定义定时器相关的成员变量、声明相关的函数定义

private slots:
	// 开始按钮槽函数
    void on_m_btnStart_clicked();
	// 复位按钮槽函数
    void on_m_btnRest_clicked();
protected:
	// 定时器事件函数
    void timerEvent(QTimerEvent *);
private:
    int m_TimerId;// 定时器ID 用于关闭定时器
    QTime m_time;// 当前时间

7:书写定时器开始函数,实现点击开始按钮,开始计时功能

void TimerDialog::on_m_btnStart_clicked()
{
    if(ui->m_btnStart->text()=="开始"){
        m_TimerId=startTimer(1);// 每1ms触发一次定时器事件
        ui->m_btnStart->setText("停止");
        ui->m_btnRest->setEnabled(false);// 关闭复位键使能
    }else{
        // 关闭定时器事件
        killTimer(m_TimerId);
        ui->m_btnStart->setText("开始");
        ui->m_btnRest->setEnabled(true);// 打开复位键使能
    }
}
// 每1ms触发一次定时器事件
// 定时器事件函数
void TimerDialog::timerEvent(QTimerEvent *){
	m_time=m_time.addMSecs(1);
    ui->m_lcdE->display(m_time.toString("HH:mm:ss.zzz"));
}

8: 书写复位按钮,实现点击复位按钮时,能够清除计时

void TimerDialog::on_m_btnRest_clicked()
{
      m_time.setHMS(0,0,0);
      ui->m_lcdE->display(m_time.toString("HH:mm:ss.zzz"));
}

9:在构造函数中,初始化当前时间等自定义的成员变量

TimerDialog::TimerDialog(QWidget *parent): QDialog(parent), ui(new Ui::TimerDialog){
	ui->setupUi(this);
     on_m_btnRest_clicked();// 复位
}

1.6 鼠标事件

  • QWidget类定义了以下虚函数提供对鼠标事件的处理,其参数QMouseEvent描述了鼠标事件的细节,如引发事件的鼠标按键、鼠标所在位置等
    • virtual void mousePressEvent (QMouseEvent* e);// 鼠标按下
    • virtual void mouseReleaseEvent(QMouseEvent* e); //鼠标抬起
    • virtual void mouseDoubleClickEvent(QMouseEvent* e);//鼠标双击
    • virtual void mouseMoveEvent (QMouseEvent* e);//鼠标移动
  • 案例:通过鼠标左键实现拖拽label方块移动
    1:设计UI
旋转label-palette -继承 -改变调色板-快速-选中颜色-OK
	autofillBackGround- √

2:重写鼠标事件函数

// mouseDialog.h文件中引入QMouseEvent,声明以下事件函数
protected:
    //按下事件
    void mousePressEvent(QMouseEvent*);
    // 移动事件
    void mouseMoveEvent(QMouseEvent*);
    // 松开
    void mouseReleaseEvent(QMouseEvent*);
    
// mouseDialog.cpp文件中重写事件函数
// 鼠标按下事件
void mouseDialog::mousePressEvent(QMouseEvent * e){}
// 移动
void mouseDialog::mouseMoveEvent(QMouseEvent* e){}
// 松开
void mouseDialog:: mouseReleaseEvent(QMouseEvent* e){}

3:书写鼠标按下事件
① 需要获取到按下的鼠标键
② 查看鼠标键是否在label区域内

// 鼠标按下事件
// button - 获取按键
// frameRect - 获取组件的区域
// contains - 包含
// QPoint - 坐标
// pos()-鼠标的坐标
void mouseDialog::mousePressEvent(QMouseEvent * e){
   if(e->button()==Qt::LeftButton){// 获取按下的键
        qDebug("11");
       QRect blockRect = ui->m_label->frameRect();// 获取m_label组件的区域
       blockRect.translate(ui->m_label->pos());// 让滑块和鼠标保持同一个坐标系
       if(blockRect.contains(e->pos())){// 获取当前按下的坐标是否位于当前区域中
           m_dragging =true;// 鼠标在区域内额标志位
           // 鼠标的偏移量
           m_offset = ui->m_label->pos()-e->pos();
       }
   }
}

4:书写鼠标移动事件函数

void mouseDialog::mouseMoveEvent(QMouseEvent* e){
    if(m_dragging){
        QPoint labelPos = e->pos()+m_offset;
        ui->m_label->move(labelPos);
    }
}

5: 书写鼠标松开事件

void mouseDialog:: mouseReleaseEvent(QMouseEvent* e){
    if(e->button()==Qt::LeftButton){
        m_dragging = false;
    }
}

6: 限制label滑块活动的区域
在这里插入图片描述

void mouseDialog::mouseMoveEvent(QMouseEvent* e){
    if(m_dragging){
        QPoint labelPos = e->pos()+m_offset;
        // 因为鼠标可能移除窗口外,需要限定活动的区域范围
        // 获取主窗口的大小
        QSize windowSize = size();
        // 获取label的大小
        QSize labelSize = ui->m_label->size();
        int xMin =0,xMax=windowSize.width()-labelSize.width();
        int yMin=0,yMax=windowSize.height()-labelSize.height();
        // 限制滑块活动范围
        // x活动范围是否在允许范围
        labelPos.setX(max(min(xMax,labelPos.x()),xMin));
        // y活动范围是否在允许范围
        labelPos.setY(max(min(yMax,labelPos.y()),yMin));
        // 滑块移动
        ui->m_label->move(labelPos);
    }
}

1.7 键盘事件

QWidget类定义了以下虚函数提供对键盘事件的处理,其参数QKeyEvent描述了键盘事件的细节,如引发事件的键盘按键、文本等
virtual void keyPressEvent(QKeyEvent* e);//按键按下
virtual void keyReleaseEvent(QKeyEvent* e);//按键抬起
具体的使用同鼠标事件

1.8 绘图事件

通过绘图事件,可以实现自定义的图像绘制,当有下列情况之一发生时,将触发窗口的绘制事件,即QWidget类的paintEvent()虚函数会被调用:

  • 窗口被创建以后第一次显示出来
  • 窗口由隐藏状态转变为可见状态
  • 窗口由最小化状态转变为正常或最大化状态
  • 窗口因尺寸大小的变化需要呈现更多的内容
  • QWidget类的update()/repaint()成员函数被调用
    如果希望在自己的窗口中显示某个图像,在QWidget的窗口子类中可以重写绘图事件函数paintEvent,在其中可用QPainter(Qt二维图形引擎)实现指定的图像绘制、渲染等操作
  • 案例:基于资源的图片浏览器
    1:添加图片资源
1.将带有图片的images目录拷贝到项目目录下 
2.右击项目 - add new...  - Qt - Qt Resource File - 
	名称 - Pictures - 各种下一步
3.add prefix - 前缀   / 
4.add files - 进入到images目录下 - 选中所有 - 打开 - ok 

2:设计UI

QFrame 
	objecname - m_frmImage
	sizePolicy - 垂直策略 - expanding
pushbutton
	objecname - m_btnPrev
	text - 上一张
pushbutton:
	objecname - m_btnNext
	text - 下一张
为上一张和下一张按钮添加槽函数,右单机 转到槽
	上一张/下一张 - 右击 - 转到槽 - clicked - 

3:重写绘图事件函数

// 绘图事件 引入的头文件有QPainter 和 QPaintEvent
void pictureDialog:: paintEvent(QPaintEvent *){
    // QT二维图形引擎
    QPainter painter(this);
    // 获取当前区域
     QRect qrect = ui->m_fraPicture->frameRect();
    // 调整坐标系为同一个坐标系
    qrect.translate(ui->m_fraPicture->pos());
    // 获取图像
    QImage image(":/images/" + QString::number(m_imageIndex) + ".jpg");
    // 将图片贴到画框中
    painter.drawImage(qrect,image);
}

4:书写上一张、下一张的槽函数

// 上一张槽函数
void pictureDialog::on_m_btnPrev_clicked()
{
    m_imageIndex--;
    enableButtons();
    update();//触发绘图事件
}
// 下一张槽函数
void pictureDialog::on_m_btnNext_clicked()
{
    m_imageIndex++;
    enableButtons();
    update();//触发绘图事件
}
void  pictureDialog::enableButtons(void){
    ui->m_btnPrev->setEnabled(m_imageIndex !=0); // 最小的索引下标
    ui->m_btnNext->setEnabled(m_imageIndex!=7);// 最大的索引下标
}

5:头文件中的声明主要有

private slots:
    void on_m_btnPrev_clicked(); // 上一页的槽函数
    void on_m_btnNext_clicked(); // 下一页的槽函数
    void enableButtons(void);// 按钮的使能
protected:
    void paintEvent(QPaintEvent *); // 绘图事件
private:
    int m_imageIndex;// 图片索引 需要在构造函数中初始化

2、绘画

2.1 画笔

  • QPen:用于设置线条的颜色、宽度、线型等
  • 常用函数
函数原型功能
void setColor(QColor& color)设置画笔颜色,即线条颜色
void setWidth(int width)设置线条宽度
void setStyle(Qt::PenStyle style)设置线条样式,参数为Qt:PenStyle枚举类型
void setCapStyle(Qt::PenCapStyle style)设置线条端点样式,参数为Qt:PenCapStyle枚举类型
void setJoinStyle(Qt::PenJoinStyle style)设置连接样式,参数为Qt:PenJoinStyle枚举类型

在这里插入图片描述

2.2 画刷

  • QBrush:用于设置一个区域的填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片做材质填充
  • 常用函数
函数原型功能
void setColor(QColor& color)设置画刷颜色,实体填充时即为填充颜色
void setStyle(Qt::BrushStyle style)设置画刷样式,参数为Qt:BrushStyle枚举类型
void setTexture(QPixmap& pixmap)设置一个QPixmap:类型的图片作为画刷的图片,
画刷样式自动设置为Qt:TexturePalette
void setTexturelmage(Qlmage& image)设置一个QImage:类型的图片作为画刷的图片,
画刷样式自动设置为Qt:TexturePalette

在这里插入图片描述

2.3 字体

  • QFont:用于设置绘制文本的字体
  • 常用函数
函数原型功能
void setBold(bool enable)设置字体是否为粗体
QFont::Bold QFont::Normal)
void setFamily(const QString &family)设置字体的字体名称
void setltalic(bool enable)设置字体是否为斜体
(QFont::Styleltalic QFont::StyleNormal)
void setUnderline(bool enable)设置字体是否有下划线
void setWeight(int weight)设置字体的粗细,参数为QFont:Weight类型
void setPointSize(int pointSize)设置字体的大小

2.4 绘图系统

  • QPainter:是用来进行绘图操作的类
  • QPaintDevice是一个可以使用QPainter进行绘图的抽象的二维界面
    • QWidget
    • QPixmap
    • QImage
  • 案例 使用QPen 、QBrush、QPainter画画
    在这里插入图片描述
// 绘画事件
oid PaintDialog:: paintEvent(QPaintEvent *){
    QPainter painter(this); // 绘制一个矩形,填充为黄色,线条颜色为红色
    QPen pen;    // 画笔
    pen.setColor(Qt::red); // 线条颜色
    pen.setWidth(5);// 线条宽度
    pen.setStyle(Qt::DashDotLine);// 线条样式
    painter.setPen(pen);
   // 画刷 内部填充的颜色
    QBrush brush;
    brush.setColor(Qt::yellow);
    brush.setStyle(Qt::SolidPattern);
    painter.setBrush(brush);
    // 设置绘画区域 绘画
    int w=width();
    int h=height();
    painter.drawRect(QRect(QPoint(w/5,h/5),QPoint(w/5*4,h/5*4)));
    
    pen.setColor(Qt::blue); // 线条颜色
    pen.setWidth(3);// 线条宽度
    pen.setStyle(Qt::SolidLine);// 线条样式
    painter.setPen(pen);
    // 填充图片
    brush.setTextureImage(QImage(":/images/1.png"));
    brush.setStyle(Qt::TexturePattern);
    painter.setBrush(brush);
    painter.drawRect(QRect(QPoint(w/5*2,h/5*2),QPoint(w/5*3,h/5*3)));
}

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

启航zpyl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值