- •Пояснительная записка к курсовому проекту
- •Техническое задание
- •Введение
- •Технологический раздел
- •Постановка задачи
- •Требования к программе
- •Проектирование
- •Разработка интерфейса
- •Алгоритм расчетов в электронной таблице
- •Тестирование программы.
- •Руководство пользователя.
- •Заключение
- •Список литературы
- •Книга Блашет
- •Книга Шлее
- •Методичка Живодеровой в.В.
Алгоритм расчетов в электронной таблице
Основное поле для ввода в ячейки реализовано через классы
Cell
SpreadsheetCompare
QTableWidget
Рассмотрим подробнее как реализовано создание самой таблицы.
В классе Spreadsheet объявляем число колонок и столбцов.
enum { MagicNumber = 0x7F51C883, RowCount = 999, ColumnCount = 26 }; - задаём магическое число, колонки и строки.
Давайте, рассмотрим куда мы попадаем при нажатии на ячейку таблицы. При описании алгоритма наши комментарии выделены курсивом.
QVariant Cell::data(int role) const
{
if (role == Qt::DisplayRole) {
if (value().isValid()) { - если значение попавшее в ячейку не содержит пометку QVariant::Invalid то возвращаем true
return value().toString(); возвращаем преобразованное значение в тип String
} else {
return "####"; - в другом случае заполняем ячейку решётками
}
} else if (role == Qt::TextAlignmentRole) { - если значение текстового типа возвращаем true
if (value().type() == QVariant::String) { -если значение value string
return int(Qt::AlignLeft | Qt::AlignVCenter); -Выравнивание текста
} else {
return int(Qt::AlignRight | Qt::AlignVCenter);
}
} else {
return QTableWidgetItem::data(role);
}
}
Давайте, рассмотрим куда попадает строка если в ней содержится формула.
QString Cell::formula() const
{
return data(Qt::EditRole).toString(); - возвращаем строку
}
QVariant Cell::value() const
{
if (cacheIsDirty) {
cacheIsDirty = false;
QString formulaStr = formula();
if (formulaStr.startsWith('\'')) { - если нет формулы
cachedValue = formulaStr.mid(1);
} else if (formulaStr.startsWith('=')) { -если есть формула
cachedValue = Invalid; -присваиваем invalid
QString expr = formulaStr.mid(1); -expr присваиваем formulaStr
expr.replace(" ", ""); - удаляем пробелы
if (expr.contains("sin") == true || expr.contains("cos") == true || expr.contains("tan") == true || expr.contains("ctg") == true ) { - если expr содержит sin или cos,tan,ctg тогда (пример для синуса)
while (expr[expr.indexOf("sin")+3] == QChar('(') && expr[expr.indexOf("(")+1] != QChar(')') ) – пока у нас есть синус ячейки
если у нас закрывающая скобка стоит после синуса
if(expr.indexOf(")") > expr.indexOf("sin") ) {
int i = 5;
QString token;
while (expr[expr.indexOf("sin")+i] != ')')
{
token += expr[expr.indexOf("sin")+i]; -
i++;
}
int column = expr[expr.indexOf("(")+1].toUpper().unicode() - 'A'; -преобразуем ячейку в числовой вид
int row = token.toInt()-1;
Cell *c = static_cast<Cell *>(
tableWidget()->item(row,column)); -переходим в ячейку
QVariant result;
if (c) result = c->value(); - если ячейка существует тогда присваиваем переменной result значение из ячейки.
result = sin(result.toDouble()); - синус из результата
expr.replace(expr.indexOf("sin"),expr.indexOf(")")-expr.indexOf("sin")+1,result.toString()); - заменяем sin(A1) на значение переменной result.
}
expr.append(QChar::Null); -добавляем \000
int pos = 0;
cachedValue = evalExpression(expr, pos); - присваиваем значение cachedValue
if (expr[pos] != QChar::Null) – если значение не в юникод формате
cachedValue = Invalid; - присваиваем invalid
} else {
bool ok; - объявляем переменную
double d = formulaStr.toDouble(&ok); -если строка перекодируется
if (ok) {
cachedValue = d; -присваиваем d
} else {
cachedValue = formulaStr; -присваиваем cachedValue значение formulaStr.
}
}
}
return cachedValue; - возвращаем значение cachedValue.
}
QVariant Cell::evalExpression(const QString &str, int &pos) const
{
QVariant result = evalTerm(str, pos); - присваиваем переменной result значение функции
while (str[pos] != QChar::Null) { - пока в строке не закончатся символы
QChar op = str[pos]; - присваиваем переменной op значение одного символа из массива строки str.
if (op != '+' && op != '-') –если у нас op не равен плюсу либо минусу
return result; - возвращаем результат
++pos;
QVariant term = evalTerm(str, pos); - присваиваем переменной term значение функции
if (result.type() == QVariant::Double – если тип переменной result и тип переменной term double то
&& term.type() == QVariant::Double) {
if (op == '+') { - если плюс
result = result.toDouble() + term.toDouble(); плюсуем
} else {
result = result.toDouble() - term.toDouble(); минусуем
}
} else {
result = Invalid; - иначе возвращаем invalid
}
}
return result;
}
QVariant Cell::evalTerm(const QString &str, int &pos) const
{
QVariant result = evalFactor(str, pos); - присваиваем значение переменной result
while (str[pos] != QChar::Null) { - пока не кончатся символы
QChar op = str[pos]; - переменной op присваиваем str[pos]
if (op != '*' && op != '/') – если op не ровна * или / тогда
return result; возвращаем result
++pos; - добавляем единицу к переменной pos
QVariant factor = evalFactor(str, pos); - переменной factor присваиваем значение функции evalFactor
if (result.type() == QVariant::Double
&& factor.type() == QVariant::Double) { - если тип result и factor double тогда
if (op == '*') {
result = result.toDouble() * factor.toDouble(); - если op равна * присваиваем переменной result выражение
} else {
if (factor.toDouble() == 0.0) {
result = Invalid;
} else {
result = result.toDouble() / factor.toDouble();
}
}
} else {
result = Invalid;
}
}
return result;
}
Реальный пример расчета максимальной дальности полёта с использованием тригонометрических функций привидён на Рис 7.
Рис 7 Расчётная таблица дальности полёта тела брошенного под углом горизонту
