【Qt】day3 自定义控件、框架、定时器、QPainter、QFile

文章目录

自定义控件封装

1.创建新文件-Qt-设计师界面类(.h .cpp .ui)

2.以QSpinBox和QSlider为例子。在.ui中设计这两个控件

3.在主ui中添加Widget,并把它升级。

类名称为自己在添加新文件(设计师界面类)写的。
若这个自定义控件经常用到,可以设为全局包含

  1. 添加两个按钮btn_get和btn_set

5.实现函数:改变数字,滑动条跟着移动 ,信号槽监听。在新组建.cpp中完成实现。

复制代码
    //QSpinBox移动 QSlider跟着移动
    void(QSpinBox:: * spSignal)(int) = &QSpinBox::valueChanged;
    connect(ui->spinBox,spSignal,ui->horizontalSlider,&QSlider::setValue);

    //QSlider滑动 QSpiBox数字跟着改变
    connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);

6.提供 getNum 和 setNum对外接口:在新组件.h声明两个函数。在新组件.cpp中实现这两个函数

自定义框架

1.创建新文件-C/C+±Class,我这里命名为myLable.

2.改3处类名

3.在头文件写函数声明

cpp 复制代码
    //鼠标进入事件
    void enterEvent(QEnterEvent *event);
    //鼠标离开事件
    void leaveEvent(QEvent *);

    //鼠标按下
    virtual void mousePressEvent(QMouseEvent *ev);
    //鼠标释放
    virtual void mouseReleaseEvent(QMouseEvent *ev);

    //鼠标移动
    virtual void mouseMoveEvent(QMouseEvent *ev);

4.在源文件实现函数

cpp 复制代码
myLabel::myLabel(QWidget *parent)
    : QLabel{parent}
{
    //设置鼠标追踪状态
    setMouseTracking(true);
}

// 鼠标进入事件
void myLabel::enterEvent(QEnterEvent *event)
{
    qDebug()<<"鼠标进入了";

}

void myLabel::leaveEvent(QEvent *)
{
    qDebug()<<"鼠标离开了";
}

