完成热力图部分,取消边框,背景透明

This commit is contained in:
2025-10-23 10:09:13 +08:00
parent 62c93e51ee
commit 8494a9c94e
6 changed files with 302 additions and 125 deletions

View File

@@ -13,25 +13,31 @@
#include <qobject.h> #include <qobject.h>
#include <qsize.h> #include <qsize.h>
using namespace creeper::plot_widget::internal;
BasicPlot::BasicPlot() : pimpl{std::make_unique<Impl>(*this)} { BasicPlot::BasicPlot() : pimpl{std::make_unique<Impl>(*this)} {
init_plot(); // setStyleSheet("background-color: rgb(255, 0, 0);");
// QColor lightBlue(230, 240, 250);
setBackground(Qt::transparent);
} }
BasicPlot::~BasicPlot() {} BasicPlot::~BasicPlot() {}
void BasicPlot::set_matrix_size(const QSize& size) { void BasicPlot::set_matrix_size(const QSize& size) {
qDebug() << "set matrix size" << size; qDebug() << "set matrix size" << size;
matrix_size = size;
pimpl->set_matrix_size(size); pimpl->set_matrix_size(size);
} }
void BasicPlot::set_matrix_size(const int& w, const int& h) { void BasicPlot::set_matrix_size(const int& w, const int& h) {
QSize size(w, h); QSize size(w, h);
qDebug() << "set matrix size" << size; qDebug() << "set matrix size" << size;
matrix_size = size;
pimpl->set_matrix_size(size); pimpl->set_matrix_size(size);
} }
void BasicPlot::set_color_gradient_range(const double& min, const double& max) {
pimpl->set_color_gradient_range(min, max);
}
void BasicPlot::set_xlabel_text(const QString& text) { void BasicPlot::set_xlabel_text(const QString& text) {
pimpl->set_xlabel_text(text); pimpl->set_xlabel_text(text);
} }
@@ -41,94 +47,50 @@ void BasicPlot::set_ylabel_text(const QString& text) {
} }
void BasicPlot::load_theme_manager(ThemeManager& mgr) { void BasicPlot::load_theme_manager(ThemeManager& mgr) {
pimpl->load_theme_manager(mgr);
} }
QSize BasicPlot::get_matrix_size() { QSize BasicPlot::get_matrix_size() const {
return matrix_size; return pimpl->get_matrix_size();
} }
void BasicPlot::set_data(const QVector<PointData>& data) {
qDebug() << "set data" << data.size();
pimpl->set_data(data);
}
bool BasicPlot::is_initialized() const {
return pimpl->is_plot_initialized();
}
void BasicPlot::init_plot() { void BasicPlot::init_plot() {
QVector<PointData> origin_data = {PointData{0, 0, 5}, PointData{0, 1, 3}, PointData{0, 2, 0}, pimpl->initialize_plot();
PointData{1, 0, 5}, PointData{1, 1, 3}, PointData{1, 2, 9},
PointData{2, 0, 5}, PointData{2, 1, 3}, PointData{2, 2, 3},
PointData{3, 0, 5}, PointData{3, 1, 3}, PointData{3, 2, 8}};
QCPColorMap* cpmp = new QCPColorMap(xAxis, yAxis);
qDebug() << "cpmp->data()->setSize():" << matrix_size;
cpmp->data()->setSize(matrix_size.width(), matrix_size.height());
cpmp->data()->setRange(QCPRange(0.5, matrix_size.width()), (QCPRange(0.5, matrix_size.height())));
// cpmp ->setSize(matrix_size.width(), matrix_size.height());
// cpmp ->setRange(QCPRange(0.5, matrix_size.width() - 0.5), QCPRange(0.5, matrix_size.height() - 0.5));
QSharedPointer<QCPAxisTickerText> xticker(new QCPAxisTickerText);
QSharedPointer<QCPAxisTickerText> yticker(new QCPAxisTickerText);
xticker->setSubTickCount(1);
xticker->setSubTickCount(1);
xAxis->setTicker(xticker);
yAxis->setTicker(yticker);
xAxis->grid()->setPen(Qt::NoPen);
yAxis->grid()->setPen(Qt::NoPen);
xAxis->grid()->setSubGridVisible(true);
yAxis->grid()->setSubGridVisible(true);
xAxis->setSubTicks(true);
yAxis->setSubTicks(true);
xAxis->setTickLength(0);
yAxis->setTickLength(0);
xAxis->setSubTickLength(6);
yAxis->setSubTickLength(6);
xAxis->setRange(0, matrix_size.width());
yAxis->setRange(0, matrix_size.height());
for (const auto& item : origin_data) {
cpmp->data()->setCell(item.x, item.y, item.z);
}
QCPColorScale* color_scale = new QCPColorScale(this);
color_scale->setType(QCPAxis::atBottom);
this->plotLayout()->addElement(1, 0, color_scale);
cpmp->setColorScale(color_scale);
QCPColorGradient gradient;
gradient.setColorStopAt(0.0, QColor("#F6EFA6"));
gradient.setColorStopAt(1.0, QColor("#BF444C"));
cpmp->setGradient(gradient);
cpmp->setDataRange(QCPRange(0, 10));
cpmp->setInterpolate(false);
QCPMarginGroup *margin_group = new QCPMarginGroup(this);
axisRect()->setMarginGroup(QCP::msLeft | QCP::msRight, margin_group);
color_scale->setMarginGroup(QCP::msLeft | QCP::msRight, margin_group);
} }
void BasicPlot::dataChanged(QVector<PointData>& map) { void BasicPlot::paintEvent(QPaintEvent* event) {
auto *cpmp = static_cast<QCPColorMap*>(this->plottable(0)); // 确保在绘制前初始化
if (!is_initialized()) {
size_t key_size = cpmp->data()->keySize(); init_plot();
size_t value_size = cpmp->data()->valueSize();
for (auto& item : map) {
if (cpmp->data()->alpha(item.x, item.y)) {
if (cpmp->data()->alpha(item.x, item.y)) {
cpmp->data()->setCell(item.x, item.y, item.z);
} }
} QCustomPlot::paintEvent(event);
}
replot();
} }
void BasicPlot::update_dynamic_heatmap(QVector<PointData>& map) { void BasicPlot::dataChanged(const QVector<PointData>& map) {
auto *cpmp = static_cast<QCPColorMap*>(this->plottable(0)); set_data(map);
// emit dataChanged(map);
}
size_t key_size = cpmp->data()->keySize(); void BasicPlot::dataRangeChanged(const double& min, const double& max) {
size_t value_size = cpmp->data()->valueSize(); set_color_gradient_range(min, max);
for (auto& item: map) { // emit dataRangeChanged(min, max);
if (cpmp->data()->alpha(item.x, item.y)) { }
cpmp->data()->setCell(item.x, item.y, item.z);
}
}
replot(); void BasicPlot::update_dynamic_heatmap(const QVector<PointData>& map) {
set_data(map);
} }
using namespace creeper; using namespace creeper;
auto HeatMapPlot::paintEvent(QPaintEvent* event) -> void {
QCustomPlot::paintEvent(event); void creeper::HeatMapPlot::paintEvent(QPaintEvent* event) {
BasicPlot::paintEvent(event);
} }

