目录

  • 第三天
  • 1 自定义控件封装
  • 2 QT鼠标事件
  • 3 定时器
  • 4 event事件分发器
  • 5 事件过滤器
  • 6 绘图事件Qpainter
  • 6.1 高级绘图
  • 6.2 绘图画图片
  • 6.3 绘图设备
  • 6.4 Qpixmap
  • 6.5 Qimage
  • 6.6 Qpicture
  • 7 文件读写


源码:CPP学习代码

第三天

1 自定义控件封装

新建一个QT widgetclass,同时生成ui,h,cpp文件

qt 封装sqlite 类_控件


在smallWidget.ui里添加上你想要的控件并调试大小

qt 封装sqlite 类_qt_02


回到mainwidget.ui,拖入一个widget(因为我们封装的也是widget),右击提升为,输入名字(名字一定要写对)。

qt 封装sqlite 类_qt_03

此时还需要进入mainWidget.h,按住ALT进入"ui_mainWidget.h",修改smallWidget的<>为引号“”(“”是本地的头文件),这时候运行就能看到我们的控件了。

qt 封装sqlite 类_开发语言_04

在smallwidget.cpp里编写代码,让这两个控件QspinxBox和QSilder联系起来,查找手册里的信号和槽,没有就查找父类

//QspinxBox移动,QSlider跟着移动 查手册,没有就查父类
connect(ui.spinBox,&QSpinBox::valueChanged,ui.horizontalSlider,&QSlider::setValue);
//QSilder移动,QspinxBox跟着移动
connect(ui.horizontalSlider, &QSlider::sliderMoved,ui.spinBox, &QSpinBox::setValue);

再添加两个按钮,一个显示值,一个让值变成一半

在smallwidget头文件里定义两个函数,并到cpp里实现

//设置值
void setNumber(int value);
//得到值
int getNumber();

void smallWidget::setNumber(int value)
{
 //设置值
 ui.spinBox->setValue(value);
}

int smallWidget::getNumber()
{
 //返回值
 return ui.spinBox->value();
}

再到mainwidget.cpp里实现信号的连接,由于smallwi是连接到mainwi里边的widget,所以可以通过ui来访问widget来得到我们定义的函数

//点击获取值
connect(ui.btn1,&QPushButton::clicked,[=](){
   qDebug()<< ui.widget->getNumber();
});
//点击设置值
connect(ui.btn2, &QPushButton::clicked, [=]() {
    ui.widget->setNumber(50);
 qDebug() << ui.widget->getNumber();
});

qt 封装sqlite 类_qt_05

2 QT鼠标事件

Enterevent,鼠标进入这个控件就会被捕捉。

不想用ui,只想用自定义事件来捕捉鼠标,就新建一个QTclass,只要h和cpp。查询手册鼠标进入和鼠标退出的函数,直接复制。

//鼠标进入
void enterEvent(QEnterEvent* event);

//鼠标离开
void leaveEvent(QEvent* event);

void mylabel::enterEvent(QEnterEvent * event)
{
 qDebug() <<"鼠标进入了";
}

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

在ui中拖入label,因为我们使用的Qlabel,所以这个mylabel.h和cpp应该继承QLabel,更改以下三处

qt 封装sqlite 类_开发语言_06

然后跟上边一样将这个更主界面连接起来,ui界面右键提升为,输入名字,然后修改ui_mainWidget.h里边将mylabely的引用改为“”。此时运行就会发现能够捕捉到鼠标

qt 封装sqlite 类_开发语言_07

在查询手册,QLabel还有很多对鼠标的操作,我们直接复制来实现,可以在点击时实现输出,移动时输出需要更改因为移动是一个过程。Qstring格式化输出Qstring(%1 %2).arg(参数1).arg(参数2)

qt 封装sqlite 类_开发语言_08