//鼠标按下
void myLabel::mousePressEvent(QMouseEvent *ev)
{
    // if(ev->button()==Qt::LeftButton){
        QString str = QString("鼠标按下了 x=%1 y=%2 globalX= %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug()<<str;
    // }


}
//鼠标释放
void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{
    // if(ev->button()==Qt::LeftButton){
        QString str = QString("鼠标按下了 x=%1 y=%2 globalX= %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug()<<str;
    // }
}

//鼠标移动
void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
//    if(ev->buttons() & Qt::LeftButton){*/ //移动是一个状态
        QString str = QString("鼠标移动了 x=%1 y=%2 globalX= %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug()<<str;
    // }
}
鼠标事件 代码
鼠标进入 enterEvent
鼠标离开 leaveEvent
鼠标按下 mousePressEvent ( QMouseEvent ev)
鼠标释放 mouseReleaseEvent
鼠标移动 mouseMoveEvent
鼠标坐标 ev->x() x坐标 ev->y() y坐标
判断所有按键 ev->button()
左按键/右按键 Qt::LeftButton / Qt::RightButton
判断组合按键 判断move时候的左右键 结合 & ev->buttons()
格式化字符串 QString( " %1 %2 " ).arg( 111 ).arg(222)
设置鼠标追踪 setMouseTracking(true);

定时器

第一种方式

1.在ui界面创建两个label_2和label_3

2.在widget.h中,写定时器的函数声明和2个公有变量

cpp 复制代码
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //重写定时器事件
    void timerEvent(QTimerEvent *);

    int id1;//定时器1的唯一标识
    int id2;//定时器2的唯一标识


private:
    Ui::Widget *ui;
};

3.在源文件写函数实现和调用定时器。

cpp 复制代码
Widget::Widget(QWidget *parent): QWidget(parent),ui(new Ui::Widget)
{
    ui->setupUi(this);
    //启动定时器
    id1 = startTimer(1000);
    id2 = startTimer(2000);
}

void Widget::timerEvent(QTimerEvent *ev)
{
    if(ev->timerId() == id1)
    { 
        static int num = 1;
        //label2 每隔1秒+1
        ui->label_2->setText(QString::number(num++));
    }
    
    if(ev->timerId() == id2)
    {
        static int num2 = 1;
        //label3 每隔2秒+1
        ui->label_3->setText(QString::number(num2++));
    }
}

第二种方式 (推荐)

1.ui界面设计两个按钮btn,btn1,一个label_4

2.在源文件,实现按键的功能和启动定时器

加入头文件<QTimer>

利用定时器类 QTimer
创建定时器对象 QTimer * timer = new QTimer(this);
启动定时器 timer->start(毫秒)

每隔一定毫秒,发送信号 timeout ,进行监听
暂停 timer->stop

事件分发器

相当于总控,在一些情况下可以屏蔽某些键位

以屏蔽"鼠标按下"为例.

1.在头文件添加函数声明

cpp 复制代码
    //通过event事件分发器 拦截 鼠标按下事件
    bool event(QEvent *e);

2.在源文件实现函数

cpp 复制代码
bool myLabel::event(QEvent *e)
{
    if(e->type()==QEvent::MouseButtonPress)
    {
        QMouseEvent * ev = static_cast<QMouseEvent *>(e); //转为QMouseEvent类型
        QString str = QString("Event函数中::鼠标按下了 x=%1 y=%2 globalX= %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
        qDebug()<<str;

        return true;  //ture代表用户自己处理这个事件,不向下分发
    }
    //其他事件 交给父类处理 默认处理
    return QLabel::event(e);
}

3.效果如图

小结:

用途:事件的分发,也可以做拦截操作

bool event( QEvent * e);

如果返回值是true 代表用户处理这个事件,不向下分发了

QPainter

基本操作

1.在头文件声明函数

cpp 复制代码
    //绘图事件
    void paintEvent(QPaintEvent * );

2.在源文件实现函数

记得要引入类#include <QPainter>

cpp 复制代码
void Widget::paintEvent(QPaintEvent * )
{
    //实例化画家对象 this指定的是绘画设备
    QPainter painter(this);

    //设置画笔
    QPen pen(QColor(255,0,0));
    //设置画笔宽度
    pen.setWidth(3);
    //设置画笔风格
    pen.setStyle(Qt::DotLine);
    //让画家使用这支笔
    painter.setPen(pen);

    //设置画刷
    QBrush brush(Qt::cyan);
    //设置画刷风格
    painter.setBrush(Qt::Dense7Pattern);
    //让画家使用画刷
    painter.setBrush(brush);

    //画线
    painter.drawLine(QPoint(0,0),QPoint(100,100));

    //画圆
    painter.drawEllipse(QPoint(100,100),50,50);

    //画矩形
    painter.drawRect(QRect(20,20,60,60));

    //画文字
    painter.drawText(QRect(10,200,150,50),"好好学习,天天向上");
}

小结:
绘图事件 void paintEvent()
声明一个画家对象 QPainter painter(this) this指定绘图设备

画线、画圆、画矩形、画文字
设置画笔 QPen 设置画笔宽度 、风格
设置画刷 QBrush 设置画刷 风格

高级设置

抗锯齿

1.在头文件声明函数

cpp 复制代码
    //绘图事件
    void paintEvent(QPaintEvent * );

2.在源文件函数实现

cpp 复制代码
void Widget::paintEvent(QPaintEvent * )
{
    QPainter painter(this);
    painter.drawEllipse(QPoint(100,50),50,50);
    //设置 抗锯齿能力 效率较低
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawEllipse(QPoint(200,50),50,50);
}

移动坐标原点

cpp 复制代码
void Widget::paintEvent(QPaintEvent * )
{
    //画矩形
    painter.drawRect(QRect(20,20,50,50));
    //移动画家
    painter.translate(100,0);
    //保存画家状态
    painter.drawRect(QRect(20,20,50,50));
    painter.translate(100,0);

    //还原画家保存状态
    painter.drawRect(QRect(20,20,50,50));
}

画家画资源图片,并实现手动移动

1.导入资源图片

2.在ui界面设计一个按钮

3.在头文件声明函数和全局变量

cpp 复制代码
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    //绘图事件
    void paintEvent(QPaintEvent * );
    int posX=0;

4.在源文件实现函数

cpp 复制代码
#include <QPainter>//画家

void Widget::paintEvent(QPaintEvent * )
{
    QPainter painter(this);
    //如果超出屏幕 从0开始
    if(posX>this->width())
    {
        posX=0;
    }
    painter.drawPixmap(posX,0,QPixmap(":/Image/Luffy.png"));
}

5.在源文件实现按钮

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //点击移动按钮 移动图片
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        posX+=20;
        //如果要手动调用绘图事件 用update更新
        update();
    });
}

