2023/9/19 -- C++/QT

news2024/12/30 0:55:39

作业

1> 登录框实现注册功能,将注册的结果放入文件中(君子作业)

2> 完成文本编辑器的保存工作

void Widget::on_saveBtn_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this,"另存为","./","*.txt");
    if(fileName.isNull()){
        QMessageBox::information(this,"提示","用户取消了另存文件");
        return;
    }
    QFile file(fileName);
    if(!file.isOpen()){
        if(!file.open(QIODevice::WriteOnly)){
            QMessageBox::critical(this,"错误","打开失败");
            return;
        }
    }
    QString text = ui->textEdit->toPlainText();
    file.write(text.toUtf8());
    file.close();
}

3>

 widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <QTimer>
#include <QTime>
#include <QTextToSpeech>
#include <QMessageBox>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

    void timerEvent(QTimerEvent *e)override;

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_startBtn_clicked();

    void on_stopBtn_clicked();

private:
    Ui::Widget *ui;

    int time_id1;
    int time_id2;

    QTextToSpeech *speecher;
};
#endif // WIDGET_H

 widget.cpp:

#include "widget.h"
#include "ui_widget.h"

void Widget::timerEvent(QTimerEvent *e)
{
    if(e->timerId() == time_id1){
        QTime sys_t = QTime::currentTime();          //获取系统时间
        //将QTime类对象转换为字符串
        QString t = sys_t.toString("hh:mm:ss");
        //展示到ui界面
        ui->timeLabel->setText(t);

    }
    if(e->timerId() == time_id2){
        QTime sys_t = QTime::currentTime();          //获取系统时间
        //将QTime类对象转换为字符串
        QString t = sys_t.toString("hh:mm:ss");
        if(t == ui->timeEdit->text()){
            QString text = ui->textEdit->toPlainText();
            speecher->say(text.toUtf8());
        }
    }
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    time_id1 = startTimer(1000);
    ui->timeLabel->setAlignment(Qt::AlignCenter);
    ui->timeEdit->setAlignment(Qt::AlignCenter);
    speecher = new QTextToSpeech(this);
}

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

//启动按钮
void Widget::on_startBtn_clicked()
{
    time_id2 = startTimer(1000);
    //提示信息
    QMessageBox box(QMessageBox::Information,"提示","已启动",QMessageBox::Ok,this);
    box.exec();
}

//停止按钮
void Widget::on_stopBtn_clicked()
{
    killTimer(time_id2);
    //提示信息
    QMessageBox box(QMessageBox::Information,"提示","已停止",QMessageBox::Ok,this);
    box.exec();
}

效果图:

一、事件处理机制

1.1 事件处理简介

1. 什么是事件?  (重点)
    事件是由窗口系统或者自身产生的,用以响应所发生的
各类事情,比如用户按下并释放了键盘或者鼠标、窗口因
暴露而需要重绘、定时器到时而应有所动作,等等

    从某种意义上讲,事件比信号更原始,甚至可以认为大多
数信号其实都是由事件产生的。比如一个下压式按钮首先
感受到的是鼠标事件,
    在进行必要的处理以产生按钮下沉
继而弹起的视觉效果之后,才会发射 clicked()信号

2. 如何处理事件?  (重点)
   myWnd(自定义类) -继承-> QWidget -继承-> QObject    
   1> 当事件发生时,首先被调用的是QObject类中的虚函数event(),
   其 QEvent型参数标识了具体的事件类型
       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类的子类, 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):
   3> 而这些事件处理函数同样也是虚函数,也可以被 QWidget类
   的子类覆盖,以提供针对不同窗口部件类型的事件处理

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

   

1.2 事件处理函数由来

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");
     }

1.3 鼠标和键盘事件

1> 事件处理函数

 //重写自己的键盘事件处理函数
    void keyPressEvent(QKeyEvent *event) override;           //键盘按下事件处理函数
    void keyReleaseEvent(QKeyEvent *event) override;         //键盘抬起事件处理函数


    //重写自己的鼠标事件处理函数
    void mousePressEvent(QMouseEvent *event) override;           //鼠标按下事件处理函数
    void mouseReleaseEvent(QMouseEvent *event) override;         //鼠标抬起事件处理函数
    void mouseDoubleClickEvent(QMouseEvent *event) override;      //鼠标双击事件处理函数
    void mouseMoveEvent(QMouseEvent *event) override;             //鼠标移动事件处理函数

2> 案例

1、ui界面

2> 头文件