View File

@@ -13,6 +13,7 @@
#include "modern-qt/utility/wrapper/widget.hh" #include "modern-qt/utility/wrapper/widget.hh"
#include <concepts> #include <concepts>
#include <qcontainerfwd.h> #include <qcontainerfwd.h>
#include <qvector.h>
struct point_data { struct point_data {
double x; double x;
@@ -26,47 +27,49 @@ class HeatMapPlot;
namespace plot_widget::internal { namespace plot_widget::internal {
class BasicPlot : public QCustomPlot { class BasicPlot : public QCustomPlot {
CREEPER_PIMPL_DEFINITION(BasicPlot)
friend class HeatMapPlot;
public: public:
// CREEPER_PIMPL_DEFINITION(BasicPlot); // BasicPlot();
BasicPlot(); // ~BasicPlot();
~BasicPlot(); // BasicPlot(const BasicPlot&) = delete;
BasicPlot(const BasicPlot&) = delete; // BasicPlot& operator=(const BasicPlot&) = delete;
BasicPlot& operator=(const BasicPlot&) = delete; private: struct Impl;
std::unique_ptr<Impl> pimpl;
friend HeatMapPlot;
public:
struct ColorSpace {};
void init_plot(); void init_plot();
void load_theme_manager(ThemeManager&);
void load_theme_manager(ThemeManager&); void set_xlabel_text(const QString&); void set_xlabel_text(const QString&);
void set_ylabel_text(const QString&); void set_ylabel_text(const QString&);
void set_matrix_size(const QSize&); void set_matrix_size(const QSize&);
void set_matrix_size(const int& w, const int& h); void set_matrix_size(const int& w, const int& h);
void set_data(const QVector<PointData>& data);
void set_color_gradient_range(const double& min, const double& max);
QSize get_matrix_size() const;
bool is_initialized() const;
public slots: public slots:
void update_dynamic_heatmap(QVector<PointData>& map); void update_dynamic_heatmap(const QVector<PointData>& map);
void dataChanged(QVector<PointData>& map); void dataChanged(const QVector<PointData>& map);
void dataRangeChanged(const double& min, const double& max);
protected:
void paintEvent(QPaintEvent*) override;
private: private:
QSize get_matrix_size(); friend struct Impl;
private:
friend class Impl;
QSize matrix_size = {3, 4};
}; };
} // namespace plot_widget::internal } // namespace plot_widget::internal
namespace plot_widget::pro { namespace plot_widget::pro {
using Token = common::Token<internal::BasicPlot>; using Token = common::Token<plot_widget::internal::BasicPlot>;
using XLabelText =
common::pro::String<Token, [](auto& self, const auto& string) { using XLabelText = common::pro::String<Token,
[](auto& self, const auto& string) {
self.set_xlabel_text(string); self.set_xlabel_text(string);
}>; }>;
using YLabelText =
common::pro::String<Token, [](auto& self, const auto& string) { using YLabelText = common::pro::String<Token,
[](auto& self, const auto& string) {
self.set_ylabel_text(string); self.set_ylabel_text(string);
}>; }>;
@@ -75,7 +78,21 @@ namespace plot_widget::pro {
explicit MatrixSize(const int& w, const int& h) : size{w, h} {} explicit MatrixSize(const int& w, const int& h) : size{w, h} {}
explicit MatrixSize(const QSize& s) : size{s} {} explicit MatrixSize(const QSize& s) : size{s} {}
void apply(auto& self) const { void apply(auto& self) const {
self.set_matrix_size(size.width(), size.height()); self.set_matrix_size(size);
}
};
using Data = common::pro::Vector<Token, PointData,
[](auto& self, const auto& data) {
self.set_data(data);
}>;
struct ColorRange : Token {
double min;
double max;
explicit ColorRange(double min, double max) : min{min}, max{max} {}
void apply(auto& self) const {
self.set_color_gradient_range(min, max);
} }
}; };
@@ -83,13 +100,26 @@ namespace plot_widget::pro {
using OnDataChanged = using OnDataChanged =
common::pro::SignalInjection<F, Token, &internal::BasicPlot::dataChanged>; common::pro::SignalInjection<F, Token, &internal::BasicPlot::dataChanged>;
template <typename F>
using OnDataRangeChanged =
common::pro::SignalInjection<F, Token, &internal::BasicPlot::dataRangeChanged>;
template<class PlotWidget> template<class PlotWidget>
concept trait = std::derived_from<PlotWidget, Token>; concept trait = std::derived_from<PlotWidget, Token>;
using PlotData = common::pro::Vector<Token, PointData, [](auto& self, const auto& vec) {
self.set_data(vec);
}>;
using DataRange = common::pro::Array<Token, int, 2, [](auto& self, const auto& arr) {
self.set_color_gradient_range(arr[0], arr[1]);
}>;
CREEPER_DEFINE_CHECKER(trait); CREEPER_DEFINE_CHECKER(trait);
using namespace widget::pro; using namespace widget::pro;
using namespace theme::pro; using namespace theme::pro;
} }
struct HeatMapPlot struct HeatMapPlot
: public Declarative<plot_widget::internal::BasicPlot, : public Declarative<plot_widget::internal::BasicPlot,
CheckerOr<plot_widget::pro::checker, widget::pro::checker, theme::pro::checker>> { CheckerOr<plot_widget::pro::checker, widget::pro::checker, theme::pro::checker>> {
@@ -97,4 +127,5 @@ struct HeatMapPlot
void paintEvent(QPaintEvent*) override; void paintEvent(QPaintEvent*) override;
}; };
} }
#endif // TOUCHSENSOR_HEATMAP_H #endif // TOUCHSENSOR_HEATMAP_H

View File

@@ -9,34 +9,182 @@
#include "modern-qt/utility/theme/theme.hh" #include "modern-qt/utility/theme/theme.hh"
#include "modern-qt/widget/sliders.hh" #include "modern-qt/widget/sliders.hh"
#include <memory> #include <memory>
#include <qcolor.h>
#include <qdebug.h>
using namespace creeper::plot_widget::internal; using namespace creeper::plot_widget::internal;
struct BasicPlot::Impl { struct BasicPlot::Impl {
explicit Impl(BasicPlot& self) noexcept : self{self} {} explicit Impl(BasicPlot& self) noexcept : self{self}, initialized(false), matrix_size(QSize{3, 4}) {}
public: public:
auto set_xlabel_text(const QString& text) -> void { xlabel = text; } auto set_xlabel_text(const QString& text) -> void {
xlabel = text;
auto set_ylabel_text(const QString& text) -> void { ylabel = text; } if (initialized) {
self.xAxis->setLabel(text);
auto set_matrix_size(const QSize& size) { self.replot();
matrix_size.setWidth(size.width()); }
matrix_size.setHeight(size.height());
} }
auto load_theme_manager(ThemeManager& mgr) { auto set_ylabel_text(const QString& text) -> void {
// mgr.append_handler(&self, [this](const ThemeManager& mgr){ ylabel = text;
// set_color_scheme(mgr.color_scheme()); if (initialized) {
// }); self.yAxis->setLabel(text);
self.replot();
}
} }
// auto set_color_scheme(slider::pro::Measurements measurements) { auto set_matrix_size(const QSize& size) -> void {
// matrix_size = size;
// } if (initialized) {
private: // 重新初始化热力图以适应新的矩阵大小
reset_plot();
if (!data_points.isEmpty()) {
set_data(data_points);
}
}
}
auto load_theme_manager(ThemeManager& mgr) -> void {
mgr.append_handler(&self, [this](const ThemeManager& mgr) {
// 可以根据主题更新颜色渐变等
if (initialized) {
self.replot();
}
});
}
auto set_color_gradient_range(const double& min, const double& max) -> void {
if (initialized && self.plottableCount() > 0) {
auto* cpmp = static_cast<QCPColorMap*>(self.plottable(0));
cpmp->setDataRange(QCPRange(min, max));
self.replot();
}
color_min = min;
color_max = max;
}
auto set_data(const QVector<PointData>& data) -> void {
data_points = data;
if (initialized) {
update_plot_data();
}
}
auto initialize_plot() -> void {
if (initialized) return;
// 创建颜色映射
QCPColorMap* cpmp = new QCPColorMap(self.xAxis, self.yAxis);
qDebug() << "initialize_plot() size:" << matrix_size;
cpmp->data()->setSize(matrix_size.width(), matrix_size.height());
cpmp->data()->setRange(QCPRange(0.5, matrix_size.width() - 0.5),
QCPRange(0.5, matrix_size.height() - 0.5));
// 配置坐标轴
QSharedPointer<QCPAxisTickerText> xticker(new QCPAxisTickerText);
QSharedPointer<QCPAxisTickerText> yticker(new QCPAxisTickerText);
xticker->setSubTickCount(1);
yticker->setSubTickCount(1);
self.xAxis->setVisible(false);
self.yAxis->setVisible(false);
self.xAxis->setTicker(xticker);
self.yAxis->setTicker(yticker);
// 设置网格
self.xAxis->grid()->setPen(Qt::NoPen);
self.yAxis->grid()->setPen(Qt::NoPen);
self.xAxis->grid()->setSubGridVisible(true);
self.yAxis->grid()->setSubGridVisible(true);
self.xAxis->setSubTicks(true);
self.yAxis->setSubTicks(true);
self.xAxis->setTickLength(0);
self.yAxis->setTickLength(0);
self.xAxis->setSubTickLength(6);
self.yAxis->setSubTickLength(6);
// 设置范围
self.xAxis->setRange(0, matrix_size.width());
self.yAxis->setRange(0, matrix_size.height());
// 设置标签
if (!xlabel.isEmpty()) self.xAxis->setLabel(xlabel);
if (!ylabel.isEmpty()) self.yAxis->setLabel(ylabel);
// 添加颜色刻度
QCPColorScale* color_scale = new QCPColorScale(&self);
color_scale->setType(QCPAxis::atBottom);
self.plotLayout()->addElement(1, 0, color_scale);
cpmp->setColorScale(color_scale);
// 设置颜色渐变
QCPColorGradient gradient;
gradient.setColorStopAt(0.0, QColor(246, 239, 166)); // F6EFA6
gradient.setColorStopAt(1.0, QColor(191, 68, 76)); // BF444C
cpmp->setGradient(gradient);
// 设置数据范围
cpmp->setDataRange(QCPRange(color_min, color_max));
cpmp->setInterpolate(false);
// 配置边距
QCPMarginGroup *margin_group = new QCPMarginGroup(&self);
self.axisRect()->setMarginGroup(QCP::msLeft | QCP::msRight, margin_group);
color_scale->setMarginGroup(QCP::msLeft | QCP::msRight, margin_group);
initialized = true;
// 如果已有数据,更新图表
if (!data_points.isEmpty()) {
update_plot_data();
}
}
auto reset_plot() -> void {
// 清除所有绘图元素
self.clearPlottables();
self.clearGraphs();
self.clearItems();
self.clearFocus();
// 重新初始化
initialized = false;
initialize_plot();
}
auto update_plot_data() -> void {
if (!initialized || self.plottableCount() == 0) return;
auto* cpmp = static_cast<QCPColorMap*>(self.plottable(0));
// 设置新数据
for (const auto& item : data_points) {
if (item.x >= 0 && item.x < matrix_size.width() &&
item.y >= 0 && item.y < matrix_size.height()) {
cpmp->data()->setCell(item.x, item.y, item.z);
}
}
// 重绘
self.replot();
}
auto is_plot_initialized() const -> bool {
return initialized;
}
auto get_matrix_size() const -> QSize {
return matrix_size;
}
private:
QString xlabel; QString xlabel;
QString ylabel; QString ylabel;
QSize matrix_size; QSize matrix_size;
QVector<PointData> data_points;
double color_min = 0.0;
double color_max = 15.0;
bool initialized;
BasicPlot& self; BasicPlot& self;
}; };

