首页 > 代码库 > 【QT】C++ GUI Qt4 学习笔记4

【QT】C++ GUI Qt4 学习笔记4

感觉这本书的顺序设计的太不合理了,出现的最多的一句话就是后面会讲。按照使用的顺序讲不行吗?搞得代码都运行不了。

我决定先直接跳到73页,子类化QTableWidgetItem这一节。因为前面功能的实现都依赖于这一部分。

 

 预备知识:

C++关键字 mutable:

  mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。
  在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
  我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰。

----------------------------------------------------------------------------------------------------------------

Start:

QTableWidget是一个QT已经实现了的二维表格的类,每一个单元格的文本都用一个自动创建的QTableWidgetItem来存储。

为了实现更多的功能,我们自己创建一个类Cell来扩展QTableWidgetItem的功能。

QVariant 类: The QVariant class acts like a union for the most common Qt data types.

 

在Cell类中,用两个私有变量来扩展功能。

  mutable QVariant cachedValue;
   mutable bool cacheIsDirty;

cachedValue 缓存单元格的值

若单元格的值不是最新的 cacheIsDirty 设为 true

 

好吧 后面变成了纯粹的看这一部分的代码,计算表达式的值时,三个函数的循环调用有些难度。

cell.h

#ifndef CELL_H#define CELL_H#include <QTableWidgetItem>class Cell : public QTableWidgetItem{public:    Cell();    QTableWidgetItem *clone() const;    void setData(int role, const QVariant &value);    QVariant data(int role) const;    void setFormula(const QString &formula); //设置单元格公式    QString formula() const;    void setDirty(); //把值设为旧的private:    QVariant value() const; //返回单元格的合适的值    QVariant evalExpression(const QString &str, int &pos) const; //解析表达式    QVariant evalTerm(const QString &str, int &pos) const; //解析项    QVariant evalFactor(const QString &str, int &pos) const; //解析因子    mutable QVariant cachedValue;    mutable bool cacheIsDirty;};#endif // CELL_H

cell.cpp

#include <QtGui>#include "cell.h"Cell::Cell(){    setDirty();}//新建一个单元格时调用QTableWidgetItem *Cell::clone() const{    return new Cell(*this);}void Cell::setDirty(){    cacheIsDirty = true;}const QVariant Invalid;QVariant Cell::value() const //设置单元格的值{    if (cacheIsDirty) {        cacheIsDirty = false;        QString formulaStr = formula();        if (formulaStr.startsWith(\‘)) { // ‘开始返回字符串            cachedValue = http://www.mamicode.com/formulaStr.mid(1);        } else if (formulaStr.startsWith(=)) { // =开始返回公式            cachedValue =http://www.mamicode.com/ Invalid;            QString expr = formulaStr.mid(1);            expr.replace(" ", "");            expr.append(QChar::Null);            int pos = 0;            cachedValue = evalExpression(expr, pos);            if (expr[pos] != QChar::Null) //解析表达式失败 返回无效值                cachedValue =http://www.mamicode.com/ Invalid;        } else {            bool ok;            double d = formulaStr.toDouble(&ok); //转换为数字成功 返回数字            if (ok) {                cachedValue = d;            } else {                cachedValue = formulaStr; //返回字符串            }        }    }    return cachedValue;}void Cell::setData(int role, const QVariant &value){    QTableWidgetItem::setData(role, value);    if (role == Qt::EditRole)        setDirty();  //如果有新的公式就把cacheIsDirty设为True 以保证下次调用text时重新计算值}QVariant Cell::data(int role) const //重新实现QTableWidgetItem::data{    if (role == Qt::DisplayRole) { //如果是DisplayRole调用这个函数 返回应该显示的文本        if (value().isValid()) {            return value().toString();        } else {            return "####"; //如果文本无效 返回####        }    } else if (role == Qt::TextAlignmentRole) {//返回合适的对齐方式        if (value().type() == QVariant::String) {            return int(Qt::AlignLeft | Qt::AlignVCenter);        } else {            return int(Qt::AlignRight | Qt::AlignVCenter);        }    } else { //如果 EditRole调用 返回该单元格的公式        return QTableWidgetItem::data(role);    }}void Cell::setFormula(const QString &formula){    setData(Qt::EditRole, formula); //对编辑角色调用setData}QString Cell::formula() const{    return data(Qt::EditRole).toString(); //重新获得该项的EditRole数据}//对于下面三个函数的循环套用没完全看懂QVariant Cell::evalExpression(const QString &str, int &pos) const{    QVariant result = evalTerm(str, pos);    while (str[pos] != QChar::Null) {        QChar op = str[pos];        if (op != + && op != -)            return result; //这里的return 使得evalFactor中调用该函数成为可能        ++pos;        QVariant term = evalTerm(str, pos);        if (result.type() == QVariant::Double                && term.type() == QVariant::Double) {            if (op == +) {                result = result.toDouble() + term.toDouble();            } else {                result = result.toDouble() - term.toDouble();            }        } else {            result = Invalid;        }    }    return result;}QVariant Cell::evalTerm(const QString &str, int &pos) const{    QVariant result = evalFactor(str, pos);    while (str[pos] != QChar::Null) {        QChar op = str[pos];        if (op != * && op != /)            return result;        ++pos;        QVariant factor = evalFactor(str, pos);        if (result.type() == QVariant::Double                && factor.type() == QVariant::Double) {            if (op == *) {                result = result.toDouble() * factor.toDouble();            } else {                if (factor.toDouble() == 0.0) {                    result = Invalid;                } else {                    result = result.toDouble() / factor.toDouble();                }            }        } else {            result = Invalid;        }    }    return result;}QVariant Cell::evalFactor(const QString &str, int &pos) const{    QVariant result;    bool negative = false;    if (str[pos] == -) {        negative = true;        ++pos;    }    if (str[pos] == () {        ++pos;        result = evalExpression(str, pos);        if (str[pos] != ))            result = Invalid;        ++pos;    } else {        QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");        QString token;        while (str[pos].isLetterOrNumber() || str[pos] == .) {            token += str[pos];            ++pos;        }        if (regExp.exactMatch(token)) {            int column = token[0].toUpper().unicode() - A;            int row = token.mid(1).toInt() - 1;            Cell *c = static_cast<Cell *>(                              tableWidget()->item(row, column));            if (c) {                result = c->value();            } else {                result = 0.0;            }        } else {            bool ok;            result = token.toDouble(&ok);            if (!ok)                result = Invalid;        }    }    if (negative) {        if (result.type() == QVariant::Double) {            result = -result.toDouble();        } else {            result = Invalid;        }    }    return result;}

 

然后回去看spreadsheet部分,把定义和clear()实现后终于可以显示一个像样子的界面了。虽然没有实现功能,但也不错了。

 

【QT】C++ GUI Qt4 学习笔记4