#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include<QKeyEvent>            //键盘事件处理类
#include<QDebug>                //信息调试类
#include<QMouseEvent>           //鼠标事件处理类


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT


public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


    //重写自己的键盘事件处理函数
    void keyPressEvent(QKeyEvent *event) override;           //键盘按下事件处理函数
    void keyReleaseEvent(QKeyEvent *event) override;         //键盘抬起事件处理函数


    //重写自己的鼠标事件处理函数
    void mousePressEvent(QMouseEvent *event) override;           //鼠标按下事件处理函数
    void mouseReleaseEvent(QMouseEvent *event) override;         //鼠标抬起事件处理函数
    void mouseDoubleClickEvent(QMouseEvent *event) override;      //鼠标双击事件处理函数
    void mouseMoveEvent(QMouseEvent *event) override;             //鼠标移动事件处理函数




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

3> 源文件

#include "widget.h"
#include "ui_widget.h"


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


    //开启鼠标追踪功能
    this->setMouseTracking(true);
}


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


//键盘按下事件处理函数的实现
void Widget::keyPressEvent(QKeyEvent *event)
{
    qDebug()<<"有键盘被按下了,键值为"<<event->key()<<"   text:"<<event->text();


    //可以对事件的键值进行判断
    switch(event->key())
    {
        case 'W':
        {
            if(ui->label->y() <= 0-ui->label->height())         //说明该组件已经全部脱离界面
            {
                ui->label->move(ui->label->x(), this->height());      //将组件放到最下面
            }


            ui->label->move(ui->label->x(), ui->label->y()-1);
        }
        break;
    }




}


//键盘抬起事件处理函数的实现
void Widget::keyReleaseEvent(QKeyEvent *event)
{
    qDebug()<<"有键盘被抬起了";
}


