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

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

效果:

a962b05de3a946b48078be5bef15a3be.jpeg

其实我是仿照大众polo劲情的水温表画的。至于指针,既然是旋转肯定是角度。看到表盘的样式时,要大致估计一下,最左侧和左右侧的刻度大概是坐标轴上的多少度。算一下它的跨度,和实际需要的水温数值要有个转换。比方说,这个水温表的刻度刚好是水温和角度一一对应,所以不用转换。

图片仪表盘:

上面看到效果后会很有成就感,但要把仪表盘画得逼真可不容易,还要考虑缩放和字体,细节太多。因此有了这种方法,从网上找图片素材,自己加工仪表盘。直接先把图片画上去当背景,然后代码只控制表针即可。以后修改背景表盘,photoshop修图即可。

后期又做了小修改,因为图片作为资源文件,每个人安排的路径可能不同,通用起见,需要调用f_Init函数先初始化路径前缀。

先看我找的素材:

d814b1bb900543c890953131dc6a1ac0.jpeg

再看我修好的效果:

f45cc417af744fc0a094cea34aceea04.jpeg4b797a398adc43fe92b78c8c647bf3b3.jpeg5931d8ffe67c407ba81f61899e8e73b8.jpegd7a770143027477db7d06663705ecf2e.jpeg

上代码:

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

效果:

06057548e3274a0897c4917e90f396a0.jpeg

效果解析:

上面效果图中,我在界面上放置了滑动条,实际操作时,可以改变滑块位置,直接看到仪表动作。

警告灯:

在上述基础上,还可以使用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.

效果如下:

72c76309eae54449bba63d82be13a2fe.jpeg

当水温和油量到达警戒值时,自动亮起故障灯。

故障灯整合面板:

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绘制动态仪表(模仿汽车仪表指针、故障灯)

背景&#xff1a; 项目需要&#xff0c;可能需要做一些仪表显示。此篇除了介绍实现方法&#xff0c;还要说明心路历程。对我而言&#xff0c;重要的是心理&#xff0c;而不是技术。写下来也是自勉。 本人起初心里是比较抵触的&#xff0c;从业20多年了&#xff0c;深知所谓界…...

【视频教程】GEE遥感云大数据在林业中的应用与典型案例实践

近年来遥感技术得到了突飞猛进的发展&#xff0c;航天、航空、临近空间等多遥感平台不断增加&#xff0c;数据的空间、时间、光谱分辨率不断提高&#xff0c;数据量猛增&#xff0c;遥感数据已经越来越具有大数据特征。遥感大数据的出现为相关研究提供了前所未有的机遇&#xf…...

【时时三省】c语言例题----华为机试题<字符串排序>

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 1&#xff0c;题目 HJ14 字符串排序 描述 给定 n 个字符串&#xff0c;请对 n 个字符串按照字典序排列。 数据范围&#xff1a; 1≤n≤1000 1≤n≤1000 &#xff0c;字符串长度满足 1≤l…...

基于vue框架的城市体育运动交流平台15s43(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,赛事类型,近期赛事,比赛报名,器材类型,器材信息,自由约战,运动队伍 开题报告内容 基于Vue框架的城市体育运动交流平台开题报告 一、项目背景与意义 随着城市化进程的加速和居民健康意识的提升&#xff0c;城市体育运动已成为现代…...

2024年软件测试经典大厂面试题(全3套)【包含答案】

前言 金三银四即将过去&#xff0c;后面迎来的便是金九银十&#xff0c;一直想着说分享一些软件测试的面试题&#xff0c;这段时间做了一些收集和整理&#xff0c;下面共有三篇经典面试题&#xff0c;大家可以试着做一下&#xff0c;答案附在后面&#xff0c;希望能帮助到大家。…...

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支持的测试想法生成器和自动化测试生成器

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

FreeRTOS内部机制学习04(任务通知和软件定时器)

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

华为eNSP :WLAN的配置

一、WLAN的知识点&#xff1a; VLAN配置&#xff1a; VLAN&#xff1a;可以想象成一个大房子&#xff08;网络&#xff09;里划分的不同房间&#xff08;VLAN&#xff09;。每个房间可以有自己的功能&#xff0c;比如一个用于睡觉&#xff08;管理&#xff09;&#xff0c;另一…...

中国大数据产业的融资热潮来袭,哪些领域最受资本青睐?

大数据产业是以数据及数据所蕴含的信息价值为核心生产要素&#xff0c;通过数据技术、数据产品、数据服务等形式&#xff0c;使数据与信息价值在各行业经济活动中得到充分释放的赋能型产业。 基于启信产业大脑的海量数据与专业研判模型&#xff0c;本文将从产业图谱、区域分析…...

Unity数据持久化 之 使用Excel.DLL读写Excel表格

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

Linux系统:chown命令

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

Unity3D ARPG(动作角色扮演游戏)设计与实现详解

动作角色扮演游戏&#xff08;Action Role-Playing Game, ARPG&#xff09;结合了传统角色扮演游戏&#xff08;RPG&#xff09;的深度与动作游戏&#xff08;Action Game&#xff09;的即时反应和流畅战斗体验。Unity3D 作为一款强大的跨平台游戏开发引擎&#xff0c;为开发者…...

Qt实现登录界面

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

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秋招内推

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

再谈c++模板

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

9.11 codeforces Div 2

文章目录 9.11 Div 2A. Doras Set&#xff08;删除三个互质数&#xff09;思路代码 B. Index and Maximum Value&#xff08;范围加减1求max&#xff09;思路代码 C. Dora and C(加a/b&#xff0c;最小化极差)思路代码 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-模型评估与选择

文章目录 经验误差与过拟合 &#xff08;Empirical error &overfitting&#xff09;1. **均方误差&#xff08;Mean Squared Error, MSE&#xff09;**2. **均方根误差&#xff08;Root Mean Squared Error, RMSE&#xff09;**3. **平均绝对误差&#xff08;Mean Absolute…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

MySQL JOIN 表过多的优化思路

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

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...