View File

@@ -44,6 +44,8 @@ static auto ComConfigComponent(ThemeManager& manager, auto&& callback) {
auto select_baud_context = std::make_shared<MutableValue<QStringList>>(); auto select_baud_context = std::make_shared<MutableValue<QStringList>>();
select_baud_context->set_silent(QStringList {"9600", "115200"}); select_baud_context->set_silent(QStringList {"9600", "115200"});
const auto row = new Row { const auto row = new Row {
// lnpro::Item<FilledTextField> { // lnpro::Item<FilledTextField> {
// text_field::pro::ThemeManager {manager}, // text_field::pro::ThemeManager {manager},
@@ -148,11 +150,22 @@ static auto ComConfigComponent(ThemeManager& manager, auto&& callback) {
} }
static auto DisplayComponent(ThemeManager& manager, int index = 0) noexcept { static auto DisplayComponent(ThemeManager& manager, int index = 0) noexcept {
auto heatmap_context = std::make_shared<MutableValue<QVector<PointData>>>();
heatmap_context->set_silent(QVector<PointData>{
PointData{0, 0, 1}, PointData{1, 0, 2}, PointData{2, 0, 3},
PointData{0, 1, 3}, PointData{1, 1, 4}, PointData{2, 1, 5},
PointData{0, 2, 6}, PointData{1, 2, 7}, PointData{2, 2, 8},
PointData{0, 3, 9}, PointData{1, 3, 10}, PointData{2, 3, 11},
});
const auto row = new Row{ const auto row = new Row{
lnpro::Item<HeatMapPlot> { lnpro::Item<HeatMapPlot> {
plot_widget::pro::SizePolicy { plot_widget::pro::SizePolicy {
QSizePolicy::Expanding, QSizePolicy::Expanding,
}, },
MutableForward {
plot_widget::pro::PlotData {},
heatmap_context,
},
pwpro::MatrixSize { pwpro::MatrixSize {
QSize{3, 4} QSize{3, 4}
}, },

View File

@@ -46,7 +46,11 @@ auto main(int argc, char *argv[]) -> int {
[&](MainWindow& window) noexcept { [&](MainWindow& window) noexcept {
}, },
mwpro::FixedSize {1080, 720}, // mwpro::FixedSize {1080, 720},
mwpro::MinimumSize {
1080,
720
},
mwpro::Central<FilledCard> { mwpro::Central<FilledCard> {
capro::ThemeManager {manager}, capro::ThemeManager {manager},
capro::Radius {0}, capro::Radius {0},

View File

@@ -131,6 +131,25 @@ namespace pro {
} }
}; };
template <class Token, typename T, std::size_t N, auto setter>
struct Array : public std::array<T, N>, Token {
using std::array<T, N>::array;
explicit Array(const std::array<T, N>& arr) noexcept
: std::array<T, N> { arr } { }
template <typename... Args>
requires (sizeof...(Args) == N)
explicit Array(Args&&... args) noexcept
: std::array<T, N> {
std::forward<Args>(args)...} {}
void apply(auto& self) const
requires requires {setter(self, *this);}
{
setter(self, *this);
}
};
// template<class Token, typename T, auto setter> // template<class Token, typename T, auto setter>
// Vector<Token, T, setter>::Vector(const QVector<T> &vec) noexcept:QVector { vec } { } // Vector<Token, T, setter>::Vector(const QVector<T> &vec) noexcept:QVector { vec } { }