//鼠标按下事件处理函数的定义
void Widget::mousePressEvent(QMouseEvent *event)
{
    //判断是哪个鼠标被按下
    if(event->button() == Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被按下,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->button() == Qt::RightButton)
    {
        qDebug()<<"鼠标右键被按下,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->button() == Qt::MidButton)
    {
        qDebug()<<"鼠标中间键被按下,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else
    {
        qDebug()<<"鼠标其他键被按下,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }
}
//鼠标抬起事件处理函数的定义
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    //判断是哪个鼠标被抬起
    if(event->button() == Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被抬起,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->button() == Qt::RightButton)
    {
        qDebug()<<"鼠标右键被抬起,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->button() == Qt::MidButton)
    {
        qDebug()<<"鼠标中间键被抬起,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else
    {
        qDebug()<<"鼠标其他键被抬起,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }
}
//鼠标双击事件处理函数的定义
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
    //判断是哪个鼠标被双击
    if(event->button() == Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被双击,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->button() == Qt::RightButton)
    {
        qDebug()<<"鼠标右键被双击,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->button() == Qt::MidButton)
    {
        qDebug()<<"鼠标中间键被双击,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else
    {
        qDebug()<<"鼠标其他键被双击,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }
}
//鼠标移动事件处理函数的定义
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    //判断是哪个鼠标被移动
    qDebug()<<"鼠标全局位置:"<<event->globalPos()<<"    组件内位置:"<<event->pos();


    ui->label->move(event->pos());          //将组件跟随鼠标移动


    if(event->buttons() == Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被移动,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->buttons() == Qt::RightButton)
    {
        qDebug()<<"鼠标右键被移动,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else if(event->buttons() == Qt::MidButton)
    {
        qDebug()<<"鼠标中间键被移动,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }else
    {
        qDebug()<<"鼠标其他键被移动,全局坐标点:"<<event->globalPos()<<"   组件内坐标:"<<event->pos();
    }
}

1.4 鼠标事件案例

1> 头文件

#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include<QDebug>
#include<QMouseEvent>


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT


public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


    //重写鼠标事件处理函数
    void mouseMoveEvent(QMouseEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;




private:
    Ui::Widget *ui;


    QPoint p;              //记录鼠标相对于组件的位置
};
#endif // WIDGET_H

2> 源文件

#include "widget.h"
#include "ui_widget.h"


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


    //设置纯净窗口
    this->setWindowFlag(Qt::FramelessWindowHint);
}


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


//鼠标移动事件处理函数
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    this->move( event->globalPos() - p );
}


//鼠标按下事件处理函数
void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
    p = event->globalPos() - this->pos();
    //      鼠标的全局坐标        组件的全局坐标
    //qDebug()<<this->pos()<<endl;
    }else if(event->button() == Qt::RightButton)
    {
        this->close();
    }
}

1.5 定时器

1> 所谓定时器,就是当定时器启动后,系统会每隔给定的时间自动调用某些函数

2> 定时器的实现有两个版本:基于属性版本和事件处理版本

3> 基于事件处理函数版本

1、无需实例化对象,调用的函数都是自身提供的
2、调用自身的成员函数startTimer(sec),启动一个定时器,那么系统就会每隔sec毫秒,自动调用自身的定时器事件处理函数,该函数返回创建的定时器id
3、调用自身成员函数killTimer(id)
4、重写定时器事件处理函数:void timerEvent(QTimerEvent *event);

案例

1、ui界面

2、头文件

#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include<QTimerEvent>             //定时器事件处理类
#include<QTime>


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT


public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


    void timerEvent(QTimerEvent *e) override;         //定时器事件处理函数


private slots:
    void on_startBtn_clicked();


    void on_closeBtn_clicked();


private:
    Ui::Widget *ui;


    int timer_id;             //定时器的id号


};
#endif // WIDGET_H

3、源文件

#include "widget.h"
#include "ui_widget.h"


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


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






//启动定时器按钮对应的槽函数
void Widget::on_startBtn_clicked()
{
    timer_id = this->startTimer(1000);
    //功能:启动一个定时器
    //参数:超时时间,每隔给定的时间后,自动调用定时器事件处理函数
    //返回值:当前定时器的id号


}


//关闭定时器按钮对应的槽函数
void Widget::on_closeBtn_clicked()
{
    this->killTimer(timer_id);           //关闭给定的定时器
}


//定时器事件处理函数
void Widget::timerEvent(QTimerEvent *e)
{
    if(e->timerId() == timer_id)         //说明定时器1到位
    {
        QTime sys_t = QTime::currentTime();          //获取系统时间
        //将QTime类对象转换为字符串
        QString t = sys_t.toString("hh:mm:ss");


        //展示到ui界面
        ui->timeLab->setText(t);
    }


//    if(e->timerId() == timer_id_1)         //说明定时器1到位
//    {


//    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R的一些奇奇怪怪的功能

1. 欧氏距离计算 df <- data.frame(x 1:10, y 1:10, row.names paste0("s", 1:10)) euro_dist <- as.matrix(dist(df))2. 集合运算 union(x, y) # 并集 intersect(x, y) # 交集 setdiff(x, y) # 只在x中存在&#xff0c;y中不存在的元素 setequal(x, y)…

Linux内核源码分析 (B.3) 深入理解 Linux 物理内存分配全链路实现

Linux内核源码分析 (B.3) 深入理解 Linux 物理内存分配全链路实现 文章目录 Linux内核源码分析 (B.3) 深入理解 Linux 物理内存分配全链路实现[toc] 前文回顾1\. 内核物理内存分配接口2.规范物理内存分配行为的掩码 gfp\_mask3\. 物理内存分配内核源码实现3.1 内存分配行为标识…

HAProxy集群与常见的Web集群软件调度器对比

HAProxy集群与常见的Web集群软件调度器对比 1、常见的Web集群调度器2、Haproxy基本介绍2.1Haproxy是什么&#xff1f;2.2Haproxy的特性2.3Haproxy常用的8种负载均衡调度算法2.3.1轮询&#xff1a;RR&#xff08;Round Robin&#xff09;2.3.2最小连接数&#xff1a;LC&#xff…

【操作系统笔记】链接阶段ELF文件

链接阶段&#xff1a;符号解析 链接阶段主要包含&#xff1a; 符号解析重定位 一般情况下&#xff0c;每个 C 文件可以看成一个程序模块&#xff0c;比如下边的main.c就是一个程序模块 #include <stdio.h>extern int shared; int sum(int *a, int n); int array[2] …

关于RISC-V安全性的全面综述

目录 摘要引言RISC-V安全综述通用平台的安全要求信任的根源与硬件安全模块OTP管理模块安全内存对称加密&#xff08;如AES&#xff09;引擎不对称加密[131]&#xff08;例如&#xff0c;公钥RSA&#xff09;引擎HASH/HAMC引擎随机数/位生成&#xff08;例如TRNG[136]&#xff0…

滴滴 OrangeFS 数据湖存储关键技术揭秘!

2015年&#xff0c;滴滴为解决小文件和图片的存储&#xff0c;成立 GIFT 小对象存储项目。伴随着业务不断成长&#xff0c;我们面临的挑战也越来越多&#xff0c;经历多次非结构化存储架构演进&#xff0c;具体如下图所示&#xff1a; 随着公司不断发展&#xff0c;滴滴的业务有…

基于Java+SpringBoot+Vue的即可运动健身器材网站设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

Spring Boot常见面试题

Spring Boot简介 Spring Boot 是由 Pivotal 团队提供&#xff0c;用来简化 Spring 应用创建、开发、部署的框架。它提供了丰富的Spring模块化支持&#xff0c;可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot通过自动配置功能&#xff0c;降低了复杂性&#xff0c;同…

ClickHouse进阶(十九):clickhouse管理与运维-权限管理

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅&#xff1a;拥抱…

MySQL数据库——索引(1)-概述以及B-Tree结构

目录 索引概述 介绍 优缺点 索引结构&#xff08;1&#xff09; 介绍 二叉树 B-Tree 索引这一个章节将分为以下几个部分来学习&#xff1a; 索引概述索引结构索引分类索引语法SQL性能分析索引使用索引设计原则 索引概述 介绍 索引&#xff08;index&#xff09;是帮助M…

基于SSM的星空游戏购买下载平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

RocketMq(四)消息分类

一、普通消息 1、同步发送消息&#xff1a;指的是Producer发出⼀条消息后&#xff0c;会在收到MQ返回的ACK之后才发下⼀条消息。该方式的消息可靠性最高&#xff0c;但消息发送效率低。 二、顺序消息 三、延时消息

JAVAAndroid实现MQTT上位机软件功能-订阅主题与发布主题

一、前言 本文我们将介绍Android或JAVA程序作为MQTT客户端连接MQTT服务器并订阅主题报文并发布主题报文&#xff0c;由于我的Android使用的也是JAVA语言&#xff0c;因此下面我们将使用IDEA完成JAVA程序&#xff0c;以实现订阅主题和发布主题的功能&#xff0c;该程序也可在后期…

MQ - 08 基础篇_消费者客户端SDK设计(下)

文章目录 导图Pre概述消费分组协调者消费分区分配策略轮询粘性自定义消费确认确认后删除数据确认后保存消费进度数据消费失败处理从服务端拉取数据失败本地业务数据处理失败提交位点信息失败总结导图 Pre

Linux系统编程(会话和进程)

文章目录 前言一、会话的概念二、会话和终端的区别三、终端进程组标识四、创建会话总结 前言 本篇文章我们来讲解会话和进程的概念&#xff0c;会话大家可能比较少见&#xff0c;他的英文名称叫session。 一、会话的概念 在Linux中&#xff0c;会话&#xff08;Session&…

9月15日上课内容 Zookeeper集群 + Kafka集群

Zookeeper 本章结构 Zookeeper 概述 Zookeeper 定义 *&#xff08;了解&#xff09; Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 Zookeeper 工作机制 *****&#xff08;非常重要&#xff0c;需要掌握&#xff09; Zookeeper从设计模式…

diffusers中DDPMScheduler/AutoencoderKL/UNet2DConditionModel/CLIPTextModel代码详解

扩散模型的训练时比较简单的 上图可见&#xff0c;unet是epsθ是unet。noise和预测出来的noise做个mse loss。 训练的常规过程&#xff1a; latents vae.encode(batch["pixel_values"].to(weight_dtype)).latent_dist_sample() latents latents*vae.config.scali…

QT连接Sqlite

使用QTCreator&#xff1b; 根据资料&#xff0c;Qt自带SQLite数据库&#xff0c;不需要再单独安装&#xff0c;默认情况下&#xff0c;使用SQLite版本3&#xff0c;驱动程序为***QSQLITE***&#xff1b; 首先创建项目&#xff1b;在 Build system 中应选中qmake&#xff0c;…

前端自定义导出PPT

1、背景 前端导出PPT&#xff0c;刚接触这个需求&#xff0c;还是比较懵逼&#xff0c;然后就在网上查找资料&#xff0c;最终确认是可行的&#xff1b;这个需求也是合理的&#xff0c;我们做了一个可视化数据报表&#xff0c;报表导出成PPT&#xff0c;将在线报表转成文档类型…

【数据库系统概论】关系数据库中的关系数据结构

前言关系关系模式关系数据库关系模型的存储结构感谢 &#x1f496; 前言 上一篇文章【数据库系统概论】数据模型介绍了数据库系统中的数据模型的基本概念。其中提到了关系模型是最重要的一种数据模型。下面将介绍支持关系模型的数据库系统——关系数据库。 按照数据模型的三大…