void mylabel::mousePressEvent(QMouseEvent* ev)
{
 //QT6很多都删了但是还能使用,不推荐
 if(ev->button() == Qt::LeftButton)
 {
  QString str = QString("鼠标按下 x =%1  y =%2 globalx=%3 ").arg(ev->pos().x()).arg(ev->pos().y()).arg(ev->globalPosition().toPoint().x());
  qDebug() << str;
 }
}

void mylabel::mouseReleaseEvent(QMouseEvent* ev)
{
 if (ev->button() == Qt::LeftButton)
 {
  qDebug() << "鼠标释放";
 }
}

void mylabel::mouseMoveEvent(QMouseEvent* ev)
{
 //因为移动是个过程,所以直接==不能够触发,这边用的是buttons,里边包含了三种状态,使用与操作符,当状态和Leftbutton相同时触发
 if (ev->button() & Qt::LeftButton)
 { 
  qDebug() << "鼠标移动111";
 }
}

在构造函数里添加上鼠标追踪,就不用判断是否点击或者移动来打印信息,会实时打印

mylabel::mylabel(QWidget*parent)
 : QLabel(parent)
{
 //设置鼠标追踪,默认false
 setMouseTracking(true);
}

3 定时器

使用时间间隔来做出动作,可以让数加一。首先得在头文件里重写定时器事件timerEvent,可以定义定时器的id,startimer启动定时器,让不同的控件有不同的时间间隔,通过timerId()来指定对应的计时器。第二种方式,直接使用QTimer新建一个对象,使用timeout信号连接即可。

//.h
//重写定时器事件
void timerEvent(QTimerEvent *event);
 
int id1;//定时器的id
int id2;//定时器的id

//.cpp
#include <QTimer>
mainWidget::mainWidget(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    //启动定时器
    id1 = startTimer(1000);//单位毫秒,每隔一秒调用函数

    id2 = startTimer(2000);//单位毫秒,每隔2秒调用函数

 //定时器的第二种方式
 QTimer* timer = new QTimer(this);
 //启动定时器
 timer->start(500);

 connect(timer,&QTimer::timeout,[=](){
  static int num2 = 1;
  ui.label3->setText(QString::number(num2++));
 });
  //点击按钮暂停

  connect(ui.btn1,&QPushButton::clicked,\[=\](){

    timer->stop();
  });
}

mainWidget::~mainWidget()
{}

void mainWidget::timerEvent(QTimerEvent * event)
{

 if (event->timerId() == id1)
 {
  static int num = 1;
  ui.label2->setText(QString::number(num++));
 }
 //   //两秒跳一次
 //if (event->timerId() == id2)
 //{
 //        static int num2 = 1;
 //        ui.label3->setText(QString::number(num2++));
 //}
    
}

4 event事件分发器

每个发出的响应都会经过这个事件分发器,如果返回true就直接截胡了,相当于你点击鼠标是不触发鼠标点击而触发你定义的事件

qt 封装sqlite 类_qt_09

type里边有很多的事件

qt 封装sqlite 类_开发语言_10

如果返回值是true代表用户需要拦截处理这个事件不向下分发

//.h
//通过Event事件分发器拦截鼠标按下事件
bool event(QEvent *e);

