热门标签 | 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



推荐阅读
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • 本文介绍了一种解决PyQt界面在高分辨率下字体显示不完全的方法。通过设置High_DPI属性或应用自适应字体,可以解决在更高分辨率电脑上字体被控件遮挡的问题。同时,还提供了判断Qt版本和设置字体大小的代码示例。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
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社区 版权所有