2024-05-18 23:53:26 +08:00
|
|
|
#ifndef DTE_H
|
|
|
|
|
#define DTE_H
|
|
|
|
|
#include <qwidget.h>
|
|
|
|
|
#include <qcalendarwidget.h>
|
|
|
|
|
#include <qlayout.h>
|
|
|
|
|
#include <qpushbutton.h>
|
|
|
|
|
#include <qlineedit.h>
|
|
|
|
|
#include <uiModule/uiModule_tableView.h>
|
2024-05-24 18:05:29 +08:00
|
|
|
#include <sqlManager/sqlManager.h>
|
2024-05-18 23:53:26 +08:00
|
|
|
#include <qfile.h>
|
|
|
|
|
#include <qmessagebox.h>
|
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QDateTimeEdit>
|
|
|
|
|
#include <QTime>
|
2024-05-22 16:47:14 +08:00
|
|
|
#include <fileManager.h>
|
|
|
|
|
#include <FrontendBackendBridge.h>
|
|
|
|
|
#include <qlabel.h>
|
2024-05-18 23:53:26 +08:00
|
|
|
#define cacheSqlFileName "sqlite-database-copy.db"
|
|
|
|
|
//#include "xlsxdocument.h"
|
|
|
|
|
class TimeRangeSelectorWidget : public QWidget {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
TimeRangeSelectorWidget(QWidget* parent = nullptr) : QWidget(parent) {
|
|
|
|
|
setupUi();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<int, int>getIntTime()
|
|
|
|
|
{
|
|
|
|
|
int time1 = startTimeEdit->time().hour() * 60 + startTimeEdit->time().minute();
|
|
|
|
|
int time2 = endTimeEdit->time().hour() * 60 + startTimeEdit->time().minute();
|
2024-05-22 16:47:14 +08:00
|
|
|
return { std::min(time1,time2),std::max(time1,time2) };
|
2024-05-18 23:53:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTime getStartTime() const {
|
|
|
|
|
return startTimeEdit->time();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QTime getEndTime() const {
|
|
|
|
|
return endTimeEdit->time();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void setupUi() {
|
|
|
|
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
|
|
|
|
|
|
|
|
|
QLabel* startLabel = new QLabel("开始时间:", this);
|
|
|
|
|
startTimeEdit = new QDateTimeEdit(this);
|
|
|
|
|
startTimeEdit->setDisplayFormat("HH:mm");
|
|
|
|
|
|
|
|
|
|
QLabel* endLabel = new QLabel("结束时间:", this);
|
|
|
|
|
endTimeEdit = new QDateTimeEdit(this);
|
|
|
|
|
endTimeEdit->setDisplayFormat("HH:mm");
|
|
|
|
|
|
|
|
|
|
layout->addWidget(startLabel);
|
|
|
|
|
layout->addWidget(startTimeEdit);
|
|
|
|
|
layout->addWidget(endLabel);
|
|
|
|
|
layout->addWidget(endTimeEdit);
|
|
|
|
|
|
|
|
|
|
setLayout(layout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDateTimeEdit* startTimeEdit;
|
|
|
|
|
QDateTimeEdit* endTimeEdit;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class dumpToExcel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
QWidget* mainWidget;
|
|
|
|
|
sqlTableDatas globalSqlDatas;
|
|
|
|
|
QCalendarWidget* calendarW;
|
|
|
|
|
QPushButton* showMainWidgetBtn;
|
|
|
|
|
QPushButton* dumpToCsvBtn;
|
|
|
|
|
QPushButton* dumpToCsvWithDateLimitBtn;
|
|
|
|
|
QPushButton* openPathSelectBtn;
|
|
|
|
|
QLineEdit* filePathLineEdit;
|
|
|
|
|
TimeRangeSelectorWidget* timeSelector;
|
|
|
|
|
dumpToExcel()
|
|
|
|
|
{
|
|
|
|
|
showMainWidgetBtn = new QPushButton(u8"导出数据为表格");
|
|
|
|
|
showMainWidgetBtn->setStyleSheet("color: white;");
|
|
|
|
|
mainWidget = new QWidget;
|
|
|
|
|
QHBoxLayout* layout = new QHBoxLayout;
|
|
|
|
|
QVBoxLayout* VLayout = new QVBoxLayout;
|
|
|
|
|
mainWidget->setLayout(VLayout);
|
|
|
|
|
VLayout->addLayout(layout);
|
|
|
|
|
QWidget* dateWIdget;
|
|
|
|
|
{
|
|
|
|
|
calendarW = new QCalendarWidget();
|
|
|
|
|
dateWIdget = new QWidget();
|
|
|
|
|
QVBoxLayout* layoutTemp = new QVBoxLayout();
|
|
|
|
|
dateWIdget->setLayout(layoutTemp);
|
|
|
|
|
QLabel* labelTemp = new QLabel(u8"请选择日期");
|
|
|
|
|
labelTemp->setAlignment(Qt::AlignCenter);
|
|
|
|
|
layoutTemp->addWidget(labelTemp);
|
|
|
|
|
layoutTemp->addWidget(calendarW);
|
|
|
|
|
layout->addWidget(dateWIdget);
|
|
|
|
|
}
|
|
|
|
|
QWidget* controlPanel;
|
|
|
|
|
{
|
|
|
|
|
controlPanel = new QWidget();
|
|
|
|
|
|
|
|
|
|
QVBoxLayout* layoutTemp = new QVBoxLayout();
|
|
|
|
|
controlPanel->setLayout(layoutTemp);
|
|
|
|
|
|
|
|
|
|
QLabel* title = new QLabel(u8"导出选项");
|
|
|
|
|
title->setAlignment(Qt::AlignCenter);
|
|
|
|
|
|
|
|
|
|
QLabel* space = new QLabel();
|
|
|
|
|
QLabel* selectFolderLabel = new QLabel(u8"选择导出路径");
|
|
|
|
|
|
|
|
|
|
QHBoxLayout* layoutTemp2 = new QHBoxLayout();
|
|
|
|
|
openPathSelectBtn = new QPushButton("...");
|
|
|
|
|
openPathSelectBtn->setFixedWidth(30);
|
|
|
|
|
|
|
|
|
|
timeSelector = new TimeRangeSelectorWidget();
|
|
|
|
|
|
|
|
|
|
layoutTemp2->addWidget(openPathSelectBtn);
|
|
|
|
|
filePathLineEdit = new QLineEdit("D://");
|
|
|
|
|
layoutTemp2->addWidget(filePathLineEdit);
|
|
|
|
|
|
|
|
|
|
dumpToCsvWithDateLimitBtn = new QPushButton(u8"导出指定时间段数据为csv表格");
|
|
|
|
|
dumpToCsvBtn = new QPushButton(u8"导出数据为CSV表格");
|
|
|
|
|
|
|
|
|
|
layoutTemp->addWidget(title);
|
|
|
|
|
//layoutTemp->addWidget(data);
|
|
|
|
|
layoutTemp->addWidget(space);
|
|
|
|
|
layoutTemp->addWidget(selectFolderLabel);
|
|
|
|
|
layoutTemp->addLayout(layoutTemp2);
|
|
|
|
|
layoutTemp->addWidget(dumpToCsvBtn);
|
|
|
|
|
layoutTemp->addWidget(timeSelector);
|
|
|
|
|
layoutTemp->addWidget(dumpToCsvWithDateLimitBtn);
|
|
|
|
|
layoutTemp->setAlignment(Qt::AlignTop);
|
|
|
|
|
}
|
|
|
|
|
layout->addWidget(controlPanel);
|
|
|
|
|
tV = new tableView();
|
|
|
|
|
VLayout->addWidget(tV->tableWidget);
|
|
|
|
|
QDate selectedDate = calendarW->selectedDate();
|
|
|
|
|
switchDate(selectedDate.toString("yyyy-MM-dd").toStdString(), "D://");
|
|
|
|
|
#pragma region
|
|
|
|
|
QObject::connect(dumpToCsvWithDateLimitBtn, &QPushButton::clicked, [=]() {
|
|
|
|
|
QDate selectedDate = calendarW->selectedDate();
|
|
|
|
|
std::pair<int, int>times = timeSelector->getIntTime();
|
|
|
|
|
saveSqlTableDataToCSV(globalSqlDatas, filePathLineEdit->text() + selectedDate.toString("yyyy-MM-dd") + ".csv",times.first,times.second);
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(openPathSelectBtn, &QPushButton::clicked, [=]() {
|
|
|
|
|
filePathLineEdit->setText(fileManager::openFolderDialog()+"/");
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(dumpToCsvBtn, &QPushButton::clicked, [=]() {
|
|
|
|
|
QDate selectedDate = calendarW->selectedDate();
|
|
|
|
|
saveSqlTableDataToCSV(globalSqlDatas, filePathLineEdit->text() + selectedDate.toString("yyyy-MM-dd") + ".csv");
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(showMainWidgetBtn, &QPushButton::clicked, [=](){
|
|
|
|
|
mainWidget->show();
|
|
|
|
|
mainWidget->raise();
|
|
|
|
|
mainWidget->isActiveWindow();
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(calendarW, &QCalendarWidget::selectionChanged, [=]() {
|
|
|
|
|
QDate selectedDate = calendarW->selectedDate();
|
|
|
|
|
switchDate(selectedDate.toString("yyyy-MM-dd").toStdString(),"D://");
|
|
|
|
|
});
|
|
|
|
|
#pragma endregion 信号连接
|
|
|
|
|
}
|
|
|
|
|
void switchDate(std::string dateStr,std::string excelPath)
|
|
|
|
|
{
|
2024-05-21 23:54:22 +08:00
|
|
|
sqlManager _sqlManager;
|
2024-05-18 23:53:26 +08:00
|
|
|
QString sqlCopiedFilePath;
|
|
|
|
|
#pragma region
|
|
|
|
|
QString path(sqlDefaultDatabasePath);
|
|
|
|
|
QFile sqlFile(path);
|
|
|
|
|
if (sqlFile.open(QIODevice::ReadOnly)) {
|
|
|
|
|
QFileInfo fileInfo(sqlFile);
|
|
|
|
|
sqlCopiedFilePath = fileInfo.absolutePath() + cacheSqlFileName;
|
|
|
|
|
QFile destinationFile(sqlCopiedFilePath);
|
|
|
|
|
if (destinationFile.open(QIODevice::WriteOnly)) {
|
|
|
|
|
QByteArray data = sqlFile.readAll();
|
|
|
|
|
destinationFile.write(data);
|
|
|
|
|
sqlFile.close();
|
|
|
|
|
destinationFile.close();
|
|
|
|
|
qDebug() << "文件复制成功";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qDebug() << "无法打开目标文件";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qDebug() << "无法打开源文件";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#pragma endregion 复制文件
|
|
|
|
|
#pragma region
|
2024-05-21 23:54:22 +08:00
|
|
|
_sqlManager.initPara(sqlCopiedFilePath.toStdString(), false);
|
|
|
|
|
//globalSqlDatas = _sqlManager.selectAllData(dateStr);
|
|
|
|
|
_sqlManager.dbPtr->Select(dateStr, {}, "", "", globalSqlDatas);
|
2024-05-18 23:53:26 +08:00
|
|
|
#pragma endregion sqlite读数据
|
|
|
|
|
#pragma region
|
|
|
|
|
if (globalSqlDatas.rowDatas.size() == 0)
|
|
|
|
|
{
|
|
|
|
|
tV->clearAllData();
|
|
|
|
|
tV->Init({u8"搜索结果"});
|
|
|
|
|
std::vector<QString> strVec({ "找不到数据" });
|
|
|
|
|
tV->addRowDataValue(strVec);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#pragma endregion 检索不到数据的对策
|
|
|
|
|
#pragma region
|
|
|
|
|
tV->clearAllData();
|
|
|
|
|
std::vector<char>avoidVec;
|
|
|
|
|
std::vector<QString>dataNames;
|
|
|
|
|
//设置表头
|
|
|
|
|
for (int i = 0; i < globalSqlDatas.rowDatas[0].size(); i++)
|
|
|
|
|
{
|
|
|
|
|
QString dataName(QString::fromStdString(globalSqlDatas.rowDatas[0][i].key));
|
|
|
|
|
auto it = bridge.back.json.sqlDataTranslate.datas.find(dataName);
|
|
|
|
|
if (it != bridge.back.json.sqlDataTranslate.datas.end())
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
dataNames.push_back(it->second);
|
|
|
|
|
if (it->second.size() == 0)
|
|
|
|
|
avoidVec.push_back(i);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
dataNames.push_back(dataName);
|
|
|
|
|
}
|
|
|
|
|
tV->Init(dataNames);
|
|
|
|
|
//插入数据
|
|
|
|
|
for (auto data : globalSqlDatas.rowDatas)
|
|
|
|
|
{
|
|
|
|
|
std::vector<QString>datas;
|
|
|
|
|
for (auto d : data)
|
|
|
|
|
datas.push_back(QString::fromStdString(d.value));
|
|
|
|
|
tV->addRowDataValue(datas);
|
|
|
|
|
}
|
|
|
|
|
//隐藏特定列
|
|
|
|
|
for(auto index:avoidVec)
|
|
|
|
|
tV->tableWidget->setColumnHidden(index, true);
|
|
|
|
|
|
|
|
|
|
#pragma endregion 将数据插入tableWidget
|
|
|
|
|
remove(sqlCopiedFilePath.toLocal8Bit());
|
|
|
|
|
}
|
|
|
|
|
int StringTimeToInt(const std::string input)
|
|
|
|
|
{
|
|
|
|
|
size_t firstColonPos = input.find(':');
|
|
|
|
|
int timeReturn = 0;
|
|
|
|
|
if (firstColonPos != std::string::npos) {
|
|
|
|
|
std::string time1 = input.substr(0, firstColonPos);
|
|
|
|
|
timeReturn += std::stoi(time1) * 60;
|
|
|
|
|
size_t secondColonPos = input.find(':', firstColonPos + 1);
|
|
|
|
|
if (secondColonPos != std::string::npos) {
|
|
|
|
|
std::string time2 = input.substr(firstColonPos + 1, secondColonPos - firstColonPos - 1);
|
|
|
|
|
timeReturn += std::stoi(time2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return timeReturn;
|
|
|
|
|
}
|
|
|
|
|
void saveSqlTableDataToCSV(const sqlTableDatas& tableData, const QString& fileName, int time1 = 0, int time2 = 0)
|
|
|
|
|
{
|
|
|
|
|
#pragma region
|
|
|
|
|
if (tableData.rowDatas.size() == 0)
|
|
|
|
|
{
|
|
|
|
|
QMessageBox::critical(nullptr, "Error", u8"检索不到数据!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#pragma endregion 没有数据的对策
|
|
|
|
|
QFile csvFile(fileName);
|
|
|
|
|
#pragma region
|
|
|
|
|
if (time1 != 0 || time2 != 0)
|
|
|
|
|
{
|
|
|
|
|
int updateTimeIndex = -1;
|
|
|
|
|
for (int i = 0; i < tableData.rowDatas[0].size(); i++)
|
|
|
|
|
{
|
|
|
|
|
if (tableData.rowDatas[0][i].key == "updateTime")
|
|
|
|
|
updateTimeIndex = i;
|
|
|
|
|
}
|
|
|
|
|
if (!csvFile.exists()) {
|
|
|
|
|
// 如果文件不存在,创建文件
|
|
|
|
|
if (csvFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
|
|
|
QTextStream stream(&csvFile);
|
|
|
|
|
//顶部标题
|
|
|
|
|
for (auto data : tableData.rowDatas[0])
|
|
|
|
|
{
|
|
|
|
|
QString title;
|
|
|
|
|
auto it = bridge.back.json.sqlDataTranslate.datas.find(QString::fromStdString(data.key));
|
|
|
|
|
if (it != bridge.back.json.sqlDataTranslate.datas.end())
|
|
|
|
|
title = it->second;
|
|
|
|
|
else
|
|
|
|
|
title = it->first;
|
|
|
|
|
stream << title << ",";
|
|
|
|
|
}
|
|
|
|
|
stream << "\n";
|
|
|
|
|
for (const auto& rowDatas : tableData.rowDatas)
|
|
|
|
|
{
|
|
|
|
|
int thisTime = StringTimeToInt(rowDatas[updateTimeIndex].value);
|
|
|
|
|
if (thisTime < time1 || thisTime > time2)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (const auto& data : rowDatas)
|
|
|
|
|
stream << QString::fromStdString(data.value) << ",";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
}
|
|
|
|
|
qDebug() << "CSV文件保存成功";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qDebug() << "无法创建CSV文件";
|
|
|
|
|
QMessageBox::critical(nullptr, "Error", u8"没有权限或空间不足!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 如果文件已存在,追加内容
|
|
|
|
|
if (csvFile.open(QIODevice::Append | QIODevice::Text)) {
|
|
|
|
|
QTextStream stream(&csvFile);
|
|
|
|
|
for (const auto& rowDatas : tableData.rowDatas)
|
|
|
|
|
{
|
|
|
|
|
int thisTime = StringTimeToInt(rowDatas[updateTimeIndex].value);
|
|
|
|
|
if (thisTime < time1 || thisTime > time2)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
for (const auto& data : rowDatas)
|
|
|
|
|
stream << QString::fromStdString(data.value) << ",";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
}
|
|
|
|
|
#pragma region
|
|
|
|
|
std::string command = "explorer /select, \"" + fileName.toStdString() + "\"";
|
|
|
|
|
size_t pos = 0;
|
|
|
|
|
while ((pos = command.find("//", pos)) != std::string::npos) {
|
|
|
|
|
command.replace(pos, 2, "\\");
|
|
|
|
|
}
|
|
|
|
|
system(command.c_str());
|
|
|
|
|
#pragma endregion 打开文件夹
|
|
|
|
|
QMessageBox::information(nullptr, "Success", u8"成功!");
|
|
|
|
|
qDebug() << "CSV文件保存成功";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qDebug() << "无法打开CSV文件";
|
|
|
|
|
#pragma region
|
|
|
|
|
std::string command = "explorer /select, \"" + fileName.toStdString() + "\"";
|
|
|
|
|
size_t pos = 0;
|
|
|
|
|
while ((pos = command.find("//", pos)) != std::string::npos) {
|
|
|
|
|
command.replace(pos, 2, "\\");
|
|
|
|
|
}
|
|
|
|
|
system(command.c_str());
|
|
|
|
|
#pragma endregion 打开文件夹
|
|
|
|
|
QMessageBox::critical(nullptr, "Error", u8"文件已存在且无法被写入!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#pragma endregion 需要判断时间的循环
|
|
|
|
|
#pragma region
|
|
|
|
|
if (!csvFile.exists()) {
|
|
|
|
|
// 如果文件不存在,创建文件
|
|
|
|
|
if (csvFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
|
|
|
QTextStream stream(&csvFile);
|
|
|
|
|
//顶部标题
|
|
|
|
|
for (auto data : tableData.rowDatas[0])
|
|
|
|
|
{
|
|
|
|
|
QString title;
|
|
|
|
|
auto it = bridge.back.json.sqlDataTranslate.datas.find(QString::fromStdString(data.key));
|
|
|
|
|
if (it != bridge.back.json.sqlDataTranslate.datas.end())
|
|
|
|
|
title = it->second;
|
|
|
|
|
else
|
|
|
|
|
title = it->first;
|
|
|
|
|
stream << title<<",";
|
|
|
|
|
}
|
|
|
|
|
stream << "\n";
|
|
|
|
|
for (const auto& rowDatas : tableData.rowDatas) {
|
|
|
|
|
for (const auto& data : rowDatas)
|
|
|
|
|
stream << QString::fromStdString(data.value) << ",";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
}
|
|
|
|
|
qDebug() << "CSV文件保存成功";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qDebug() << "无法创建CSV文件";
|
|
|
|
|
QMessageBox::critical(nullptr, "Error", u8"没有权限或空间不足!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 如果文件已存在,追加内容
|
|
|
|
|
if (csvFile.open(QIODevice::Append | QIODevice::Text)) {
|
|
|
|
|
QTextStream stream(&csvFile);
|
|
|
|
|
for (const auto& rowDatas : tableData.rowDatas) {
|
|
|
|
|
for (const auto& data : rowDatas)
|
|
|
|
|
stream << QString::fromStdString(data.value) << ",";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
}
|
|
|
|
|
#pragma region
|
|
|
|
|
std::string command = "explorer /select, \"" + fileName.toStdString() + "\"";
|
|
|
|
|
size_t pos = 0;
|
|
|
|
|
while ((pos = command.find("//", pos)) != std::string::npos) {
|
|
|
|
|
command.replace(pos, 2, "\\");
|
|
|
|
|
}
|
|
|
|
|
system(command.c_str());
|
|
|
|
|
#pragma endregion 打开文件夹
|
|
|
|
|
QMessageBox::information(nullptr, "Success", u8"成功!");
|
|
|
|
|
qDebug() << "CSV文件保存成功";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
qDebug() << "无法打开CSV文件";
|
|
|
|
|
#pragma region
|
|
|
|
|
std::string command = "explorer /select, \"" + fileName.toStdString() + "\"";
|
|
|
|
|
size_t pos = 0;
|
|
|
|
|
while ((pos = command.find("//", pos)) != std::string::npos) {
|
|
|
|
|
command.replace(pos, 2, "\\");
|
|
|
|
|
}
|
|
|
|
|
system(command.c_str());
|
|
|
|
|
#pragma endregion 打开文件夹
|
|
|
|
|
QMessageBox::critical(nullptr, "Error", u8"文件已存在且无法被写入!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#pragma endregion 不需要判断时间的循环
|
|
|
|
|
}
|
|
|
|
|
public slots:
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
tableView* tV;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
#endif
|