当前位置: 首页 > news >正文

QT----基于QML的计时器

赶上了实习的末班车,现在在做QML开发,第一天的学习成果,一个计时器.逻辑挺简单的,纯QML实现,代码在仓库,可以对比文档和提交记录学习起来更清晰
QT-Timer

file
file

file
file

学习使用c++的listmodel

学习使用了如何用c++的listmodel来存储数据.

新建一个TImeListModel类继承自QAbstractListModel

class TimeListModel : public QAbstractListModel
{Q_OBJECT
public:explicit TimeListModel(QObject *parent = nullptr);

创建一个结构体存储数据对,在用一个列表存储所有的数据,这个datalist就是listview

private:// 定义一个结构体来存储列表项的数据,包括 idnumber 和 timeStrstruct Data{QString m_idnumber; // 存储编号QString m_timeStr;  // 存储时间字符串};// 使用 QList 来存储所有 Data 结构体的数据QList<Data> m_datalist;

然后重写三个函数,这三个函数是必须重写的,直接复制就行,都不用改.在定义一个枚举以便 QML 通过这些角色从模型中获取数据。具体来说,NumberRoleTimerRole 代表不同的数据属性,能够让 ListView 或其他基于模型的视图组件根据这些角色来访问对应的字段。


// 返回模型中数据的总数,用于 ListView 获取到数据的数量// 这个函数是 QAbstractListModel 的纯虚函数,必须实现int rowCount(const QModelIndex &parent = QModelIndex()) const override;// 返回模型的角色名称,用于在 QML 中根据角色访问数据// 例如,NumberRole 对应的别名可以被 ListView 使用virtual QHash<int, QByteArray> roleNames() const override;// 获取指定行和角色的数据,这个函数会在 ListView 渲染数据时被调用// 数据是从 QList 中的 Data 结构体获取的QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;// 枚举角色,用于指定 QML 中访问数据的键值// NumberRole 和 TimerRole 允许 QML 中根据不同的键来访问数据enum DataRoles{NumberRole = Qt::UserRole + 1, // 用户自定义的角色从 Qt::UserRole 开始TimerRole,                     // 时间角色};

重写这三个函数的实现,根据你的数据直接抄就行,数据的个数与结构体和枚举对应

rowCount获取列表里元素的个数

roleNames设置角色与对应的名称,这样可以在qml使用model.m_idnumber来访问列表元素的idnumber

data用于获取索引和角色的数据

// 返回列表项的数量,用于 ListView 知道有多少项要显示
int TimeListModel::rowCount(const QModelIndex &parent) const
{// 返回数据列表的大小return m_datalist.size();
}// 定义数据角色的名称映射,用于在 QML 中使用这些角色名称来访问数据
QHash<int, QByteArray> TimeListModel::roleNames() const
{// 设置角色与对应的名称,这样可以在 QML 中通过 "m_idnumber" 和 "m_timeStr" 获取对应的数据QHash<int,QByteArray> roles;roles[NumberRole] = "m_idnumber"; // 角色 NumberRole 对应 m_idnumberroles[TimerRole] = "m_timeStr";   // 角色 TimerRole 对应 m_timeStrreturn roles;
}// 获取指定索引行和角色的数据,用于 ListView 显示数据
QVariant TimeListModel::data(const QModelIndex &index, int role) const
{int row = index.row(); // 获取当前索引的行号// 检查索引是否有效,避免访问越界if(row < 0 || row >= m_datalist.count()) {return QVariant(); // 返回无效数据}// 获取当前行对应的数据const Data &data = m_datalist[row];// 根据传入的角色返回不同的数据switch(role) {case NumberRole:return data.m_idnumber;  // 返回编号数据case TimerRole:return data.m_timeStr;   // 返回时间字符串数据default:return QVariant();       // 返回空值}
}

除了三个必须重写的函数,一般我们会添加一个增加数据 append和删除数据的函数,我这边直接清空就行使用 clear.将这两个函数暴露给QML,使用 Q_INVOKABLE添加上这个后,这两个函数可以在qml中调用

// Q_INVOKABLE 使得这些方法可以从 QML 中被调用// append 函数用于向模型中添加数据,接收 idnumber 和 timeStr 两个字符串Q_INVOKABLE void append(const QString &idnumber , const QString &timeStr);// 清空模型中的所有数据Q_INVOKABLE void clear();

实现这两个函数,添加数据时需要发送信号,添加时发送,添加完成发送,这样listView会在界面上实时刷新,如果想插入到末尾,发送信号位置是开始位置m_datalist.lastIndexOf(),结束位置也是

// 向数据列表中添加一项新数据
void TimeListModel::append(const QString &idnumber, const QString &timeStr)
{// 通知视图模型即将插入一行新数据,索引 0 表示新数据会插入到列表的最前面emit beginInsertRows(QModelIndex(), 0, 0);// 使用 prepend 将新的 Data 结构体添加到列表的开头m_datalist.prepend({idnumber, timeStr});// 通知视图模型插入操作完成,ListView 会根据此信号刷新显示emit endInsertRows();
}// 清除所有数据
void TimeListModel::clear()
{int row = m_datalist.count(); // 获取当前数据的行数// 只有当数据列表不为空时才执行清除操作if(row > 0) {// 通知视图模型即将移除所有行,范围从 0 到最后一行emit beginRemoveRows(QModelIndex(), 0, m_datalist.size() - 1);// 清空数据列表m_datalist.clear();// 通知视图模型移除操作完成emit endRemoveRows();} else {return; // 如果没有数据,直接返回}
}

随后在main.cpp中注册这个listmodel,引入头文件,实例化model,这样在qml中可以使用m_TimeListModel这个对象.第二种方法需要在qml中实例化对象

//把写好的list模型注册到qml中TimeListModel listmodel;engine.rootContext()->setContextProperty("m_TimeListModel",&listmodel);//第二种方法qmlRegisterType<TimeListModel>("com.timeListModel",1,0,"TimeListModel");//在qml中import导入import com.timeListModel 1.0TimeListModel{id:m_TimeListModel}

现在可以把qml中ListView中原来的model替换为m_TimeListModel,在原来的逻辑中使用append和clear

ListView{id:list1anchors.fill:parentanchors.margins: 20 //让元素离listview有边界clip: truemodel:m_TimeListModeldelegate: recordlistspacing: 5}m_TimeListModel.append(index.toString(),totaltime);
TimeListModel.clear()

多线程优化

在使用的过程中发现自己的计时器时间会慢,并且一直点击记录的话时间1s可以走10s,排查发现是在计时器的间隔取得太小了,取了1太过于消耗资源,改成10的话能解决这个问题.同时也想尝试使用线程来解决.

新建TimerThread 类继承自QObject,只有这样才能使用线程.我们需要发送时间和运行的状态,因此使用信号和QML文件通信

#ifndef TIMERTHREAD_H
#define TIMERTHREAD_H#include <QObject>
#include <QTimer>
#include <QThread>
#include <cmath>/******************************************************************************** @file       timerthread.h* @brief      把计时放入线程** @author     纯真丁一郎* @date       2024/09/18* @Blog       https://www.relxdingyilang.cn/* @history*****************************************************************************/class TimerThread : public QObject
{Q_OBJECT
public:explicit TimerThread(QObject *parent = nullptr);//判断运行状态bool isRunning = false;QString caculateTime(int totaltime);signals:void timeUpdated(QString totaltimestr); //发送时间给主界面void sig_isRunning(bool isRunning);//发送状态public slots:void start();void stop();void pause();void onTimeout();private:int m_totaltime; //总时间QTimer *timer;
};#endif // TIMERTHREAD_H

cpp里实现计时的功能启动计时器,计算时间格式.使用定时器的timeout信号,让我们的时间增加

#include "timerthread.h"TimerThread::TimerThread(QObject *parent): QObject{parent}
{m_totaltime = 0;timer = new QTimer(this);connect(timer,&QTimer::timeout,this,&TimerThread::onTimeout);}void TimerThread::start(){timer->start(1);isRunning = true;emit sig_isRunning(isRunning);
}void TimerThread::pause(){timer->stop();isRunning = false;emit sig_isRunning(isRunning);
}void TimerThread::stop(){timer->stop();isRunning = false;m_totaltime = 0;emit sig_isRunning(isRunning);
}void TimerThread::onTimeout(){//计时m_totaltime += 1;emit timeUpdated(caculateTime(m_totaltime));
}QString TimerThread::caculateTime(int totaltime){//格式化字符串int millisecond =totaltime % 1000;millisecond = std::floor(millisecond/10);int second = int(std::floor(totaltime /1000) )% 60;int minute = int(std::floor(totaltime/1000 /60)) % 60;QString result = (minute<10 ? "0":"") + QString::number(minute)+":"+(second<10 ? "0":"") + QString::number(second) + ":"+(millisecond<10 ? "0":"")+QString::number(millisecond);return result;
}

在main.cpp里实现多线程,实例化timerThread类,在实例化一个工作线程,把我们自己的类放入工作线程,启动工作线程即可.
同时我们需要qmlRegisterType来注册我们的类,这样才能让QML文件知道要与这个文件通信

 //注册计时线程,并将计时线程移动到工作线程TimerThread timerThread;QThread workerThread;timerThread.moveToThread(&workerThread);//启动工作线程workerThread.start();QQmlApplicationEngine engine;qmlRegisterType<TimerThread>("com.timerthread",1,0,"TimerThread");

main.qml的修改,首先使用import倒入我们的timerThread类,这样我们就可以在qml中实例化,可以加上idimport com.timerthread 1.0

定义两个变量,接受我们信号发送的参数.发送的参数的作用域只在Connection里,所以需要外部变量来接收,方便我们的使用.on+信号名,接的第一个字母大写!!!

 property bool isrunning: falseproperty string totaltime: ""TimerThread{id:timerThread}Connections{target:timerThread// 使用传递过来的 totaltime 参数,信号传递出来的参数在connect内部可以直接使用,在外部不行onTimeUpdated:{timerDisplay.text = totaltimestrtotaltime = totaltimestr//console.log(totaltime)}onSig_isRunning:{isrunning = isRunningconsole.log(isRunning)}}

后边就将原来的一些变量替换为新接收的变量就行.

使用多线程的方式,定时器间隔取1也能精确计时,线程起到了作用

实际上 创建的timerThread并没有被使用,在qml中又实例化了另一个TimerThread对象,这两是不同的实例,放入线程的并没有被使用
file

尝试解决线程的bug

一开始是在main.cpp里moveTothread,然后注册这个对象到上下文,再在qml直接访问对象内部。但是这样会报错,这个C++类和Qml引擎不再同一个线程里

QQmlEngine: Illegal attempt to connect to TimerThread(0x88fd60) that is in a different thread than the QML engine QQmlApplicationEngine(0x88fd30.

//注册计时线程,并将计时线程移动到工作线程TimerThread timerThread;QThread workerThread;timerThread.moveToThread(&workerThread);//启动工作线程workerThread.start();QQmlApplicationEngine engine;engine.rootContext()->setContextProperty("TimerThread",&timerThread);

使用重写run的方法

失败,线程号是一样的

使用中间类的方法,moveToThread

参考这篇文章https://www.cnblogs.com/judes/p/11249300.html
参考这篇文章https://www.cnblogs.com/judes/p/11249300.html

线程分离

  • TimerThread_test2 类负责实际的定时器逻辑,并运行在一个单独的线程中。
  • TimerInterface 类作为 TimerThread_test2 和 QML 之间的桥梁,管理线程的生命周期,并处理信号和槽的连接。

信号和槽机制

  • TimerThread_test2 通过信号 timeUpdatedsig_isRunning 将定时器的状态和时间信息发送给 TimerInterface
  • TimerInterface 通过信号 sig_timeUpdatedsig_isRunning 将这些信息进一步传递给 QML。

QML 集成

  • 通过将 TimerInterface 注册为 QML 类型,可以在 QML 中直接调用 TimerInterface 的方法和接收信号。

我是新建了一个新类TimerThread_test2,把TimerThread里的东西都复制进来.这个方法的原理就是使用一个中间类TimerInterface,TimerInterface给qml调用是运行在主线程中,它发出信号再去调用子线程中的TimerThread_test2.
file

TimerThread_test2文件里新建一个类TimerInterface(继承自QObject),它的成员变量为下

private:QThread m_Thread;QString m_timeStr;TimerThread_test2 m_TimerThread_test2;

在TimerInterface的构造函数里,将 m_TimerThread_test2移动到子线程里,将本来qml调用m_TimerThread_test2的信号全通过TimerInterface调用,将m_TimerThread_test2要发送给qml文件的数据全通过TimerInterface发送,这样就完成了这个类的编写.(详细代码在后边,逻辑其实很简单)

TimerInterface::TimerInterface(QObject *parent) : QObject(parent)
{m_TimerThread_test2.moveToThread(&m_Thread);.....中间逻辑先省略m_Thread.start();
}

随后我们在main.cpp中引入头文件注册 qmlRegisterType<TimerInterface>``("tool",1,0,"TimerThread_test");在qml文件中import import tool 1.0然后我们就可以使用这个类,修改逻辑.start,stop,pause.

 TimerThread_test{id:m_TimerThread;}Connections{target:m_TimerThread// 使用传递过来的 totaltime 参数,信号传递出来的参数在connect内部可以直接使用,在外部不行// function onTimeUpdated(totaltimestr){//     timerDisplay.text = totaltimestr//     totaltime = totaltimestr//     //console.log(totaltime)// }function onSig_isRunning(isRunning){isrunning = isRunning// console.log(isRunning)}}

当我们点击开始后,可以发现中间类Interface是在主线程的,定时器是在子线程运行,多线程的方案实现成功.

file
完整代码,.h文件

#ifndef TIMERTHREAD_TEST2_H
#define TIMERTHREAD_TEST2_H#include <QObject>
#include <QTimer>
#include <QThread>
#include <cmath>
#include <QDebug>class TimerThread_test2 : public QObject
{Q_OBJECT
public:// explicit TimerThread_test2(QString &timeStr);explicit TimerThread_test2(QObject *parent = nullptr);//判断运行状态bool isRunning = false;QString caculateTime(int totaltime);void getid();signals:void timeUpdated(QString totaltimestr); //发送时间给主界面void sig_isRunning(bool isRunning);//发送状态public slots:void start();void stop();void pause();void onTimeout();private:int m_totaltime; //总时间QTimer *timer;QString m_timeStr;
};class TimerInterface: public QObject{Q_OBJECT// Q_PROPERTY(QString timeStr READ getData NOTIFY dataChanged)
public:explicit TimerInterface(QObject *parent = nullptr);~TimerInterface();Q_INVOKABLE void start();Q_INVOKABLE void pause();Q_INVOKABLE void stop();void get_is_Running(bool is_running);void get_Updated(QString timeStr);
signals:void sig_start();void sig_stop();void sig_pause();void sig_isRunning(bool is_running);void sig_timeUpdated(QString timeStr);
private:QThread m_Thread;QString m_timeStr;TimerThread_test2 m_TimerThread_test2;
};#endif // TIMERTHREAD_TEST2_H

.cpp文件

#include "timerthread_test2.h"// TimerThread_test2::TimerThread_test2(QString &timeStr): m_timeStr(timeStr)
TimerThread_test2::TimerThread_test2(QObject *parent) : QObject(parent)
{m_totaltime = 0;timer = new QTimer(this);connect(timer,&QTimer::timeout,this,&TimerThread_test2::onTimeout);
}void TimerThread_test2::start(){timer->start(1);isRunning = true;emit sig_isRunning(isRunning);//qDebug()<< "TimerThread_test2: start";getid();
}void TimerThread_test2::pause(){timer->stop();isRunning = false;emit sig_isRunning(isRunning);
}void TimerThread_test2::stop(){timer->stop();isRunning = false;m_totaltime = 0;emit sig_isRunning(isRunning);
}void TimerThread_test2::onTimeout(){//计时m_totaltime += 1;//格式化字符串int millisecond =m_totaltime % 1000;millisecond = std::floor(millisecond/10);int second = int(std::floor(m_totaltime /1000) )% 60;int minute = int(std::floor(m_totaltime/1000 /60)) % 60;QString result = (minute<10 ? "0":"") + QString::number(minute)+":"+(second<10 ? "0":"") + QString::number(second) + ":"+(millisecond<10 ? "0":"")+QString::number(millisecond);emit timeUpdated(result);
}
void TimerThread_test2::getid(){qDebug() <<"定时器线程ID: "<< QThread::currentThreadId();
}// TimerInterface::TimerInterface() : m_TimerThread_test2(m_timeStr)
TimerInterface::TimerInterface(QObject *parent) : QObject(parent)
{m_TimerThread_test2.moveToThread(&m_Thread);connect(this,&TimerInterface::sig_start,&m_TimerThread_test2,&TimerThread_test2::start);connect(this,&TimerInterface::sig_pause,&m_TimerThread_test2,&TimerThread_test2::pause);connect(this,&TimerInterface::sig_stop,&m_TimerThread_test2,&TimerThread_test2::stop);connect(&m_TimerThread_test2,&TimerThread_test2::timeUpdated,this, &TimerInterface::get_Updated);connect(&m_TimerThread_test2,&TimerThread_test2::sig_isRunning,this,&TimerInterface::get_is_Running);m_Thread.start();
}TimerInterface::~TimerInterface()
{m_Thread.quit();m_Thread.wait();
}void TimerInterface::start()
{emit sig_start();qDebug() << "TimerInterface start in  : " << QThread::currentThreadId();
}void TimerInterface::pause()
{emit sig_pause();
}void TimerInterface::stop()
{emit sig_stop();
}void TimerInterface::get_is_Running(bool is_running)
{sig_isRunning(is_running);
}void TimerInterface::get_Updated(QString timeStr)
{emit sig_timeUpdated(timeStr);
}

相关文章:

QT----基于QML的计时器

赶上了实习的末班车,现在在做QML开发,第一天的学习成果,一个计时器.逻辑挺简单的,纯QML实现,代码在仓库,可以对比文档和提交记录学习起来更清晰 QT-Timer 学习使用c的listmodel 学习使用了如何用c的listmodel来存储数据. 新建一个TImeListModel类继承自QAbstractListModel c…...

Stable Diffusion的高分辨率修复(Hires.fix)

Stable Diffusion的高分辨率修复&#xff08;Hires.fix&#xff09;是一项重要的功能&#xff0c;它旨在提高生成图像的分辨率和细节&#xff0c;从而使画面变得更加清晰和精细。以下是关于Stable Diffusion高分辨率修复&#xff08;Hires.fix&#xff09;的详细解释&#xff1…...

智慧体育馆可视化:实时监控与智能管理

利用图扑可视化技术实现对体育馆的实时监控和数据分析&#xff0c;提升运营效率、观众体验和安全管理水平&#xff0c;打造智能化场馆环境。...

【NLP】基于“检测器-纠错器”中文文本纠错框架

前言 许多方法将中文拼写纠正&#xff08;检测和纠正给定中文句子中的错误字符&#xff09;视为序列标注任务&#xff0c;并在句子对上进行微调。一些方法使用错误检测器作为初步任务&#xff0c;然后将检测结果用于辅助后续的错误纠正过程。然而&#xff0c;现有方法在使用检…...

vue 中加载 Mapbox GL JS Examples

Mapbox GL JS 示例 1. Mapbox GL JS的基础使用2. style 的使用2.1. 切换 style2.2. 配置一个第三方 style &#xff08;添加一个Layer&#xff09;2.3. 配置一个带有 slot 的 style2.4. 创建一个自定义 style 的 layer 类实现 WebGL 内容2.5. 添加Marker2.6. 添加 geojson 格式…...

Vue3 中组件传递 + css 变量的组合

文章目录 需求效果如下图所示代码逻辑代码参考 需求 开发一个箭头组件&#xff0c;根据父组件传递的 props 来修改 css 的颜色 效果如下图所示 代码逻辑 代码 父组件&#xff1a; <Arrow color"red" />子组件&#xff1a; <template><div class&…...

秋分之际,又搭建了一款微信记账本小程序

在这个金色的季节里&#xff0c;每一粒粮食都蕴含着生命的奇迹&#xff0c;每一片叶子都在诉说着成长的故事。秋分之际&#xff0c;又搭建了一款微信记账本小程序。 产品概述 微信记账本小程序是一款便捷的个人财务管理工具&#xff0c;旨在帮助用户轻松记录、管理和分析日常…...

聚合函数count 和 group by

count函数&#xff1a; count&#xff08;列名&#xff09; SELECT COUNT(sid) FROM grade 统计列中所有的数值个数&#xff0c;会忽略null值。 count&#xff08;*&#xff09;和count&#xff08;1&#xff09; SELECT COUNT(*) FROM grade SELECT COUNT(1) FROM grade 统…...

Vue的工程化和element快速入门

vue项目的创建&#xff1a; vue项目的启动方式&#xff1a; vue项目开发流程&#xff1a; 代码示例&#xff1a; <!-- <script>//写数据export default{data(){return{msg: 上海}}} </script> --><script setup>import {ref} from vue;//调用ref函数&…...

【Kubernetes】常见面试题汇总(三十一)

目录 83.简述你知道的 K8s 中几种 Controller 控制器并详述其工作原理。简述 ingress-controller 的工作机制。 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 …...

在 Windows 上安装和配置 NVIDIA 驱动程序、CUDA、cuDNN 和 TensorRT

在 Windows 上安装和配置 NVIDIA 驱动程序、CUDA、cuDNN 和 TensorRT 1. 安装 NVIDIA 图形驱动程序2. 安装 CUDA Toolkit3. 安装 cuDNN4.安装 TensorRT5. 常见问题1. 安装 NVIDIA 图形驱动程序 首先需要安装兼容 CUDA 的 NVIDIA 驱动程序。 下载最新驱动: 访问 NVIDIA 官网,…...

京准电钟:NTP网络校时服务器助力校园体育场馆

京准电钟&#xff1a;NTP网络校时服务器助力校园体育场馆 京准电钟&#xff1a;NTP网络校时服务器助力校园体育场馆 体育场馆数字时钟系统可为观众及工作人员提供标准时间信息&#xff0c;为计算机及其他系统提供标准时间源&#xff0c;为协调场馆各业务系统与各部门的工作提供…...

9.25度小满一面

1.map的底层 2.unorder_map哈希表有自己实现过吗&#xff1f;哈希冲突 3.poll和epoll和select的优缺点、 4.线程同步机制是用来做什么的? 5.五子棋项目问题-- 算法题: 6.LeetCode.重排链表 给定一个单链表 L 的头节点 head &#xff0c;单链表 L 表示为&#xff1a; L0…...

mysql批量修改表前缀

现有表前缀xh,批量修改为fax_需要怎么做 SELECTCONCAT(ALTER TABLE ,table_name, RENAME TO fax_,substring(table_name, 3),;) FROMinformation_schema. TABLES WHEREtable_name LIKE xh_%; 运行之后可以但是生成了一批修改表明的命令 此时批量复制执行就可实现批量修改表前…...

算法复杂度

1. 数据结构前⾔ 1.1数据结构 数据结构是计算机存储数据&#xff0c;组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。常见的数据结构有线性表&#xff0c;树&#xff0c;图&#xff0c;哈希等。 1.2 算法 算法是一种计算过程&#xff0c;输…...

vue到出excel

安装 npm install exceljs npm install file-saver<template><button click"dade66">导出 66</button> </template><script> import ExcelJS from exceljs; import { saveAs } from file-saver;export default {data() {return {data…...

【延时队列的实现方式】

文章目录 延时队列JDK自带的延时队列实现Redis实现延迟队列RabbitMQ 延时队列 延时队列 延时队列是一种特殊类型的队列&#xff0c;它允许元素在特定时间间隔后才能被处理。这种队列在处理具有延迟需求的任务时非常有用&#xff0c;例如定时任务、事件驱动系统等 延时队列在项…...

Fyne ( go跨平台GUI )中文文档- 扩展Fyne (七)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章&#xff1a; Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI…...

Qt (19)【Qt 线程安全 | 互斥锁QMutex QMutexLocker | 条件变量 | 信号量】

阅读导航 引言一、互斥锁1. QMutex&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;使用示例基本需求⭕thread.h⭕thread.cpp⭕widget.h⭕widget.cpp 2. QMutexLocker&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;使用示例 3. QReadWriteLocker、QR…...

Java语法-类和对象(上)

1. 面向对象的初步认识 1.1 什么是面向对象 概念: Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。 1.2 面向对象VS面向过程 如:洗衣服 面向过程: 注重的是洗衣服的过程,少了一个环节也不…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...