热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

跟我一起学QT3:电子表格的制作

为什么80%的码农都做不了架构师?0.源代码下载(qt5)https:github.comleichaojianqttreemasterspreadsheet1

为什么80%的码农都做不了架构师?>>>   hot3.png

0. 源代码下载(qt5)

https://github.com/leichaojian/qt/tree/master/spreadsheet

1. 子类化QMainWindow

#include #include "finddialog.h"
#include "gotocelldialog.h"
#include "mainwindow.h"
#include "sortdialog.h"
#include "spreadsheet.h"MainWindow::MainWindow()
{spreadsheet = new Spreadsheet;//设置为中央窗口部件setCentralWidget(spreadsheet);createActions();createMenus();createContextMenu();createToolBars();createStatusBar();readSettings();findDialog = 0;//显示窗口左上角的图标setWindowIcon(QIcon(":/images/icon.png"));setCurrentFile("");
}//closeEvent事件:中途拦截close信号,用来确定是否要关闭窗口
void MainWindow::closeEvent(QCloseEvent *event)
{if (okToContinue()) {//保存设置,接收此事件writeSettings();event->accept();} else {//忽略此事件event->ignore();}
}void MainWindow::newFile()
{//说明保存成功if (okToContinue()) {//保存成功后,清空界面,设置标题spreadsheet->clear();setCurrentFile("");}
}void MainWindow::open()
{if (okToContinue()) {//创建文件对话框(getOpenFileName)并且选择过滤后的文件名(fileName)//"Spreadsheet files (*.sp)"中Spreadsheet files为描述文字,而*.sp为过滤条件QString fileName = QFileDialog::getOpenFileName(this,tr("Open Spreadsheet"), ".",tr("Spreadsheet files (*.sp)"));//如果文件不为空,则加载文件if (!fileName.isEmpty())loadFile(fileName);}
}bool MainWindow::save()
{//是当前文件而非新建文件if (curFile.isEmpty()) {return saveAs();} else {return saveFile(curFile);}
}bool MainWindow::saveAs()
{//getSaveFileName:得到保存的文件,如果文件存在,则会提示是否要覆盖QString fileName = QFileDialog::getSaveFileName(this,tr("Save Spreadsheet"), ".",tr("Spreadsheet files (*.sp)"));if (fileName.isEmpty())return false;return saveFile(fileName);
}void MainWindow::find()
{if (!findDialog) {findDialog = new FindDialog(this);connect(findDialog, SIGNAL(findNext(const QString &,Qt::CaseSensitivity)),spreadsheet, SLOT(findNext(const QString &,Qt::CaseSensitivity)));connect(findDialog, SIGNAL(findPrevious(const QString &,Qt::CaseSensitivity)),spreadsheet, SLOT(findPrevious(const QString &,Qt::CaseSensitivity)));}//非模态对话框--->show()findDialog->show();//raise()使窗口成为顶层窗口findDialog->raise();//activateWindow()激活顶层窗口findDialog->activateWindow();
}void MainWindow::goToCell()
{GoToCellDialog dialog(this);//exec为模态对话框(这里不同于show的非模态对话框)if (dialog.exec()) {QString str = dialog.lineEdit->text().toUpper();spreadsheet->setCurrentCell(str.mid(1).toInt() - 1,str[0].unicode() - 'A');}
}//对局部区域进行排序
void MainWindow::sort()
{SortDialog dialog(this);QTableWidgetSelectionRange range = spreadsheet->selectedRange();//选定的列('A' + 1, 'A' + 4 ==> 'B','E')dialog.setColumnRange('A' + range.leftColumn(),'A' + range.rightColumn());if (dialog.exec()) {SpreadsheetCompare compare;compare.keys[0] =dialog.primaryColumnCombo->currentIndex();compare.keys[1] =dialog.secondaryColumnCombo->currentIndex() - 1;compare.keys[2] =dialog.tertiaryColumnCombo->currentIndex() - 1;compare.ascending[0] =(dialog.primaryOrderCombo->currentIndex() == 0);compare.ascending[1] =(dialog.secondaryOrderCombo->currentIndex() == 0);compare.ascending[2] =(dialog.tertiaryOrderCombo->currentIndex() == 0);spreadsheet->sort(compare);}
}void MainWindow::about()
{QMessageBox::about(this, tr("About Spreadsheet"),tr("

Spreadsheet 1.1

""

Copyright © 2008 Software Inc.""

Spreadsheet is a small application that ""demonstrates QAction, QMainWindow, QMenuBar, ""QStatusBar, QTableWidget, QToolBar, and many other ""Qt classes."));
}void MainWindow::openRecentFile()
{if (okToContinue()) {//qobject_cast动态类型转换--->这里sender()的含义是什么?QAction *action = qobject_cast(sender());//通过action->data()得到文件名if (action)loadFile(action->data().toString());}
}void MainWindow::updateStatusBar()
{locationLabel->setText(spreadsheet->currentLocation());formulaLabel->setText(spreadsheet->currentFormula());
}void MainWindow::spreadsheetModified()
{setWindowModified(true);updateStatusBar();
}//一个动作(action)就是一个可以添加到任意数量的菜单和工具栏上的项
void MainWindow::createActions()
{//New动作newAction = new QAction(tr("&New"), this);newAction->setIcon(QIcon(":/images/new.png"));newAction->setShortcut(QKeySequence::New); //快捷键newAction->setStatusTip(tr("Create a new spreadsheet file"));connect(newAction, SIGNAL(triggered()), this, SLOT(newFile()));//Open动作openAction = new QAction(tr("&Open..."), this);openAction->setIcon(QIcon(":/images/open.png"));openAction->setShortcut(QKeySequence::Open);openAction->setStatusTip(tr("Open an existing spreadsheet file"));connect(openAction, SIGNAL(triggered()), this, SLOT(open()));//Save动作saveAction = new QAction(tr("&Save"), this);saveAction->setIcon(QIcon(":/images/save.png"));saveAction->setShortcut(QKeySequence::Save);saveAction->setStatusTip(tr("Save the spreadsheet to disk"));connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));//Save as动作saveAsAction = new QAction(tr("Save &As..."), this);saveAsAction->setStatusTip(tr("Save the spreadsheet under a new ""name"));connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));//最近打开文件动作for (int i = 0; i setVisible(false);connect(recentFileActions[i], SIGNAL(triggered()),this, SLOT(openRecentFile()));}//Exit动作exitAction = new QAction(tr("E&xit"), this);exitAction->setShortcut(tr("Ctrl+Q"));exitAction->setStatusTip(tr("Exit the application"));//这里close由Qt提供connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));//Cut动作cutAction = new QAction(tr("Cu&t"), this);cutAction->setIcon(QIcon(":/images/cut.png"));cutAction->setShortcut(QKeySequence::Cut);cutAction->setStatusTip(tr("Cut the current selection's contents ""to the clipboard"));connect(cutAction, SIGNAL(triggered()), spreadsheet, SLOT(cut()));//Copy动作copyAction = new QAction(tr("&Copy"), this);copyAction->setIcon(QIcon(":/images/copy.png"));copyAction->setShortcut(QKeySequence::Copy);copyAction->setStatusTip(tr("Copy the current selection's contents ""to the clipboard"));connect(copyAction, SIGNAL(triggered()), spreadsheet, SLOT(copy()));//Paste动作pasteAction = new QAction(tr("&Paste"), this);pasteAction->setIcon(QIcon(":/images/paste.png"));pasteAction->setShortcut(QKeySequence::Paste);pasteAction->setStatusTip(tr("Paste the clipboard's contents into ""the current selection"));connect(pasteAction, SIGNAL(triggered()),spreadsheet, SLOT(paste()));//Delete动作deleteAction = new QAction(tr("&Delete"), this);deleteAction->setShortcut(QKeySequence::Delete);deleteAction->setStatusTip(tr("Delete the current selection's ""contents"));connect(deleteAction, SIGNAL(triggered()),spreadsheet, SLOT(del()));selectRowAction = new QAction(tr("&Row"), this);selectRowAction->setStatusTip(tr("Select all the cells in the ""current row"));connect(selectRowAction, SIGNAL(triggered()),spreadsheet, SLOT(selectCurrentRow()));selectColumnAction = new QAction(tr("&Column"), this);selectColumnAction->setStatusTip(tr("Select all the cells in the ""current column"));connect(selectColumnAction, SIGNAL(triggered()),spreadsheet, SLOT(selectCurrentColumn()));selectAllAction = new QAction(tr("&All"), this);selectAllAction->setShortcut(QKeySequence::SelectAll);selectAllAction->setStatusTip(tr("Select all the cells in the ""spreadsheet"));//selectAll由父类QTableWidget实现connect(selectAllAction, SIGNAL(triggered()),spreadsheet, SLOT(selectAll()));findAction = new QAction(tr("&Find..."), this);findAction->setIcon(QIcon(":/images/find.png"));findAction->setShortcut(QKeySequence::Find);findAction->setStatusTip(tr("Find a matching cell"));connect(findAction, SIGNAL(triggered()), this, SLOT(find()));goToCellAction = new QAction(tr("&Go to Cell..."), this);goToCellAction->setIcon(QIcon(":/images/gotocell.png"));goToCellAction->setShortcut(tr("Ctrl+G"));goToCellAction->setStatusTip(tr("Go to the specified cell"));connect(goToCellAction, SIGNAL(triggered()),this, SLOT(goToCell()));recalculateAction = new QAction(tr("&Recalculate"), this);recalculateAction->setShortcut(tr("F9"));recalculateAction->setStatusTip(tr("Recalculate all the ""spreadsheet's formulas"));connect(recalculateAction, SIGNAL(triggered()),spreadsheet, SLOT(recalculate()));sortAction = new QAction(tr("&Sort..."), this);sortAction->setStatusTip(tr("Sort the selected cells or all the ""cells"));connect(sortAction, SIGNAL(triggered()), this, SLOT(sort()));showGridAction = new QAction(tr("&Show Grid"), this);showGridAction->setCheckable(true); //复选动作showGridAction->setChecked(spreadsheet->showGrid());showGridAction->setStatusTip(tr("Show or hide the spreadsheet's ""grid"));connect(showGridAction, SIGNAL(toggled(bool)),spreadsheet, SLOT(setShowGrid(bool)));
#if QT_VERSION <0x040102// workaround for a QTableWidget bug in Qt 4.1.1connect(showGridAction, SIGNAL(toggled(bool)),spreadsheet->viewport(), SLOT(update()));
#endifautoRecalcAction &#61; new QAction(tr("&Auto-Recalculate"), this);autoRecalcAction->setCheckable(true);autoRecalcAction->setChecked(spreadsheet->autoRecalculate());autoRecalcAction->setStatusTip(tr("Switch auto-recalculation on or ""off"));connect(autoRecalcAction, SIGNAL(toggled(bool)),spreadsheet, SLOT(setAutoRecalculate(bool)));aboutAction &#61; new QAction(tr("&About"), this);aboutAction->setStatusTip(tr("Show the application&#39;s About box"));connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));aboutQtAction &#61; new QAction(tr("About &Qt"), this);aboutQtAction->setStatusTip(tr("Show the Qt library&#39;s About box"));connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}void MainWindow::createMenus()
{//addMenu用于创建一个窗口部件fileMenu &#61; menuBar()->addMenu(tr("&File"));fileMenu->addAction(newAction);fileMenu->addAction(openAction);fileMenu->addAction(saveAction);fileMenu->addAction(saveAsAction);separatorAction &#61; fileMenu->addSeparator(); //分隔符//最近打开的文件for (int i &#61; 0; i addAction(recentFileActions[i]);fileMenu->addSeparator();fileMenu->addAction(exitAction);editMenu &#61; menuBar()->addMenu(tr("&Edit"));editMenu->addAction(cutAction);editMenu->addAction(copyAction);editMenu->addAction(pasteAction);editMenu->addAction(deleteAction);//Select是Edit菜单下的一个子菜单selectSubMenu &#61; editMenu->addMenu(tr("&Select"));selectSubMenu->addAction(selectRowAction);selectSubMenu->addAction(selectColumnAction);selectSubMenu->addAction(selectAllAction);editMenu->addSeparator();editMenu->addAction(findAction);editMenu->addAction(goToCellAction);toolsMenu &#61; menuBar()->addMenu(tr("&Tools"));toolsMenu->addAction(recalculateAction);toolsMenu->addAction(sortAction);optionsMenu &#61; menuBar()->addMenu(tr("&Options"));optionsMenu->addAction(showGridAction);optionsMenu->addAction(autoRecalcAction);//菜单栏中增加间隔menuBar()->addSeparator();helpMenu &#61; menuBar()->addMenu(tr("&Help"));helpMenu->addAction(aboutAction);helpMenu->addAction(aboutQtAction);
}/**************************
任何Qt窗口部件都可以有一个与之相关联的QAction列表。要为该应用程序提供一个上下文菜单&#xff0c;可以将
所需要的动作添加到Spreadsheet窗口部件中&#xff0c;并且将那个窗口部件的上下文菜单策略(context menu policy)
设置为一个显示这些动作的上下文菜单。当用户在一个窗口部件上单击鼠标右键&#xff0c;或者是在键盘上按下一个与平台相关的按键时&#xff0c;就可以激活这些上下文菜单。
*****************************/
void MainWindow::createContextMenu()
{//将菜单栏cutAction&#xff0c;copyAction和pasteAction关联到spreadsheet中spreadsheet->addAction(cutAction);spreadsheet->addAction(copyAction);spreadsheet->addAction(pasteAction);spreadsheet->setContextMenuPolicy(Qt::ActionsContextMenu);
}void MainWindow::createToolBars()
{fileToolBar &#61; addToolBar(tr("&File"));fileToolBar->addAction(newAction);fileToolBar->addAction(openAction);fileToolBar->addAction(saveAction);editToolBar &#61; addToolBar(tr("&Edit"));editToolBar->addAction(cutAction);editToolBar->addAction(copyAction);editToolBar->addAction(pasteAction);editToolBar->addSeparator();editToolBar->addAction(findAction);editToolBar->addAction(goToCellAction);
}void MainWindow::createStatusBar()
{locationLabel &#61; new QLabel(" W999 ");//默认情况下是向左对齐并且垂直居中locationLabel->setAlignment(Qt::AlignHCenter);locationLabel->setMinimumSize(locationLabel->sizeHint());formulaLabel &#61; new QLabel;//设定缩进大小formulaLabel->setIndent(3);statusBar()->addWidget(locationLabel);//1为伸展因子&#xff0c;防止状态显示过于靠近statusBar()->addWidget(formulaLabel, 1);connect(spreadsheet, SIGNAL(currentCellChanged(int, int, int, int)),this, SLOT(updateStatusBar()));//修改(modified)后更新状态栏connect(spreadsheet, SIGNAL(modified()),this, SLOT(spreadsheetModified()));//更新状态栏updateStatusBar();
}//读取配置---通常为键值方式
void MainWindow::readSettings()
{QSettings settings("Software Inc.", "Spreadsheet");restoreGeometry(settings.value("geometry").toByteArray());recentFiles &#61; settings.value("recentFiles").toStringList();updateRecentFileActions();bool showGrid &#61; settings.value("showGrid", true).toBool();showGridAction->setChecked(showGrid);bool autoRecalc &#61; settings.value("autoRecalc", true).toBool();autoRecalcAction->setChecked(autoRecalc);
}void MainWindow::writeSettings()
{QSettings settings("Software Inc.", "Spreadsheet");settings.setValue("geometry", saveGeometry());settings.setValue("recentFiles", recentFiles);settings.setValue("showGrid", showGridAction->isChecked());settings.setValue("autoRecalc", autoRecalcAction->isChecked());
}bool MainWindow::okToContinue()
{if (isWindowModified()) {int r &#61; QMessageBox::warning(this, tr("Spreadsheet"),tr("The document has been modified.\n""Do you want to save your changes?"),QMessageBox::Yes | QMessageBox::No| QMessageBox::Cancel);if (r &#61;&#61; QMessageBox::Yes) {return save();} else if (r &#61;&#61; QMessageBox::Cancel) {return false;}}return true;
}bool MainWindow::loadFile(const QString &fileName)
{//readFile从磁盘中读取文件并显示出来if (!spreadsheet->readFile(fileName)) {statusBar()->showMessage(tr("Loading canceled"), 2000);return false;}setCurrentFile(fileName);statusBar()->showMessage(tr("File loaded"), 2000);return true;
}bool MainWindow::saveFile(const QString &fileName)
{if (!spreadsheet->writeFile(fileName)) {statusBar()->showMessage(tr("Saving canceled"), 2000);return false;}setCurrentFile(fileName);statusBar()->showMessage(tr("File saved"), 2000);return true;
}void MainWindow::setCurrentFile(const QString &fileName)
{curFile &#61; fileName;setWindowModified(false);QString shownName &#61; tr("Untitled");if (!curFile.isEmpty()) {//strippedName:移除文件名中的路径字符shownName &#61; strippedName(curFile);//从最近打开文件中移除当前文件recentFiles.removeAll(curFile);//将当前文件加入最近打开文件的开头recentFiles.prepend(curFile);//更新最近打开文件updateRecentFileActions();}//显示标题(*代表已修改而未保存)setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Spreadsheet")));
}void MainWindow::updateRecentFileActions()
{QMutableStringListIterator i(recentFiles);//用来移除任何不存在的文件while (i.hasNext()) {if (!QFile::exists(i.next()))i.remove();}for (int j &#61; 0; j setText(text);recentFileActions[j]->setData(recentFiles[j]);recentFileActions[j]->setVisible(true);} else {recentFileActions[j]->setVisible(false);}}separatorAction->setVisible(!recentFiles.isEmpty());
}QString MainWindow::strippedName(const QString &fullFileName)
{return QFileInfo(fullFileName).fileName();
}
2.  子类化QTableWidget


#include #include "cell.h"
#include "spreadsheet.h"Spreadsheet::Spreadsheet(QWidget *parent): QTableWidget(parent)
{autoRecalc &#61; true;//将item的原型设置为Cell类型setItemPrototype(new Cell);//选择模式为&#xff1a;ContiguousSelection&#xff0c;则允许单矩形选择框方法setSelectionMode(ContiguousSelection);connect(this, SIGNAL(itemChanged(QTableWidgetItem *)),this, SLOT(somethingChanged()));//调用clear()来重新调整表格的尺寸大小并且设置列标题clear();
}//得到当前位置
QString Spreadsheet::currentLocation() const
{return QChar(&#39;A&#39; &#43; currentColumn())&#43; QString::number(currentRow() &#43; 1);
}//返回当前单元格的公式
QString Spreadsheet::currentFormula() const
{return formula(currentRow(), currentColumn());
}//自定义selectedRange(),用于返回选中的表格范围
QTableWidgetSelectionRange Spreadsheet::selectedRange() const
{QList ranges &#61; selectedRanges();if (ranges.isEmpty())return QTableWidgetSelectionRange();return ranges.first();
}void Spreadsheet::clear()
{//调整表格为0行0列&#xff0c;做到清空所有的表格内容setRowCount(0);setColumnCount(0);//重新设置表格的大小为RowCount*ColumnCountsetRowCount(RowCount);setColumnCount(ColumnCount);for (int i &#61; 0; i setText(QString(QChar(&#39;A&#39; &#43; i)));//设置水平标题栏列i到item中setHorizontalHeaderItem(i, item);}setCurrentCell(0, 0);
}//从二进制文件中读取数据并写入表格中
bool Spreadsheet::readFile(const QString &fileName)
{QFile file(fileName);if (!file.open(QIODevice::ReadOnly)) {QMessageBox::warning(this, tr("Spreadsheet"),tr("Cannot read file %1:\n%2.").arg(file.fileName()).arg(file.errorString()));return false;}QDataStream in(&file);in.setVersion(QDataStream::Qt_4_3);quint32 magic;in >> magic;if (magic !&#61; MagicNumber) {QMessageBox::warning(this, tr("Spreadsheet"),tr("The file is not a Spreadsheet file."));return false;}clear();quint16 row;quint16 column;QString str;QApplication::setOverrideCursor(Qt::WaitCursor);while (!in.atEnd()) {in >> row >> column >> str;setFormula(row, column, str);}QApplication::restoreOverrideCursor();return true;
}//通过二进制方式写入文件中
bool Spreadsheet::writeFile(const QString &fileName)
{QFile file(fileName);if (!file.open(QIODevice::WriteOnly)) {QMessageBox::warning(this, tr("Spreadsheet"),tr("Cannot write file %1:\n%2.").arg(file.fileName()).arg(file.errorString()));return false;}QDataStream out(&file);out.setVersion(QDataStream::Qt_4_3);out <}void Spreadsheet::sort(const SpreadsheetCompare &compare)
{QList rows;QTableWidgetSelectionRange range &#61; selectedRange();int i;for (i &#61; 0; i }//cut &#61; copy &#43; del
void Spreadsheet::cut()
{copy();del();
}void Spreadsheet::copy()
{//由于在构造函数中setSelectionMode(ContiguousSelection);则选择范围无法大于1&#xff0c;需自定义selectedRange()QTableWidgetSelectionRange range &#61; selectedRange();QString str;//行与行之间用&#39;\n&#39;来分割&#xff0c;列与列之间用&#39;\t&#39;来分割for (int i &#61; 0; i 0)str &#43;&#61; "\n";for (int j &#61; 0; j 0)str &#43;&#61; "\t";str &#43;&#61; formula(range.topRow() &#43; i, range.leftColumn() &#43; j);}}//放到剪切板上面QApplication::clipboard()->setText(str);
}void Spreadsheet::paste()
{QTableWidgetSelectionRange range &#61; selectedRange();QString str &#61; QApplication::clipboard()->text();QStringList rows &#61; str.split(&#39;\n&#39;);int numRows &#61; rows.count();int numColumns &#61; rows.first().count(&#39;\t&#39;) &#43; 1;//这里不够智能&#xff0c;必须选定一样大小的范围才能粘贴上去(excel和wps只要选定一个表格即可)if (range.rowCount() * range.columnCount() !&#61; 1&& (range.rowCount() !&#61; numRows|| range.columnCount() !&#61; numColumns)) {QMessageBox::information(this, tr("Spreadsheet"),tr("The information cannot be pasted because the copy ""and paste areas aren&#39;t the same size."));return;}for (int i &#61; 0; i }void Spreadsheet::del()
{QList items &#61; selectedItems();if (!items.isEmpty()) {foreach (QTableWidgetItem *item, items)delete item; //直接释放资源即可somethingChanged();}
}void Spreadsheet::selectCurrentRow()
{selectRow(currentRow());
}void Spreadsheet::selectCurrentColumn()
{selectColumn(currentColumn());
}void Spreadsheet::recalculate()
{for (int row &#61; 0; row setDirty(); //标记为重新计算}}//通过update来重新绘制整个电子表格viewport()->update();
}//判断是否自动重新计算并更新
void Spreadsheet::setAutoRecalculate(bool recalc)
{autoRecalc &#61; recalc;if (autoRecalc)recalculate();
}void Spreadsheet::findNext(const QString &str, Qt::CaseSensitivity cs)
{int row &#61; currentRow();int column &#61; currentColumn() &#43; 1;while (row }void Spreadsheet::findPrevious(const QString &str,Qt::CaseSensitivity cs)
{int row &#61; currentRow();int column &#61; currentColumn() - 1;while (row >&#61; 0) {while (column >&#61; 0) {if (text(row, column).contains(str, cs)) {clearSelection();setCurrentCell(row, column);activateWindow();return;}--column;}column &#61; ColumnCount - 1;--row;}QApplication::beep();
}void Spreadsheet::somethingChanged()
{if (autoRecalc)recalculate();emit modified();
}Cell *Spreadsheet::cell(int row, int column) const
{//这里item是一个函数return static_cast(item(row, column));
}//设定公式
void Spreadsheet::setFormula(int row, int column,const QString &formula)
{Cell *c &#61; cell(row, column);if (!c) {c &#61; new Cell;setItem(row, column, c);}c->setFormula(formula);
}//返回给定单元格中的公式-->返回是公式的结果
QString Spreadsheet::formula(int row, int column) const
{Cell *c &#61; cell(row, column);if (c) {return c->formula();} else {return "";}
}//返回row行&#xff0c;column列的数据
QString Spreadsheet::text(int row, int column) const
{Cell *c &#61; cell(row, column);if (c) {return c->text();} else {return "";}
}bool SpreadsheetCompare::operator()(const QStringList &row1,const QStringList &row2) const
{for (int i &#61; 0; i row2[column];}}}}return false;
}
3. 子类化QTableWidgetItem

#include #include "cell.h"Cell::Cell()
{//设置缓存为最新setDirty();
}QTableWidgetItem *Cell::clone() const
{return new Cell(*this);
}void Cell::setData(int role, const QVariant &value)
{//通过特定的模式(role)来显示数据(value)QTableWidgetItem::setData(role, value);//编辑模式(EditRole)下&#xff0c;单元格需要重新计算if (role &#61;&#61; Qt::EditRole)setDirty();
}QVariant Cell::data(int role) const
{//显示文本if (role &#61;&#61; Qt::DisplayRole) {if (value().isValid()) {return value().toString();} else {return "####";}} else if (role &#61;&#61; Qt::TextAlignmentRole) {//返回一个对齐方式if (value().type() &#61;&#61; QVariant::String) {return int(Qt::AlignLeft | Qt::AlignVCenter);} else {return int(Qt::AlignRight | Qt::AlignVCenter);}} else {return QTableWidgetItem::data(role);}
}void Cell::setFormula(const QString &formula)
{setData(Qt::EditRole, formula);
}QString Cell::formula() const
{return data(Qt::EditRole).toString();
}void Cell::setDirty()
{cacheIsDirty &#61; true;
}const QVariant Invalid;//得到单元格的数据
QVariant Cell::value() const
{if (cacheIsDirty) {cacheIsDirty &#61; false;QString formulaStr &#61; formula();//数据以单引号(&#39;)开头&#xff0c;则为字符串if (formulaStr.startsWith(&#39;\&#39;&#39;)) {cachedValue &#61; formulaStr.mid(1);} else if (formulaStr.startsWith(&#39;&#61;&#39;)) {cachedValue &#61; Invalid;QString expr &#61; formulaStr.mid(1);expr.replace(" ", "");expr.append(QChar::Null);//为&#61;号情况下&#xff0c;计算公式的值int pos &#61; 0;cachedValue &#61; evalExpression(expr, pos);if (expr[pos] !&#61; QChar::Null)cachedValue &#61; Invalid;} else {//否则&#xff0c;为double类型bool ok;double d &#61; formulaStr.toDouble(&ok);if (ok) {cachedValue &#61; d;} else {cachedValue &#61; formulaStr;}}}return cachedValue;
}QVariant Cell::evalExpression(const QString &str, int &pos) const
{QVariant result &#61; evalTerm(str, pos);while (str[pos] !&#61; QChar::Null) {QChar op &#61; str[pos];if (op !&#61; &#39;&#43;&#39; && op !&#61; &#39;-&#39;)return result;&#43;&#43;pos;QVariant term &#61; evalTerm(str, pos);if (result.type() &#61;&#61; QVariant::Double&& term.type() &#61;&#61; QVariant::Double) {if (op &#61;&#61; &#39;&#43;&#39;) {result &#61; result.toDouble() &#43; term.toDouble();} else {result &#61; result.toDouble() - term.toDouble();}} else {result &#61; Invalid;}}return result;
}QVariant Cell::evalTerm(const QString &str, int &pos) const
{QVariant result &#61; evalFactor(str, pos);while (str[pos] !&#61; QChar::Null) {QChar op &#61; str[pos];if (op !&#61; &#39;*&#39; && op !&#61; &#39;/&#39;)return result;&#43;&#43;pos;QVariant factor &#61; evalFactor(str, pos);if (result.type() &#61;&#61; QVariant::Double&& factor.type() &#61;&#61; QVariant::Double) {if (op &#61;&#61; &#39;*&#39;) {result &#61; result.toDouble() * factor.toDouble();} else {if (factor.toDouble() &#61;&#61; 0.0) {result &#61; Invalid;} else {result &#61; result.toDouble() / factor.toDouble();}}} else {result &#61; Invalid;}}return result;
}QVariant Cell::evalFactor(const QString &str, int &pos) const
{QVariant result;bool negative &#61; false;if (str[pos] &#61;&#61; &#39;-&#39;) {negative &#61; true;&#43;&#43;pos;}if (str[pos] &#61;&#61; &#39;(&#39;) {&#43;&#43;pos;result &#61; evalExpression(str, pos);if (str[pos] !&#61; &#39;)&#39;)result &#61; Invalid;&#43;&#43;pos;} else {QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");QString token;while (str[pos].isLetterOrNumber() || str[pos] &#61;&#61; &#39;.&#39;) {token &#43;&#61; str[pos];&#43;&#43;pos;}if (regExp.exactMatch(token)) {int column &#61; token[0].toUpper().unicode() - &#39;A&#39;;int row &#61; token.mid(1).toInt() - 1;Cell *c &#61; static_cast(tableWidget()->item(row, column));if (c) {result &#61; c->value();} else {result &#61; 0.0;}} else {bool ok;result &#61; token.toDouble(&ok);if (!ok)result &#61; Invalid;}}if (negative) {if (result.type() &#61;&#61; QVariant::Double) {result &#61; -result.toDouble();} else {result &#61; Invalid;}}return result;
}




转:https://my.oschina.net/voler/blog/343676



推荐阅读
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • WinMain 函数详解及示例
    本文详细介绍了 WinMain 函数的参数及其用途,并提供了一个具体的示例代码来解析 WinMain 函数的实现。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • 三角测量计算三维坐标的代码_双目三维重建——层次化重建思考
    双目三维重建——层次化重建思考FesianXu2020.7.22atANTFINANCIALintern前言本文是笔者阅读[1]第10章内容的笔记,本文从宏观的角度阐 ... [详细]
  • 通过将常用的外部命令集成到VSCode中,可以提高开发效率。本文介绍如何在VSCode中配置和使用自定义的外部命令,从而简化命令执行过程。 ... [详细]
  • 基于iSCSI的SQL Server 2012群集测试(一)SQL群集安装
    一、测试需求介绍与准备公司计划服务器迁移过程计划同时上线SQLServer2012,引入SQLServer2012群集提高高可用性,需要对SQLServ ... [详细]
  • C语言中全部可用的数学函数有哪些?2.longlabs(longn);求长整型数的绝对值。3.doublefabs(doublex);求实数的绝对值。4.doublefloor(d ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 字符串学习时间:1.5W(“W”周,下同)知识点checkliststrlen()函数的返回值是什么类型的?字 ... [详细]
  • window下的python安装插件,Go语言社区,Golang程序员人脉社 ... [详细]
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
author-avatar
fanguobiao
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有