Files
energy_storage/src/pv/PvTable.cpp
2025-08-22 19:06:50 +08:00

432 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "PvTable.h"
#include "PvStyle.h"
#include "pv/PvApp.h"
static const string STYLE_BKG =
"border-width:1 1 1 1px; border-style:outset solid; border-color:rgba(180,180,180,255);"
"background-color:rgba(80,80,80,0);";
//*********************************************************************************************************************
// PvTable
PvTable::PvTable(PARAM* p, int parent, int x, int y, int w, int row, Options& opts)
//: PvWidget(p, parent, PvRect(x, y, w, opts.item_height* row + (opts.show_header ? (opts.header_height) : 0))),
: PvObject(p), option_(opts), nRow_(row), nCol_(0)
{
// 计算表格的显示区域
int h = opts.row_height* row + (opts.show_header ? (opts.head_height) : 0);
rect_.set(x, y, w, h);
// 表格的主窗体QWidget设置样式无效
pvid_ = PvApp::widget(p, parent, x, y, w, h+1);
// 表格的背景色和边框样式
PvApp::label(p, pvid_, 0, 0, w, h+1, "", qss::QSS_TABLE);
vecHead_.resize(0);
vecRows_.resize(nRow_);
vecData_.resize(nRow_);
// 创建行高亮显示背景
for (int row = 0; row < nRow_; row++)
{
int y = item_posy(row);
string qss = (row % 2 != 0) ? qss::QSS_TABLE_ROW_0 : qss::QSS_TABLE_ROW_1;
int rowBkg = PvApp::label(p, pvid_, 1, y, rect_.w-2, option_.row_height, "", qss);
pvHide(p, rowBkg);
vecRows_[row].bkg = rowBkg;
}
}
void PvTable::addHead(string id, string text, int width, vector<pair<string, string>> mapping)
{
vecHead_.push_back(Head(id, text, width, mapping));
nCol_ = vecHead_.size();
if (width <= -1) { width = rect_.w-1 - posCol_; }
int col = nCol_ - 1;
// 创建表头的标签
if (option_.show_header)
{
vecHead_[col].pvid = PvApp::label(p, pvid_, posCol_, 0, width, option_.head_height, text, qss::QSS_TABLE_HEAD);
}
// 创建列的单元格
for (int row = 0; row < nRow_; ++row)
{
int y = item_posy(row);
int pvid = PvApp::label(p, pvid_, posCol_, y, width, option_.row_height, "", qss::QSS_TABLE_CELL);
vecRows_[row].vecCells.push_back(pvid);
PvApp::bind(p, MOUSE_OVER_EVENT, pvid, [=](string s) { highlight(row, (s == "1")); });
}
posCol_ += width;
}
void PvTable::addHead(vector<string> vec_text)
{
int colSize = vec_text.size();
int x = 0;
for (int i = 0; i < vec_text.size(); ++i)
{
int w = float(rect_.w-1) * float(i+1) / float(colSize);
string text = vec_text[i];
this->addHead(text, text, w-x);
x = w;
}
}
void PvTable::setRowVisible(int row, bool v)
{
if (row < 0 || row >= vecRows_.size())
{
return;
}
auto& rowItem = vecRows_[row];
if (rowItem.visible != v)
{
rowItem.visible = v;
rowItem.visible ? pvShow(p, rowItem.bkg) : pvHide(p, rowItem.bkg);
if (!v)
{
for (int col = 0; col<rowItem.vecCells.size(); ++col)
{
pvSetText(p, rowItem.vecCells[col], "");
}
}
}
}
void PvTable::highlight(int row, bool v)
{
string qss = ((row % 2 != 0) ? qss::QSS_TABLE_ROW_0 : qss::QSS_TABLE_ROW_1);
if (vecRows_.size() > 0 && row <= vecRows_.size())
{
if (v) { qss = "background-color:rgba(14,45,60,200);border:1px solid rgba(255,0,0,100);"; }
pvSetStyleSheet(p, vecRows_[row].bkg, qss.c_str());
}
}
void PvTable::addOperate(vector<string> vecOpt)
{
// 创建表头的标签
if (option_.show_header)
{
PvApp::label(p, pvid_, posCol_, 0, rect_.w - posCol_, option_.head_height, "操作", qss::QSS_TABLE_HEAD);
}
for (int row = 0; row < nRow_; ++row)
{
int y = item_posy(row);
int cellWidget = PvApp::label(p, pvid_, posCol_, y, rect_.w - posCol_, option_.row_height, "", qss::QSS_TABLE_CELL);
//PvInstance::bind_event(p, MOUSE_OVER_EVENT, btn_opt, [=](string s) { highlight(row, (s == "1")); });
vecOpt_.push_back({ cellWidget, vector<int>() });
auto& vec_opt_btn_ = vecOpt_.back().second;
int x = 5, w = 60;
for (int i = 0; i < vecOpt.size(); i++)
{
auto& title = vecOpt[i];
w = 20 + 15 * title.size() / 3;
int btn = PvApp::button(p, cellWidget, x, 4, w, 24, title, qss::button(14, "", "", "none; border-radius: 0px"));
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](std::string) {
if (cbOperate_) { cbOperate_(row, 0, title); }
});
vec_opt_btn_.push_back(btn);
x += (w + 5);
}
pvHide(p, cellWidget);
}
}
void PvTable::setOperateCallback(CallbackTableOpt cb)
{
cbOperate_ = cb;
};
void PvTable::set_text(PARAM* p, int row, int col, string text, string style)
{
if (row < nRow_ && col < nCol_)
{
pvSetText(p, vecRows_[row].vecCells[col], text.c_str());
if (!style.empty())
{
int idx = row + 1;
if (idx % 2 != 0)
{
style = item_base_style_ + style;
}
else
{
style = item_base_style_ + style;
}
//style = "qproperty-alignment:AlignCenter;" + style + "}";
string s = "QLabel{" + style + "} QLabel:disabled{color:rgb(150,150,150)}";
pvSetStyleSheet(p, vecRows_[row].vecCells[col], s.c_str());
}
}
}
void PvTable::setRowData(int row, Fields& d)
{
if (row >= nRow_) { return; }
vecData_[row] = d;
for (int col = 0; col < vecHead_.size(); ++col)
{
auto& head = vecHead_[col];
string text = d.value(head.id);
text = head.getMapping(text);
pvSetText(p, vecRows_[row].vecCells[col], text.c_str());
}
setRowVisible(row, true);
this->setOperateVisible(row, d.size() > 0);
}
void PvTable::setRowData(int row, std::vector<std::string> vd)
{
if (row >= nRow_) { return; }
pvShow(p, vecRows_[row].bkg);
for (int col = 0; col < vecHead_.size(); ++col)
{
if (col < vd.size()) {
auto& head = vecHead_[col];
string text = head.getMapping(vd[col]);
pvSetText(p, vecRows_[row].vecCells[col], text.c_str());
}
}
setRowVisible(row, true);
this->setOperateVisible(row, vd.size() > 0);
}
Fields PvTable::getRowData(int row)
{
static Fields tmp;
return (row >= 0 && row < vecData_.size()) ? vecData_[row] : tmp;
}
void PvTable::mappingData(Fields& fields)
{
for (int i=0; i< vecHead_.size(); ++i)
{
auto& head = vecHead_[i];
if (fields.hasKey(head.id))
{
auto& val = fields.value(head.id);
val = head.getMapping(val);
}
}
}
void PvTable::set_border_visible(PARAM* p, bool v)
{
v ? pvShow(p, border_id_) : pvHide(p, border_id_);
}
int PvTable::item_posy(int row)
{
return option_.show_header ? row * option_.row_height + option_.head_height : row * option_.row_height;
}
void PvTable::add_col_button(PARAM* p, int col, string title, PvRect& rt, string style)
{
if (col >= nCol_)
{
return;
}
for (int row = 0; row < nRow_; ++row)
{
int id = PvApp::button(p, vecRows_[row].vecCells[col], rt.x, rt.y, rt.w, rt.h, title, style);
pvHide(p, id);
vec_col_item_btn_[row].push_back(id);
//PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, id, [=](string s)
//{
// if (cb_operate_)
// {
// cb_operate_(row, col, title);
// }
//});
}
}
void PvTable::add_col_button(PARAM* p, int col, vector<string> vec_title)
{
int x = 5;
int w = 0;
for (int i = 0; i < vec_title.size(); i++)
{
auto& title = vec_title[i];
w = 20 + 20 * title.size() / 3;
this->add_col_button(p, col, title, PvRect(x, 3, w, 28), qss::button());
x += (w + 5);
}
}
void PvTable::setOperateVisible(int row, bool v, int id)
{
if (row < vecOpt_.size())
{
auto& vec_opt_btn = vecOpt_[row].second;
int pvid = id < 0 ? vecOpt_[row].first : ((id < vec_opt_btn.size()) ? vec_opt_btn[id] : PV_ID_NUL);
v ? pvShow(p, pvid) : pvHide(p, pvid);
}
}
int PvTable::border_id()
{
return border_id_;
}
int PvTable::rows()
{
return nRow_;
}
int PvTable::colums()
{
return nCol_;
}
vector<Fields> PvTable::data()
{
return vecData_;
}
PvTable::Head& PvTable::header(int col)
{
return vecHead_[col];
}
static const string STYLE_NORMAL =
"QPushButton { background-color:rgba(255,255,255,30);border-radius:0px;font:bold 16px ;color:white;border:1px solid #20a481;}"
"QPushButton:hover { background-color:rgba(32,164,128,255);color:white;}"
"QPushButton:pressed { border-width:3px 0 0 3px;border-style:inset;color:white;}"
"QPushButton:disabled { color: gray; border-color: gray; }";
static const string STYLE_ACTIVE =
"QPushButton { background-color:rgba(32,164,128,255);border-radius:0px;font:bold 16px ;color:white;border:1px solid #20a481;}"
"QPushButton:hover { background-color:rgba(32,164,128,255);color:white;}"
"QPushButton:pressed { border-width:3px 0 0 3px;border-style:inset;color:white;}"
"QPushButton:disabled { color: gray; border-color: gray; }";
PvPagination::PvPagination(PARAM* p, int parent, int x, int y, int n)
: PvObject(p)
{
pvid = PvApp::label(p, parent, x, y, 2*32 + 80, 30, "", "border: 0px solid gray;");
// 分页控件
btnPrev = PvApp::button(p, pvid, 0, 0, 30, 30, "<", STYLE_NORMAL);
for (int i = 0; i < n; i++)
{
int btn = PvApp::button(p, pvid, (i+1)*32, 0, 30, 30, std::to_string(i+1), STYLE_NORMAL);
pvHide(p, btn);
vecBtn.push_back({btn, i});
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](string) { this->activePage(i, true); });
}
btnNext = PvApp::button(p, pvid, 32, 0, 30, 30, ">", STYLE_NORMAL);
labelInfo = PvApp::label(p, pvid, 2*32, 0, 80, 30, " 共0页", qss::label(14, "rgb(27, 220, 224)"));
pvSetEnabled(p, btnPrev, 0);
pvSetEnabled(p, btnNext, 0);
PvApp::bind(p, PvEvent::BUTTON_EVENT, btnPrev, [=](string e) { this->activePage(--pageIndex, true); });
PvApp::bind(p, PvEvent::BUTTON_EVENT, btnNext, [=](string e) { this->activePage(++pageIndex, true); });
}
void PvPagination::setPage(int index, int count)
{
pageIndex = index;
pageCount = count;
for (int i = 0; i < vecBtn.size(); ++i)
{
auto& btn = vecBtn[i];
auto btnid = btn.first;
int idx = i + 1;
if (idx > pageCount)
{
pvHide(p, btnid);
}
else
{
pvShow(p, btnid);
//if (pageCount > 7)
//{
// if (idx == 4)
// {
// idx = 0;
// }
// else if (idx > 4)
// {
// idx = pageCount - (7 - idx);
// }
//}
//btn.second = idx;
//string text = to_string(idx);
//if (text.empty() || text == "0")
//{
// text = "...";
// pvSetEnabled(p, btnid, false);
//}
////pvMove(p, btnid, x, y);
//pvSetText(p, btnid, text.c_str());
//if (idx == idx)
//{
// this->active_page_button(p, idx, pageIndex);
// pageIndex = idx;
//}
//x += (32);
}
}
int x = (count+1)*32;
pvMove(p, btnNext, x, 0);
pvMove(p, labelInfo, x+=32, 0);
pvSetText(p, labelInfo, ("" + std::to_string(count) + "").c_str());
pvResize(p, pvid, x += 81, 30);
this->activePage(pageIndex);
}
int PvPagination::page()
{
return pageIndex;
};
void PvPagination::activePage(int index, bool invoke)
{
if (pageCount == 0)
{
pageIndex = 0;
return;
}
pageIndex = index;
if (pageIndex < 0){ pageIndex = 0; }
if (pageIndex >= pageCount) { pageIndex = pageCount - 1; }
pvSetEnabled(p, btnPrev, pageIndex != 0);
pvSetEnabled(p, btnNext, (pageIndex != pageCount - 1));
if (btnActive != PV_ID_NUL) { pvSetStyleSheet(p, btnActive, STYLE_NORMAL.c_str()); }
btnActive = vecBtn[pageIndex].first;
pvSetStyleSheet(p, btnActive, STYLE_ACTIVE.c_str());
if (invoke)
{
if (callback) callback(pageIndex);
}
}
void PvPagination::setCallback(std::function<void(int index)> func)
{
callback = func;
}
PvPageTable::PvPageTable(PARAM* p, int parent, int x, int y, int w, int rows, PvTable::Options& opts)
//: PvWidget(p, parent, PvRect(x, y, w, opts.item_height* rows + (opts.show_header ? (opts.header_height) : 0)))
: PvObject(p)
{
int h = opts.row_height* rows + (opts.show_header ? (opts.head_height) : 0);
int pvid_ = PvApp::widget(p, parent, x, y, w, h);
table_ = make_shared<PvTable>(p, pvid_, 0, 0, w, rows, opts);
}
shared_ptr<PvTable> PvPageTable::getTable()
{
return table_;
}