6.实现效果如下

小结:
抗锯齿 效率低

painter.setRenderHint(QPainter::Antialiasing);
对画家进行移动

painter.translate(100,0);
保存状态 save
还原状态 restore
如果想手动调用绘图事件 利用update
利用画家画图片 painter.drawPixmap( x,y,QPixmap( 路飞) )

作业

实现路飞的自动移动,即自动连播。

头文件

cpp 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

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 * );
    int posX=0;

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

源文件

cpp 复制代码
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>//画家
#include <QTimer>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QTimer * timer = new QTimer(this);
    timer->start(500);

    connect(timer,&QTimer::timeout,[=](){
        posX+=20;
        update();
    });
}

void Widget::paintEvent(QPaintEvent * )
{
    QPainter painter(this);
    if(posX>this->width())
    {
        posX=0;
    }
    painter.drawPixmap(posX,0,QPixmap(":/Image/Luffy.png"));
}

Widget::~Widget()
{
    delete ui;
}

QPaintDevice绘图设备

QPixmap

对不同平台做了显示的优化

QPixmap pix( 300,300)

pix.fill( 填充颜色 )
利用画家 往pix上画画 QPainter painter( & pix)
保存 pix.save( "路径")

Qimage

可以对像素进行访问

使用和QPixmap差不多 QImage img(300,300,QImage::Format_RGB32);

其他流程和QPixmap一样
可以对像素进行修改 img.setPixel(i,j,value);

QPicture

记录和重现 绘图指令

QPicture pic

painter.begin(&pic);
保存 pic.save( 任意后缀名 )
重现 利用画家可以重现painter.drawPicture(0,0,pic);

QFile文件读写操作

1.在ui文件创建如下页面

2.文件为utf-8文件,进行读操作

添加头文件#include <QFileDialog> #include <QFile>

cpp 复制代码
    //点击选取文件按钮,弹出文件对话框
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\Gemini\\Desktop\\Qt-学习\\QT资料\\day3资料\\Doc");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //读取内容 放入到 textEdit中
        QFile file(path);  //参数是读取文件的路径
        //设置打开方式
        file.open(QIODevice::ReadOnly);

        //QByteArray array = file.readAll();两种读结果都一样
        QByteArray array;
        while(!file.atEnd())
        {
            array+=file.readLine();//按行读   
        }
        //将读取到的数据放入textEdit中
        ui->textEdit->setText(array);
        //对文件对象进行关闭
        file.close();
    });

3.进行写操作

cpp 复制代码
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\Gemini\\Desktop\\Qt-学习\\QT资料\\day3资料\\Doc");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);

        //读取内容 放入到 textEdit中
        QFile file(path);  //参数是读取文件的路径
        
        //进行写操作
        file.open(QIODevice::Append);//用追加方式去进行写
        file.write("啊啊啊啊");
        file.close();
}

4.读写结合如下

QFileInfo文件信息获取

添加头文件include <QFileInfo>

在源代码

cpp 复制代码
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\Gemini\\Desktop\\Qt-学习\\QT资料\\day3资料\\Doc");
        //将路径放入到lineEdit中
        ui->lineEdit->setText(path);
        QFileInfo info(path);
        qDebug()<<"大小:"<<info.size()<<"后缀名"<<info.suffix()<<"文件名称:"<<info.fileName()<<"文件路径:"<<info.filePath();
        qDebug()<<"创建日期:"<<info.birthTime().toString("yyyy/MM/dd hh:mm:ss");
        qDebug()<<"最后修改日期"<<info.lastModified().toString("yyyy/MM/dd hh:mm:ss");
	}
相关推荐
腾讯TNTWeb前端团队2 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰5 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪5 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪5 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy6 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom7 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom7 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom7 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom7 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom7 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试