Qt绘制动态仪表(模仿汽车仪表指针、故障灯)
背景:
项目需要,可能需要做一些仪表显示。此篇除了介绍实现方法,还要说明心路历程。对我而言,重要的是心理,而不是技术。写下来也是自勉。
本人起初心里是比较抵触的,从业20多年了,深知所谓界面,实际上最根本还是代码实现的,操作系统层面多少年来一步步发展更新,是靠不断封装演变来的。所谓的可视化开发,主要还是靠ide提供的插件控件,通常只是应用。如果要按照自己的想法做个什么,那就是绘图机制,把代码变成图不用想就知道麻烦。基于这种心理,就是再说qt可以做得很炫,个人表示一看就够那种,根本看不进去。
终究为了活下去,所以要保住工作,也是对技术的不服输,所以不忙时打开qt示例,看它的文档。其实看过很多遍了,主要是看不进去。终于要善于提炼代码,看它的主要部分,缩小规模,然后研读手册,必要时看看别人怎么说的,逐个尝试,最后形成自己的总结,就学会了。
下面只介绍干货。
用法总结:
所谓绘图机制,肯定用到paintEvent函数,每一个能看到的窗体都是使用操作系统的重绘机制显示的。说人话就是,绘图的过程要写在paintEvent函数里,只要做了更新显示操作,记着调用update函数,它会调用paintEvent函数重绘界面。
qt绘图就一个QPainter,所有事都是它干的。QPen用于设置边框边线,QBrush用于设置填充。
painter画任何东西都是有个draw***函数。
画任何东西都基于坐标系,所以要先操作坐标系,再画。比如想画仪表盘刻度,设定好间隔(循环),转一次坐标系,画一个短线,最后转完一圈,也就画了一圈刻度。
painter就是画画,肯定后画的覆盖先画的,跟图层似的。
因为能旋转坐标系,所以要记住前后的坐标系状态,所以前面调用QPainter::save(),最后调用QPainter::restore()。比如画仪表,开始画背景是正常坐标系,接着通过旋转坐标系画刻度,最后要在正常坐标系下画表轴或者其它东西。这中间,旋转坐标系那部分,就需要暂存painter状态,画完这部分再恢复。
具体下面例子说明。
下面无论我画什么,都不再贴mainwindow代码了,没有必要,每个仪表都是一个类,使用时,在界面画一个label,提升为这个类即可。
手绘仪表盘:
思路是:
先画个黑色矩形当背景;
再旋转坐标系画刻度;
通过一个全局的成员变量值,作为指针旋转角度值,通过旋转坐标系把指针画到相应位置;
最后画一个转轴盖住指针(其实也可以把指针别画那么长,留出圆心位置即可)。
我鸟语不行,注释部分,看官您忽略就好。至于表芯转轴,你们说叫hand heart还是center?要不咱别较真的了,主要看代码。
guage_watertemp.h
/**************************************************************************************************** File name: guage_watertemp.h (Guage_WaterTemp)** Created by: Henrick.Nie at 2024-9-8** Used for: The car water temprature guage.**************************************************************************************************/
#ifndef GUAGE_WATERTEMP_H
#define GUAGE_WATERTEMP_H#include <QLabel>
#include <QPainter>
#include <QDebug>class Guage_WaterTemp : public QLabel
{Q_OBJECTpublic:explicit Guage_WaterTemp(QWidget *parent = nullptr);void f_SetTemp(const qreal &realTemp);private:qreal m_realTemp, m_realMin = 25, m_realMax = 155;void paintEvent(QPaintEvent *event);void f_Draw(QPainter *p);
};#endif // GUAGE_WATERTEMP_H
guage_watertemp.cpp
#include "guage_watertemp.h"Guage_WaterTemp::Guage_WaterTemp(QWidget *parent) :QLabel(parent)
{
}
void Guage_WaterTemp::paintEvent(QPaintEvent *event)
{QLabel::paintEvent(event);QPainter painter(this);f_Draw(&painter);
}
void Guage_WaterTemp::f_Draw(QPainter *p)
{QColor colorHand = QColor(Qt::red);//Init the size data.int iHeartSize = width() / 5;int iX0 = width() / 2, iY0 = height() - iHeartSize;int iBackWidth = width(), iBackHeight = width() / 2 + iHeartSize * 1.5 ;int iBackLeft = 0 - iBackWidth / 2, iBackTop = 0 - iBackWidth / 2 - iHeartSize / 2;int iMarkSize = iBackWidth / 40, iMarklength = iBackWidth / 20;int iHandSize = iBackWidth / 25, iHandLeft = iBackLeft + width() / 20, iHandLength = iBackWidth / 2 - iBackWidth / 20;int iText30Left = iBackLeft + width() / 28, iText30Top = 0 - width() / 15;int iText90Left = 0 - width() / 18, iText90Top = 0 - width() / 4;int iText150Left = width() / 3.5, iText150Top = iText30Top;//Init the origin.p->setRenderHint(QPainter::Antialiasing);p->translate(iX0, iY0);//Draw the black rect as the background.p->setPen(Qt::NoPen);p->setBrush(QBrush(Qt::black));p->drawRect(iBackLeft, iBackTop, iBackWidth, iBackHeight);//Draw the hand heart on the origin.p->setPen(QPen(QBrush(colorHand), iHeartSize, Qt::SolidLine, Qt::RoundCap));p->drawPoint(0, 0);//Draw the mark. (From 30 degrees to 150 degrees, 150-30=120, 120/10=12)p->save();p->rotate(30);for(int i = 30; i <= 150; ++i){QBrush brush = (i < 140) ? QBrush(Qt::white) : QBrush(Qt::red);p->setPen(QPen(brush, iMarkSize));p->drawPoint(iBackLeft, 0);p->rotate(1);}p->restore();QList<int> iList_Big = { 30, 90, 150 };p->save();p->rotate(30);for (int i = 30; i <= 150; i += 12){int iSize = iList_Big.contains(i) ? iMarkSize * 2 : iMarkSize;int iLeft = iList_Big.contains(i) ? iBackLeft + iMarkSize / 2 : iBackLeft;int iLength = iList_Big.contains(i) ? iMarklength + 10 : iMarklength;QBrush brush = (i < 130) ? QBrush(Qt::white) : QBrush(Qt::red);p->setPen(QPen(brush, iSize));p->drawLine(iLeft, 0, iLeft + iLength, 0);p->rotate(12);}p->restore();//Draw the mark text.p->setFont(QFont("", width() / 10));p->setPen(QPen(QBrush(Qt::white), width() / 18));p->drawText(iText30Left, iText30Top, "30");p->drawText(iText90Left, iText90Top, "90");p->drawText(iText150Left, iText150Top, "150");//Draw hands.p->save();p->setPen(QPen(QBrush(colorHand), iHandSize, Qt::SolidLine, Qt::RoundCap));if (m_realTemp < m_realMin){m_realTemp = m_realMin;}if (m_realTemp > m_realMax){m_realTemp = m_realMax;}p->rotate(m_realTemp);p->drawLine(iHandLeft, 0, iHandLeft + iHandLength, 0);p->restore();p->end();
}
void Guage_WaterTemp::f_SetTemp(const qreal &realTemp)
{m_realTemp = realTemp;update();
}
效果:
其实我是仿照大众polo劲情的水温表画的。至于指针,既然是旋转肯定是角度。看到表盘的样式时,要大致估计一下,最左侧和左右侧的刻度大概是坐标轴上的多少度。算一下它的跨度,和实际需要的水温数值要有个转换。比方说,这个水温表的刻度刚好是水温和角度一一对应,所以不用转换。
图片仪表盘:
上面看到效果后会很有成就感,但要把仪表盘画得逼真可不容易,还要考虑缩放和字体,细节太多。因此有了这种方法,从网上找图片素材,自己加工仪表盘。直接先把图片画上去当背景,然后代码只控制表针即可。以后修改背景表盘,photoshop修图即可。
后期又做了小修改,因为图片作为资源文件,每个人安排的路径可能不同,通用起见,需要调用f_Init函数先初始化路径前缀。
先看我找的素材:
再看我修好的效果:
上代码:
polo_base.h
/**************************************************************************************************** File name: polo_baes.h (Polo_Base)** Created by: Henrick.Nie at 2024-9-9** Used for: The base class of the polo guage.** Using method:**** Firstly, a image resource path is required.**** obj->f_Init(":/images/");****************************************************************************************************/#ifndef POLO_BASE_H
#define POLO_BASE_H#include <QLabel>
#include <QPainter>
#include <QDebug>class Polo_Base : public QLabel
{Q_OBJECT
public:explicit Polo_Base(QWidget *parent = nullptr);inline virtual void f_Init(const QString &sRcPathPrefix) = 0;protected:inline void f_SetBack(const QString &sFileName) { m_sPicPath = sFileName; }virtual void f_SetValue(const qreal &realValue);private:QString m_sPicPath;qreal m_realDegree, m_realMin = 40, m_realMax = 140;void paintEvent(QPaintEvent *event);void f_Draw(QPainter *p);
};#endif // POLO_BASE_H
polo_base.cpp
#include "polo_base.h"Polo_Base::Polo_Base(QWidget *parent) :QLabel(parent)
{}
void Polo_Base::paintEvent(QPaintEvent *event)
{QLabel::paintEvent(event);QPainter painter(this);f_Draw(&painter);
}
void Polo_Base::f_Draw(QPainter *p)
{QColor colorHand = QColor(Qt::red);//Init the origin.int iX0 = width() / 2, iY0 = height() - width() / 4;p->setRenderHint(QPainter::Antialiasing);p->translate(iX0, iY0);//Draw the background picture.QPixmap pic(m_sPicPath);int iPicWidth = width(), iPicHeight = width() * pic.height() / pic.width();int iLeft = 0 - iPicWidth / 2, iTop = 0 - iPicHeight + width() / 4;p->drawPixmap(iLeft, iTop, width(), width() * pic.height() / pic.width(), pic);//Draw hands.int iHandSize = width() / 25, iHandLeft = iLeft - width() / 15, iHandLength = width() / 2 - width() / 20;p->save();p->setPen(QPen(QBrush(colorHand), iHandSize, Qt::SolidLine, Qt::RoundCap));if (m_realDegree < m_realMin){m_realDegree = m_realMin;}if (m_realDegree > m_realMax){m_realDegree = m_realMax;}p->rotate(m_realDegree);p->drawLine(iHandLeft, 0, iHandLeft + iHandLength, 0);p->restore();//Draw the hand heart on the origin.int iHeartSize = width() / 4;p->setPen(QPen(QBrush(QColor(Qt::darkGray)), iHeartSize, Qt::SolidLine, Qt::RoundCap));p->drawPoint(0, 0);p->end();
}
void Polo_Base::f_SetValue(const qreal &realValue)
{m_realDegree = realValue;update();
}
polo_watertemp.h
/**************************************************************************************************** File name: polo_watertemp.h (Polo_WaterTemp)** Created by: Henrick.Nie at 2024-9-9** Used for: The water temprature guage of polo.** Using method:**** Firstly, a image resource path is required.**** obj->f_Init(":/images/");****************************************************************************************************/#ifndef POLO_WATERTEMP_H
#define POLO_WATERTEMP_H#include "polo_base.h"class Polo_WaterTemp : public Polo_Base
{Q_OBJECT
public:explicit Polo_WaterTemp(QWidget *parent = nullptr);void f_Init(const QString &sRcPathPrefix) override;void f_SetValue(const qreal &realValue) override;
};#endif // POLO_WATERTEMP_H
polo_watertemp.cpp
#include "polo_watertemp.h"Polo_WaterTemp::Polo_WaterTemp(QWidget *parent) :Polo_Base(parent)
{}
void Polo_WaterTemp::f_Init(const QString &sRcPathPrefix)
{f_SetBack(sRcPathPrefix + "polo_watertemp.jpg");
}
void Polo_WaterTemp::f_SetValue(const qreal &realValue)
{//The given water temprature value, it equals the degrees.Polo_Base::f_SetValue(realValue);
}
polo_fuel.h
/**************************************************************************************************** File name: polo_fuel.h (Polo_Fuel)** Created by: Henrick.Nie at 2024-9-9** Used for: The fuel guage of polo.** Using method:**** Firstly, a image resource path is required.**** obj->f_Init(":/images/");****************************************************************************************************/#ifndef POLO_FUEL_H
#define POLO_FUEL_H#include "polo_base.h"class Polo_Fuel : public Polo_Base
{Q_OBJECT
public:explicit Polo_Fuel(QWidget *parent = nullptr);void f_Init(const QString &sRcPathPrefix) override;void f_SetValue(const qreal &realValue) override;
};#endif // POLO_FUEL_H
polo_fuel.cpp
#include "polo_fuel.h"Polo_Fuel::Polo_Fuel(QWidget *parent) :Polo_Base(parent)
{}
void Polo_Fuel::f_Init(const QString &sRcPathPrefix)
{f_SetBack(sRcPathPrefix + "polo_fuel.jpg");
}
void Polo_Fuel::f_SetValue(const qreal &realValue)
{Polo_Base::f_SetValue(40 + realValue * 2.2);
}
燃料表这个要注意数值换算了。下面转速表也是。
tachometer.h
/**************************************************************************************************** File name: tachometer.h (TachoMeter)** Created by: Henrick.Nie at 2024-9-9** Using method:**** Firstly, a image resource path is required.**** obj->f_Init(":/images/");****************************************************************************************************/#ifndef TACHOMETER_H
#define TACHOMETER_H#include <QLabel>
#include <QPainter>
#include <QDebug>class TachoMeter : public QLabel
{Q_OBJECT
public:explicit TachoMeter(QWidget *parent = nullptr);inline void f_Init(const QString &sRcPathPrefix) { m_sRcPathPrefix = sRcPathPrefix; }void f_SetValue(const qreal &realValue);private:QString m_sRcPathPrefix;qreal m_realValue = -45, m_realMin = -45, m_realMax = 225;void paintEvent(QPaintEvent *event);void f_Draw(QPainter* p);
};#endif // TACHOMETER_H
tachometer.cpp
#include "tachometer.h"TachoMeter::TachoMeter(QWidget *parent) :QLabel(parent)
{}
void TachoMeter::paintEvent(QPaintEvent *event)
{QLabel::paintEvent(event);QPainter painter(this);f_Draw(&painter);
}
void TachoMeter::f_Draw(QPainter *p)
{//Init the size data.int iSideSize = qMin(width(), height());int iX0 = width() / 2, iY0 = height() / 2;//Init the origin.p->setRenderHint(QPainter::Antialiasing);p->translate(iX0, iY0);//Draw the background.p->setPen(Qt::NoPen);p->setBrush(QBrush(Qt::black));p->drawRect(0 - width() / 2, 0 - height() / 2, width(), height());QPixmap pic(m_sRcPathPrefix + "tacho1.jpg");int iLeft = 0 - iSideSize / 2, iTop = 0 - iSideSize / 2;p->drawPixmap(iLeft, iTop, iSideSize, iSideSize, pic);//Draw the hand.p->save();p->setPen(QPen(QBrush(Qt::red), iSideSize / 40, Qt::SolidLine, Qt::RoundCap));if (m_realValue < m_realMin){m_realValue = m_realMin;}if (m_realValue > m_realMax){m_realValue = m_realMax;}p->rotate(m_realValue);p->drawLine(0 - iSideSize / 2 + iSideSize / 20, 0, 0, 0);p->restore();//centerp->setPen(Qt::NoPen);p->setBrush(QBrush(QColor(Qt::darkGray)));p->drawEllipse(QPoint(0, 0), iSideSize / 20, iSideSize / 20);p->end();
}
void TachoMeter::f_SetValue(const qreal &realValue)
{//value: 0 to 800//degree: -45 to 225 (225-(-45))=270qreal realScale = 270.0 / 800.0; //per 10 rpmm_realValue = 0 - 45 + realValue * realScale;update();
}
效果:
效果解析:
上面效果图中,我在界面上放置了滑动条,实际操作时,可以改变滑块位置,直接看到仪表动作。
警告灯:
在上述基础上,还可以使用label的setmovie函数,播放一些动态的gif图片。以实现警告灯的效果。
label_movie.h
/**************************************************************************************************** File name: label_movie.h (Label_Movie)** Created by: Henrick.Nie at 2024-9-10** Using method:**** Firstly, a image resource path is required.**** obj->f_Init(":/images/");****************************************************************************************************/#ifndef LABEL_MOVIE_H
#define LABEL_MOVIE_H#include <QLabel>
#include <QPainter>
#include <QMovie>
#include <QDebug>class Label_Movie : public QLabel
{Q_OBJECT
public:explicit Label_Movie(QWidget *parent = nullptr);inline void f_Init(const QString &sRcPathPrefix) { m_sRcPathPrefix = sRcPathPrefix; }void f_SetJpg(const QString &sFileName);void f_SetGif(const QString &sFileName);private:QString m_sRcPathPrefix;QMovie m_movie;
};#endif // LABEL_MOVIE_H
label_movie.cpp
#include "label_movie.h"Label_Movie::Label_Movie(QWidget *parent) :QLabel(parent)
{}
void Label_Movie::f_SetJpg(const QString &sFileName)
{this->setPixmap(QPixmap(m_sRcPathPrefix + sFileName));
}
void Label_Movie::f_SetGif(const QString &sFileName)
{m_movie.stop();m_movie.setFileName(m_sRcPathPrefix + sFileName);this->setMovie(&m_movie);m_movie.start();
}
之所以要包装一个label,因为qt手册提到ownership,也许qt这样处理有其它用意,但对于本次情况,每次单独处理不方便。
[slot] void QLabel::setMovie(QMovie *movie)
Sets the label contents to movie. Any previous content is cleared. The label does NOT take ownership of the movie.
The buddy shortcut, if any, is disabled.
效果如下:
当水温和油量到达警戒值时,自动亮起故障灯。
故障灯整合面板:
guage_warning.h
/**************************************************************************************************** File name: guage_warning.h (Guage_Warning)** Created by: Henrick.Nie at 2024-9-11** Used for: The warning light of the engine.** Using method:**** Firstly, a image resource path is required.**** obj->f_Init(":/images/");****************************************************************************************************/#ifndef GUAGE_WARNING_H
#define GUAGE_WARNING_H#include <QWidget>namespace Ui {
class Guage_Warning;
}class Guage_Warning : public QWidget
{Q_OBJECTpublic:explicit Guage_Warning(QWidget *parent = nullptr);~Guage_Warning();enum EWarningType { eNone, eWater, eOil, eFuel, eEngine, eBattery, eBrake };void f_Init(const QString &sRcPathPrefix);void f_SetStatus(const EWarningType &eType, const bool &bIsWarning);private:Ui::Guage_Warning *ui;QString m_sRcPathPrefix;EWarningType m_eType = eNone;};#endif // GUAGE_WARNING_H
guage_warning.cpp
#include "guage_warning.h"
#include "ui_guage_warning.h"Guage_Warning::Guage_Warning(QWidget *parent) :QWidget(parent),ui(new Ui::Guage_Warning)
{ui->setupUi(this);this->setStyleSheet("background: black;");ui->gridLayout->setSpacing(0);
}Guage_Warning::~Guage_Warning()
{delete ui;
}void Guage_Warning::f_Init(const QString &sRcPathPrefix)
{m_sRcPathPrefix = sRcPathPrefix;ui->labWater ->setPixmap(QPixmap(m_sRcPathPrefix + "warning_water.jpg"));ui->labOil ->setPixmap(QPixmap(m_sRcPathPrefix + "warning_oil.jpg"));ui->labFuel ->setPixmap(QPixmap(m_sRcPathPrefix + "warning_fuel.jpg"));ui->labEngine ->setPixmap(QPixmap(m_sRcPathPrefix + "warning_engine.jpg"));ui->labBattery->setPixmap(QPixmap(m_sRcPathPrefix + "warning_battery.jpg"));ui->labBrake ->setPixmap(QPixmap(m_sRcPathPrefix + "warning_brake.jpg"));
}
void Guage_Warning::f_SetStatus(const EWarningType &eType, const bool &bIsWarning)
{Label_Movie *lab;QString sJpg, sGif;switch (eType) {case eWater:lab = ui->labWater;sJpg = "warning_water.jpg";sGif = "warning_water.gif";break;case eOil:lab = ui->labOil;sJpg = "warning_oil.jpg";sGif = "warning_oil.gif";break;case eFuel:lab = ui->labFuel;sJpg = "warning_fuel.jpg";sGif = "warning_fuel.gif";break;case eEngine:lab = ui->labEngine;sJpg = "warning_engine.jpg";sGif = "warning_engine.gif";break;case eBattery:lab = ui->labBattery;sJpg = "warning_battery.jpg";sGif = "warning_battery.gif";break;case eBrake:lab = ui->labBrake;sJpg = "warning_brake.jpg";sGif = "warning_brake.gif";break;default:lab = nullptr;break;}if (nullptr == lab){return;}lab->f_Init(m_sRcPathPrefix);void (Label_Movie::*f_ptr)(const QString &sFileName) = bIsWarning ? &Label_Movie::f_SetGif : &Label_Movie::f_SetJpg;QString sPic = bIsWarning ? sGif : sJpg;(lab->*f_ptr)(sPic);
}
guage_warning.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Guage_Warning</class><widget class="QWidget" name="Guage_Warning"><property name="geometry"><rect><x>0</x><y>0</y><width>316</width><height>134</height></rect></property><property name="minimumSize"><size><width>129</width><height>66</height></size></property><property name="windowTitle"><string>Form</string></property><layout class="QGridLayout" name="gridLayout"><item row="0" column="0"><widget class="Label_Movie" name="labWater"><property name="text"><string>TextLabel</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item><item row="0" column="1"><widget class="Label_Movie" name="labOil"><property name="text"><string>TextLabel</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item><item row="0" column="2"><widget class="Label_Movie" name="labFuel"><property name="text"><string>TextLabel</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item><item row="1" column="0"><widget class="Label_Movie" name="labEngine"><property name="text"><string>TextLabel</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item><item row="1" column="1"><widget class="Label_Movie" name="labBattery"><property name="text"><string>TextLabel</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item><item row="1" column="2"><widget class="Label_Movie" name="labBrake"><property name="text"><string>TextLabel</string></property><property name="alignment"><set>Qt::AlignCenter</set></property></widget></item></layout></widget><customwidgets><customwidget><class>Label_Movie</class><extends>QLabel</extends><header>label_movie.h</header></customwidget></customwidgets><resources/><connections/>
</ui>
使用的时候更简洁:
void MainWindow::on_sbWaterTemp_valueChanged(int value)
{ui->lab_WaterTemp->f_SetTemp(value);ui->lab_WaterTempPolo->f_SetValue(value);ui->wWarning->f_SetStatus(Guage_Warning::eWater, (value > 120));
}void MainWindow::on_sbWaterTemp_2_valueChanged(int value)
{on_sbWaterTemp_valueChanged(value);
}void MainWindow::on_sbFuel_valueChanged(int value)
{ui->lab_FuelPolo->f_SetValue(value);ui->wWarning->f_SetStatus(Guage_Warning::eFuel, (value < 10));
}void MainWindow::on_sbTacho_valueChanged(int value)
{ui->lab_Tacho->f_SetValue(value);
}
整合故障灯后效果如下:
本文完。
相关文章:

