You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

490 lines
18 KiB
C++

#include "FITKTableWidget.h"
#include <QKeyEvent>
#include <QLineEdit>
#include <QApplication>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <QItemDelegate>
#include "TableWidgetFileReadFileDialog.h"
namespace Comp
{
class FITKTableWidgetLineEdit : public QLineEdit {
public:
FITKTableWidgetLineEdit(QWidget* parent = nullptr) : QLineEdit(parent) {
setContextMenuPolicy(Qt::NoContextMenu);
setStyleSheet("border{none;background-color: #CDCDCD;color: #F2F2F2;}");
};
~FITKTableWidgetLineEdit() = default;
protected:
/**
* @brief
* @param event
* @author YanZhiHui (chanyuantiandao@126.com)
* @date 2024-04-22
*/
virtual void keyPressEvent(QKeyEvent *event) override {
if ((event->modifiers()& Qt::ControlModifier) != 0 && (event->key() == Qt::Key_X || event->key() == Qt::Key_C || event->key() == Qt::Key_V)) {
event->ignore();
//QApplication::postEvent(this->parent(), event);
}
else {
QLineEdit::keyPressEvent(event);
}
}
/**
* @brief
* @param event
* @author YanZhiHui (chanyuantiandao@126.com)
* @date 2024-04-22
*/
virtual void keyReleaseEvent(QKeyEvent *event) override {
if ((event->modifiers()& Qt::ControlModifier) != 0 && (event->key() == Qt::Key_X || event->key() == Qt::Key_C || event->key() == Qt::Key_V)) {
event->ignore();
//QApplication::postEvent(this->parent(), event);
}
else {
QLineEdit::keyReleaseEvent(event);
}
}
};
class TableWidgetItemDelegate : public QItemDelegate {
protected:
// 创建编辑器
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
// 创建自己需要的控件进行返回
QLineEdit *editor = new FITKTableWidgetLineEdit(parent);
return editor;
}
// 设置编辑器数据
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const override {
// 将参数editor转换为对应创建的控件再进行数据初始设置就行
QLineEdit *cob = static_cast<QLineEdit *>(editor);
QString value = index.model()->data(index, Qt::EditRole).toString();
cob->setText(value);
}
// 更新编辑器集合属性
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
// 将编辑器设置为矩形属性
editor->setGeometry(option.rect);
}
// 设置模型数据
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
{
QLineEdit *comboBox = static_cast<FITKTableWidgetLineEdit *>(editor); // 类型转换
// 模型(单元格)显示的数据
model->setData(index, comboBox->text());
}
};
/**
* @brief
* @param parent
* @author YanZhiHui (chanyuantiandao@126.com)
* @date 2024-04-22
*/
FITKTableWidget::FITKTableWidget(QWidget *parent) : QTableWidget(parent)
{
setEditTriggers(QAbstractItemView::AllEditTriggers);
_clipboard = QApplication::clipboard();
setItemDelegate(new TableWidgetItemDelegate);
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customContextMenuRequestedSlot(QPoint)));
}
/**
* @brief
* @author YanZhiHui (chanyuantiandao@126.com)
* @date 2024-04-22
*/
FITKTableWidget::~FITKTableWidget()
{
}
/**
* @brief
* @param b
* @author YanZhiHui (chanyuantiandao@126.com)
* @date 2024-04-22
*/
void FITKTableWidget::setAppendLineByEnterPressed(bool b)
{
_isAppendLineByEnterPressed = b;
}
void FITKTableWidget::setIsAloneRow(bool isAlone)
{
_isAloneRow = isAlone;
if (_isAloneRow) {
_isAppendLineByEnterPressed = false;
}
else {
_isAppendLineByEnterPressed = true;
}
}
void FITKTableWidget::addTableRowAndItem(int rowNum)
{
int columnNum = columnCount();
insertRow(rowNum);
for (int i = 0; i < columnNum; ++i)
{
setItem(rowNum, i, new QTableWidgetItem);
}
}
/**
* @brief
* @param[in]
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::customContextMenuRequestedSlot(QPoint)
{
delete _tableWidgetContextMenu;
_tableWidgetContextMenu = new QMenu();
QAction* cutAction = new QAction(_tableWidgetContextMenu);
cutAction->setText(tr("Cut"));
cutAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X));
connect(cutAction, SIGNAL(triggered()), this, SLOT(cutActionSlot()));
_tableWidgetContextMenu->addAction(cutAction);
QAction* copyAction = new QAction(_tableWidgetContextMenu);
copyAction->setText(tr("Copy"));
copyAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
connect(copyAction, SIGNAL(triggered()), this, SLOT(copyActionSlot()));
_tableWidgetContextMenu->addAction(copyAction);
QAction* pasteAction = new QAction(_tableWidgetContextMenu);
pasteAction->setText(tr("Paste"));
pasteAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_V));
connect(pasteAction, SIGNAL(triggered()), this, SLOT(pasteActionSlot()));
_tableWidgetContextMenu->addAction(pasteAction);
_tableWidgetContextMenu->addSeparator();
if (!_isAloneRow) {
QAction* insertBeforeAction = new QAction(_tableWidgetContextMenu);
insertBeforeAction->setText(tr("Insert Row Before"));
connect(insertBeforeAction, SIGNAL(triggered()), this, SLOT(insertBeforeActionSlot()));
_tableWidgetContextMenu->addAction(insertBeforeAction);
QAction* insertAfterAction = new QAction(_tableWidgetContextMenu);
insertAfterAction->setText(tr("Insert Row After"));
connect(insertAfterAction, SIGNAL(triggered()), this, SLOT(insertAfterActionSlot()));
_tableWidgetContextMenu->addAction(insertAfterAction);
QAction* deleteRowAction = new QAction(_tableWidgetContextMenu);
deleteRowAction->setText(tr("Delete Rows"));
connect(deleteRowAction, SIGNAL(triggered()), this, SLOT(deleteRowActionSlot()));
_tableWidgetContextMenu->addAction(deleteRowAction);
_tableWidgetContextMenu->addSeparator();
}
QAction* clearContentsAction = new QAction(_tableWidgetContextMenu);
clearContentsAction->setText(tr("Clear Contents"));
connect(clearContentsAction, SIGNAL(triggered()), this, SLOT(clearContentsActionSlot()));
_tableWidgetContextMenu->addAction(clearContentsAction);
QAction* clearTableAction = new QAction(_tableWidgetContextMenu);
clearTableAction->setText(tr("Clear Table"));
connect(clearTableAction, SIGNAL(triggered()), this, SLOT(clearTableActionSlot()));
_tableWidgetContextMenu->addAction(clearTableAction);
_tableWidgetContextMenu->addSeparator();
QAction* readFileAction = new QAction(_tableWidgetContextMenu);
readFileAction->setText(tr("Read from file..."));
readFileAction->setIcon(QIcon(":/icons/icoR_fileOpen.xpm"));
connect(readFileAction, SIGNAL(triggered()), this, SLOT(readFileActionSlot()));
_tableWidgetContextMenu->addAction(readFileAction);
_tableWidgetContextMenu->addSeparator();
_tableWidgetContextMenu->exec(QCursor::pos());
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::cutActionSlot()
{
QTableWidgetItem* tableWidgetItem = currentItem();
if (tableWidgetItem == nullptr) return;
_clipboard->setText(tableWidgetItem->text());
tableWidgetItem->setText("");
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::copyActionSlot()
{
QTableWidgetItem* tableWidgetItem = currentItem();
if (tableWidgetItem == nullptr) return;
_clipboard->setText(tableWidgetItem->text());
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::pasteActionSlot()
{
QTableWidgetItem* tableWidgetItem = currentItem();
if (tableWidgetItem == nullptr) return;
auto txt = _clipboard->text();
if (txt.contains('\t')) {
QStringList rowTxts = txt.split('\n');
int currentRow = tableWidgetItem->row();
int currentCol = tableWidgetItem->column();
int totalCol = columnCount();
for (int i = 0; i < rowTxts.size(); ++i) {
auto row = currentRow + i;
if (row >= rowCount()) {
addTableRowAndItem(row);
}
auto colTxts = rowTxts.at(i).split('\t');
for (int j = 0; j < colTxts.size(); ++j) {
auto col = currentCol + j;
if (col >= totalCol) break;
auto it = item(row, col);
if (it == nullptr) break;
it->setText(colTxts.at(j));
}
}
}
else {
tableWidgetItem->setText(txt);
}
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::insertBeforeActionSlot()
{
addTableRowAndItem(currentRow());
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::insertAfterActionSlot()
{
addTableRowAndItem(currentRow() + 1);
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::deleteRowActionSlot()
{
if (rowCount() <= 1)
{
QTableWidgetItem* it = item(currentRow(), 0);
if (it != nullptr) it->setText("");
}
else
{
removeRow(currentRow());
}
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::clearContentsActionSlot()
{
QTableWidgetItem* tableWidgetItem = currentItem();
if (tableWidgetItem == nullptr) return;
tableWidgetItem->setText("");
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::clearTableActionSlot()
{
int rowNum = rowCount();
for (int i = 0; i < 2; ++i)
{
for (int j = 0; j < rowNum; ++j)
{
QTableWidgetItem* tableWidgetItem = item(j, i);
if (tableWidgetItem == nullptr) continue;
tableWidgetItem->setText("");
}
}
}
/**
* @brief
* @author yanzhihui (chanyuantiandao@126.com)
* @date 2023-07-26
*/
void FITKTableWidget::readFileActionSlot()
{
// 获取当前选择的表格,作为填充数据的开始位置
QModelIndex index = currentIndex();
int totalRow = rowCount();
int totalColumn = columnCount();
if (!index.isValid()) return;
// 打开文件选择对话框
auto amplitudeReadFileDialog = new TableWidgetFileReadFileDialog({ totalRow, totalColumn, index.row(), index.column() }, nullptr);
if (amplitudeReadFileDialog->exec() != QDialog::Accepted) return;
// 从打开文件对话框中获取最新数据
QString filePath = amplitudeReadFileDialog->getFile();
int startRow = amplitudeReadFileDialog->getStartRow();
int startColumn = amplitudeReadFileDialog->getStartColumn();
// 文件是否可以正常打开
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::critical(this, tr("Error Information"), QString(tr("Error to read file: %1")).arg(filePath));
return;
}
char buf[1024];
qint64 lineLength = file.readLine(buf, sizeof(buf));
// 读取文本行数
int currentFileLine = 1;
// 当前行的总列数
int columnNum = 0;
QString errMessage{};
// 序列号转换索引号
int i = startRow - 1;
while (lineLength != -1)
{
// 如果最大索引号超过了当前索引值,则插入新行
if (totalRow - 1 < i)
{
addTableRowAndItem(i);
}
// 用正则匹配数据
QStringList resultList = QString(buf).split(QRegExp("[\\t|,|\\s]"), QString::SkipEmptyParts);
columnNum = resultList.size();
// 文件中的数据列是否超出表格有效列
if (errMessage.isEmpty() && columnNum > totalColumn - startColumn + 1)
{
errMessage = QString(tr("The data read from the file were truncated.\nRow %1 int the file contains %2 columns of data, which cannot fit starting in the table column %3."))
.arg(currentFileLine)
.arg(resultList.size())
.arg(startColumn);
}
if (startColumn == 1 && columnNum > 0)
{
setItem(i, 0, new QTableWidgetItem(resultList.at(0)));
if (columnNum > 1)
{
setItem(i, 1, new QTableWidgetItem(resultList.at(1)));
}
}
else if (startColumn == 2 && columnNum > 0)
{
setItem(i, 1, new QTableWidgetItem(resultList.at(0)));
}
++i;
lineLength = file.readLine(buf, sizeof(buf));
++currentFileLine;
}
if (!errMessage.isEmpty())
{
QMessageBox::warning(this, tr("Warning Information"), errMessage);
}
}
/*
*
*
* :
* event - QKeyEvent*
*
* :
* EnterReturn
*/
void FITKTableWidget::keyPressEvent(QKeyEvent *event)
{
// 获取按键值只处理enter和return键
int key = event->key();
if (key == Qt::Key_Enter && key == Qt::Key_Return)
{
// 获取当前选中单元格的索引
QModelIndex index = currentIndex();
if (!index.isValid())
return;
int row = index.row();
int column = index.column();
// 如果当前列不是最后一列,则移动到下一列
if (column < columnCount() - 1)
{
int nextVisiablecolumn = column + 1;
while (nextVisiablecolumn < columnCount())
{
if (!isColumnHidden(nextVisiablecolumn))
{
setCurrentCell(row, nextVisiablecolumn);
edit(index.siblingAtColumn(nextVisiablecolumn));
break;
}
++nextVisiablecolumn;
}
}
// 如果当前行为非最后一行,则移动到下一行
else if (row < rowCount() - 1)
{
setCurrentCell(row + 1, 0);
edit(index.sibling(row + 1, 0));
}
// 如果配置了按下Enter键添加新行则添加新行
else if (_isAppendLineByEnterPressed)
{
insertRow(rowCount());
for (int i = colorCount() - 1; i >= 0; --i)
{
setItem(rowCount(), i, new QTableWidgetItem(""));
}
setCurrentCell(row + 1, 0);
edit(index.sibling(row + 1, 0));
}
}
else if ((event->modifiers()& Qt::ControlModifier) != 0 && key == Qt::Key_X) {
cutActionSlot();
}
else if ((event->modifiers()& Qt::ControlModifier) != 0 && key == Qt::Key_C) {
copyActionSlot();
}
else if ((event->modifiers()& Qt::ControlModifier) != 0 && key == Qt::Key_V) {
pasteActionSlot();
}
else {
QTableWidget::keyPressEvent(event);
}
}
/**
* @brief
* @author YanZhiHui (chanyuantiandao@126.com)
* @date 2024-04-22
*/
void FITKTableWidget::keyReleaseEvent(QKeyEvent *event)
{
QTableWidget::keyReleaseEvent(event);
}
bool FITKTableWidget::edit(const QModelIndex & index, EditTrigger trigger, QEvent * event)
{
auto result = QTableWidget::edit(index, trigger, event);
QList<QLineEdit*> lineEdits = findChildren<QLineEdit*>();
for (int i = 0; i < lineEdits.size(); i++)
{
// 重写方法,屏蔽编辑框的右键菜单
QLineEdit* target = lineEdits.at(i);
target->setContextMenuPolicy(Qt::NoContextMenu);
}
return result;
}
} // namespace GUI