#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> 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 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 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 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() }); 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 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 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 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 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(p, pvid_, 0, 0, w, rows, opts); } shared_ptr PvPageTable::getTable() { return table_; }