Qt绘制动态仪表(模仿汽车仪表指针、故障灯)
背景: 项目需要,可能需要做一些仪表显示。此篇除了介绍实现方法,还要说明心路历程。对我而言,重要的是心理,而不是技术。写下来也是自勉。 本人起初心里是比较抵触的,从业20多年了,深知所谓界…...

【视频教程】GEE遥感云大数据在林业中的应用与典型案例实践
近年来遥感技术得到了突飞猛进的发展,航天、航空、临近空间等多遥感平台不断增加,数据的空间、时间、光谱分辨率不断提高,数据量猛增,遥感数据已经越来越具有大数据特征。遥感大数据的出现为相关研究提供了前所未有的机遇…...

【时时三省】c语言例题----华为机试题<字符串排序>
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 1,题目 HJ14 字符串排序 描述 给定 n 个字符串,请对 n 个字符串按照字典序排列。 数据范围: 1≤n≤1000 1≤n≤1000 ,字符串长度满足 1≤l…...

基于vue框架的城市体育运动交流平台15s43(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
系统程序文件列表 项目功能:用户,赛事类型,近期赛事,比赛报名,器材类型,器材信息,自由约战,运动队伍 开题报告内容 基于Vue框架的城市体育运动交流平台开题报告 一、项目背景与意义 随着城市化进程的加速和居民健康意识的提升,城市体育运动已成为现代…...

2024年软件测试经典大厂面试题(全3套)【包含答案】
前言 金三银四即将过去,后面迎来的便是金九银十,一直想着说分享一些软件测试的面试题,这段时间做了一些收集和整理,下面共有三篇经典面试题,大家可以试着做一下,答案附在后面,希望能帮助到大家。…...

What is Node.JS and its Pros and Cons
What is Node.JS and its Pros and Cons JavaScript is a client-side development tool. Node.js is a server-side development tool. And it’s only a runtime environment based on Chrome V8 so we don’t write some code in Node.js. Pros: JavaScript on a server …...

TestCraft - GPT支持的测试想法生成器和自动化测试生成器
在当今快速变化的软件开发世界中,自动化测试已成为确保软件质量的关键环节。而随着AI技术的进步,越来越多的工具开始引入人工智能,来辅助生成测试用例和自动化测试脚本。其中,TestCraft,作为一款GPT支持的测试想法生成…...

FreeRTOS内部机制学习04(任务通知和软件定时器)
文章目录 何为任务通知?任务通知使用例子任务通知的优势以及劣势优势劣势 深入源码看看API函数内部干了什么函数的种类函数都做了啥? 软件定时器软件定时器的作用软件定时器内部到底做了什么实现了“闹钟”功能引入守护任务,守护任务做了啥&a…...

华为eNSP :WLAN的配置
一、WLAN的知识点: VLAN配置: VLAN:可以想象成一个大房子(网络)里划分的不同房间(VLAN)。每个房间可以有自己的功能,比如一个用于睡觉(管理),另一…...

中国大数据产业的融资热潮来袭,哪些领域最受资本青睐?
大数据产业是以数据及数据所蕴含的信息价值为核心生产要素,通过数据技术、数据产品、数据服务等形式,使数据与信息价值在各行业经济活动中得到充分释放的赋能型产业。 基于启信产业大脑的海量数据与专业研判模型,本文将从产业图谱、区域分析…...

Unity数据持久化 之 使用Excel.DLL读写Excel表格
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 终于找到一个比较方便容易读表的方式了,以前用json读写excel转的cvs格式文件我怎么使用怎么别扭…...

Linux系统:chown命令
1、命令详解: chown命令用于设置文件所有者和文件关联组的命令,全称为change directory。在Linux当中默认文件均有拥有者,可以利用 chown 将指定文件的拥有者改为指定的用户或组,输入参数时用户可以是用户名或者用户 ID࿰…...

Unity3D ARPG(动作角色扮演游戏)设计与实现详解
动作角色扮演游戏(Action Role-Playing Game, ARPG)结合了传统角色扮演游戏(RPG)的深度与动作游戏(Action Game)的即时反应和流畅战斗体验。Unity3D 作为一款强大的跨平台游戏开发引擎,为开发者…...

Qt实现登录界面
本文基于Qt实现一个简单的登录界面,主要使用到Widget、button、edit等控件,基于自定义的信号槽实现界面的跳转,使用绘图设备添加背景图等。 1. 创建主界面 设计主界面的样式,并添加相关的控件。如下显示: 代码如下&…...

big.LITTLE
big.LITTLE 1 多核异构调度算法 http://www.linaro.org/?sbig.LITTLE http://git.linaro.org https://wiki.linaro.org/Archived%20LSK%20Versions big.LITTLE CPUs can be configured in 2 modes of operation: IKS – In Kernel Switcher (also known as CPU Migration…...

汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推
汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推 ①得物 【八大职类】技术、供应链、产品、运营、设计、职能、商品研究、风控等大类…...

再谈c++模板
前言 在前面我们曾经简单的介绍过c的模板,但还并不全面,我们通过stl容器的学习加深了我们对c这门语言的理解。那么今天我们就再来谈一谈c模板,对模板再进行一点简单的补充 非类型模板参数 前面我们介绍的是类型模板参数,简单理…...

9.11 codeforces Div 2
文章目录 9.11 Div 2A. Doras Set(删除三个互质数)思路代码 B. Index and Maximum Value(范围加减1求max)思路代码 C. Dora and C(加a/b,最小化极差)思路代码 9.11 Div 2 Dashboard - Codeforces Round 969 (Div. 2) …...

二级菜单的两种思路(完成部分)
第一种 <el-form ref"formRef" :model"form" :rules"rules" label-width"120px"><el-form-item label"类型" prop"type"><el-select v-model"form.type" placeholder"请选择类型&q…...

【机器学习导引】ch2-模型评估与选择
文章目录 经验误差与过拟合 (Empirical error &overfitting)1. **均方误差(Mean Squared Error, MSE)**2. **均方根误差(Root Mean Squared Error, RMSE)**3. **平均绝对误差(Mean Absolute…...

二开ihoneyBakFileScan备份扫描
优点:可以扫描根据域名生成的扫描备份的扫描工具 二开部分:默认网址到字典(容易被封),二开字典到网址(类似test404备份扫描规则),同时把被封不能扫描的网址保存到waf_url.txt 中&am…...

leetcode21. 合并两个有序链表
思路: 用一个新链表来表示合并后的有序链表, 每次比较两个链表,将较小的那个结点存储至新链表中 # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val0, nextNone): # self.val val # …...

搭建 WordPress 及常见问题与解决办法
浪浪云活动链接 :https://langlangy.cn/?i8afa52 文章目录 环境准备安装 LAMP 堆栈 (Linux, Apache, MySQL, PHP)配置 MySQL 数据库 安装 WordPress配置 WordPress常见问题及解决办法数据库连接错误白屏问题插件或主题冲突内存限制错误 本文旨在介绍如何在服务器上…...

《ORANGE‘s 一个操作系统的实现》--保护模式进阶
保护模式进阶 大内存读写 GDT段 ;GDT [SECTION .gdt] ; 段基址, 段界限 , 属性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 LABEL_DESC_NORMAL: Descriptor 0, 0ffffh, DA_DRW ; Normal 描…...

【可变参模板】可变参类模板
可变参类模板也和可变参函数模板一样,允许模板定义含有0到多个(任意个)模板参数。可变参类模板参数包的展开方式有多种,以下介绍几种常见的方法。 一、递归继承展开 1.1类型模板参数包的展开 首先先看下面的代码: /…...

Linux 递归删除大量的文件
一般情况下 在 Ubuntu 中,递归删除大量文件和文件夹可以通过以下几种方式快速完成。常用的方法是使用 rm 命令,配合一些适当的选项来提高删除速度和效率。 1. 使用 rm 命令递归删除 最常见的方式是使用 rm 命令的递归选项 -r 来删除目录及其所有内容。…...

设计一个算法,找出由str1和str2所指向两个链表共同后缀的起始位置
假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,则可共享相同的后缀存储空间,例如,’loading’和’being’的存储映像如下图所示。 设str1和str2分别指向两个单词所在单链表的头结点,链表结点结构为 data…...

Python中如何判断一个变量是否为None
在Python中,判断一个变量是否为None是一个常见的需求,特别是在处理可选值、默认值或者是在函数返回结果可能不存在时。虽然这个操作本身相对简单,但围绕它的讨论可以扩展到Python的哲学、类型系统、以及如何在不同场景下优雅地处理None值。 …...

表观遗传系列1:DNA 甲基化以及组蛋白修饰
1. 表观遗传 表观遗传信息很多为化学修饰,包括 DNA 甲基化以及组蛋白修饰,即DNA或蛋白可以通过化学修饰添加附加信息。 DNA位于染色质(可视为微环境)中,并不是裸露的,因此DNA分子研究需要跟所处环境结合起…...

Android 跳转至各大应用商店应用详情页
测试通过机型品牌: 华为、小米、红米、OPPO、一加、Realme、VIVO、IQOO、荣耀、魅族、三星 import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import …...