//.cpp
bool mylabel::event(QEvent* e)
{
 //如果是鼠标按下,在event事件分发中做拦截操作
 if (e->type() == QEvent::MouseButtonPress)
 {
  //类型转换,e是ev的父类
  QMouseEvent* ev = static_cast<QMouseEvent*>(e);
  QString str = QString("鼠标按下222 x =%1  y =%2 globalx=%3 ").arg(ev->pos().x()).arg(ev->pos().y()).arg(ev->globalPosition().toPoint().x());
  qDebug() << str;

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

5 事件过滤器

相当于拦截了事件分发器。使用过程两个步骤,1、给控件安装事件过滤器,2、重写eventfilter事件

qt 封装sqlite 类_qt 封装sqlite 类_11

//.h
 //在widget中重写eventfilter事件
 bool eventFilter(QObject *watched, QEvent *event);

//.cpp
//给label1安装事件过滤器
//1、构造函数里安装事件过滤器
ui.label1->installEventFilter(this);

//2、重写事件,obj就是控件
bool mainWidget::eventFilter(QObject* watched, QEvent* event)
{
 if (watched == ui.label1)
 {
  if (event->type() == QEvent::MouseButtonPress)
  {
   //类型转换,e是ev的父类
   QMouseEvent* ev = static_cast<QMouseEvent*>(event);
   QString str = QString("事件过滤器鼠标按下 x =%1  y =%2 globalx=%3 ").arg(ev->pos().x()).arg(ev->pos().y()).arg(ev->globalPosition().toPoint().x());
   qDebug() << str;
  }
 }
 //默认交给父类处理
 return QWidget::eventFilter(watched,event);
}

6 绘图事件Qpainter

整体比较简单。只需要重写panitEvent事件,并且声明画家对象,笔刷画笔也只需要先声明对象。

//.h
//绘图事件
void paintEvent(QPaintEvent *);

//.cpp
void mainWidget::paintEvent(QPaintEvent*)
{
    //实例化画家对象,this指定的是绘图设备
    QPainter painter(this);
    //设置画笔
    QPen pen(QColor(255,0,0));
    pen.setWidth(3);//宽度
    pen.setStyle(Qt::DotLine);//风格
    //使用画笔,红色
    painter.setPen(pen);

    //画刷,会填充封闭的图形
    QBrush brush(QColor(0,255,0));
    painter.setBrush(brush);
    //画线
    painter.drawLine(QPoint(0,0),QPoint(100,100));
    //画圆
    painter.drawEllipse(QPoint(100,100),50,50);
    //画矩形
    painter.drawRect(50,50,50,50);
    //画文字
    painter.drawText(QRect(10,200,150,50),"学习");
}

qt 封装sqlite 类_开发语言_12

6.1 高级绘图

可以添加抗锯齿,让图像看来更清晰painter.setRenderHint(QPainter::Antialiasing);

还可以设置保存点,移动初始绘图点后保存,后边还能拿来用,如下变,本来应该是画三个矩形,但是恢复了保存点,第三个矩形和第二个矩形绘制重叠了。

qt 封装sqlite 类_开发语言_13

高级绘图/
   //指定当前窗口绘图
   QPainter painter(this);
画圆
//painter.drawEllipse(QPoint(100,100),50,50);
//   //设置抗锯齿
//   painter.setRenderHint(QPainter::Antialiasing);
//   painter.drawEllipse(QPoint(200, 200), 50, 50);

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

   //移动画家,水平移动,绘画的初始点移动
   painter.translate(100,0);
   //相当于保存这个移动后的点
   painter.save();
   painter.drawRect(QRect(20, 20, 50, 50));

   painter.translate(100, 0);
   //复原状态,相当于退回到保存点
   painter.restore();
   painter.drawRect(QRect(20, 20, 50, 50));

6.2 绘图画图片

使用drawPixmap放置图片,使用按钮让图片移动,重新绘制使用upadte()

//.h
//绘图事件
void paintEvent(QPaintEvent *);

int pos = 0;


//.cpp
mainWidget::mainWidget(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    //点击按钮移动图片
 connect(ui.btn1, &QPushButton::clicked, [=]() {
    //如果要手动调用绘图事件使用update
        pos += 20;
        update();
 });
}
void mainWidget::paintEvent(QPaintEvent*)
{
    画资源图片/
 //指定当前窗口绘图
 QPainter painter(this);

    if (pos>this->width())
    {
        pos = 0; 
    }
    painter.drawPixmap(pos,0,QPixmap(":/Image/butterfly.png"));

}

6.3 绘图设备

l QPixmap专门为图像在屏幕上的显示做了优化

l QBitmap是QPixmap的一个子类,它的色深限定为1(只有黑白图),可以使用 QPixmap的isQBitmap()函数来确定这个QPixmap是不是一个QBitmap。

l QImage专门为图像的像素级访问做了优化(可以访问每个像素)。

l QPicture则可以记录和重现QPainter的各条命令。

6.4 Qpixmap

这样会在本地得到一张背景为白色的圆

//pixmap绘图设备
QPixmap pix(300,300);

//填充背景颜色
pix.fill(Qt::white);

//声明画家
QPainter painter(&pix);
painter.setPen(QPen(Qt::green));
painter.drawEllipse(QPoint(150,150),100,100);

//保存
pix.save("E:\\pix.png");

6.5 Qimage

如果只是在本地保存一张图片那么书写的代码和上边几乎一样,就是更改绘图设备没QImage。它的强大之处在于能够修改像素。

我们首先对绘图事件进行重载,然后使用for循环更改像素值,修改后我们能看到中间一块变红了

//.h
  //绘图事件
  void paintEvent(QPaintEvent *);

//.cpp
void mainWidget::paintEvent(QPaintEvent*)
{
    //绘图窗口
    QPainter painter(this);

    //利用QImage修改像素
    QImage img;
    img.load(":Image/butterfly.png");

    //修改像素点
    for (int i = 50; i<100;i++)
    {
        for (int j = 50; j<100;j++)
        {
            //设置像素点的值
            QRgb value = qRgb(255,0,0);
            img.setPixel(i,j,value);
        }
    }
    painter.drawImage(0,0,img);

}

qt 封装sqlite 类_控件_14

6.6 Qpicture

主要是用来记录操作,可以把操作保存下来,再次加载

//mianWidget
 //QPicter绘图设备,可以记录和重新绘图指令
 QPicture pic;
 QPainter painter;
 painter.begin(&pic); //开始往上画
 painter.setPen(QPen(Qt::cyan));
 painter.drawEllipse(QPoint(150, 150), 100, 100);
 painter.end();//结束画画

 //保存在磁盘
 pic.save("E:\\pic.zt");

void mainWidget::paintEvent(QPaintEvent*)
{
    QPainter painter(this);
    //重现QPicture指令
    QPicture pic;
    pic.load("E:\\pic.zt");
    painter.drawPicture(0,0,pic);
}

7 文件读写

首先先搭建选取文件的界面,一个按钮,一个lineedit,一个text widget,然后编写代码,点击按钮选择文件,显示路径和内容,其中utf-8和gbk的文件读取方式不一样

查询手册有这些值可以选

qt 封装sqlite 类_开发语言_15

//点击按钮弹出文件对话框
connect(ui.pushButton,&QPushButton::clicked,[=](){

    QString path = QFileDialog::getOpenFileName(this,"打开文件",":/132.txt");
    //将路径放到lineedit中
    ui.lineEdit->setText(path);

    //读取内容,放入textedit
    //Qfile默认格式是UTF-8
    

    QFile file(path);//参数就是读取路径
    //设置打开方式
    file.open(QIODeviceBase::ReadOnly);
    
   
    /*QByteArray array =  file.readAll();*/
    QByteArray array;
    while (!file.atEnd()) 
    {
        array += file.readLine();
    }

    //将读到的数据放入到textedit中
    //QString content = QString::fromLocal8Bit(array); //读取gkb格式用这个
    ui.textEdit->setText(array);
    //关闭
    file.close();

接下来开始一追加方式写入文件,并不会实时显示,需要在打开一次才能看到上一次写入的内容

//进行写文件
file.open(QIODeviceBase::Append);
file.write("啊啊啊啊啊啊啊啊啊啊啊啊啊");
file.close();

读取文件信息QFileInfo,birthTime等QDateTime类型有格式化输出

//QFileInfo文件信息类
 QFileInfo info(file);

 qDebug() <<"大小:"<< info.size() <<"name :" << info.fileName() <<"houzhui:" << info.suffix();
 qDebug() << "创建日期:" << info.birthTime().toString("yyyy/mm/dd");
 qDebug() << "最后修改日期:" << info.lastModified().toString("yyyy-mm-dd");

qt 封装sqlite 类_qt_16