понедельник, 17 ноября 2008 г.

Эволюция формы "параметры изделия"





и каждый раз я говорил себе "вот теперь - точно оно!"  


четверг, 6 ноября 2008 г.

Система калькуляции заказов

Приступили к работе над калькулятором. На данный момент остановились на следующей системе - расчет на основе данных по оборудованию + скидки/наценки по конкретным клиентам. Ниже - пример расчета, основанный на оборудовании. Критика - приветствуется ) 

Операция
Время переналадки
Скорость
Учетная стоимость/час
Учетный материал 1
Кол-во на приладку
Расход на единицу
Техотходы %
...
Исполнитель
Учетная ставка

/
ПРИМЕР
Фальцовка автоматическая
Приладка 15 минут
Скорость 5000/час
Стоимость 1500/час
Техотходы 5%
Оператор фальцаппарта 100р./час

Печать SM-74-4
Переналадка 30 минут
Скорость 10000/час
Стоимость 10000р./час
Бумага на приладку 250 листов
Техотходы 5%.
Печатник 250р./час

Вывод форм Suprasetter
Скорость 12/час
Стоимость 1000 р./час
Формы 300р./шт
Оператор 200р./час
Техотходы 2%

/
ПРИМЕР
Заказ газета А2 4+4 1 фальц 10000 экз.

Калькуляция

Вывод форм тираж 8 шт.
Время операции 1 час.
Стоимость
Формы 2400
Техотходы 50
Оператор 200
Работа оборудования 1000
Итого 3650 р.

Печать SM74-4 Выходной тираж 10100 экз.
2 переналадки
20200 оттисков
Бумага на приладку 500 л
Бумага на техотходы 1000 л.
Всего бумаги 21700 л. * 1,5 р. = 32250 р.
Время печати 3 часа
Стоимость операции 63000 р.

Фальцовка Выходной тираж 10050 экз.
Время операции 2,5 часа
Техотходы 50 экз.
Стоимость 4000 р.

воскресенье, 28 сентября 2008 г.

Реализация раздела "Заказчики". Часть 3

3. "Корзина"

Таблица "корзина" реализуется аналогично таблице "все заказчики", с единственным отличием - в условии фильтрации proxyModel:

proxyModel->setFilterRegExp(QRegExp("0", Qt::CaseInsensitive, QRegExp::FixedString)); 
proxyModel->setFilterKeyColumn(10);

- после чего в таблице "корзина" будут отображаться записи, в которых значение колонки "active" равно "0". Таким образом, все что нужно сделать для того, чтобы переместить запись заказчика в корзину - изменить значение "active":

customerform *page = (customerform*) ui.tabWidget->currentWidget(); // получаем указатель на текущую закладку в tabWidget заказчиков
QSqlRecord record = model->record(page->mapper->currentIndex()); // получаем из модели запись текущего заказчика
record.setValue("active", "0"); // устанавливаем active в ноль
model->setRecord(page->mapper->currentIndex(), record); // обновляем запись текущего заказчика
model->submitAll();
ui.tabWidget->removeTab(ui.tabWidget->currentIndex()); // удаляем текущую вкладку 

Востановим запись из корзины:

QModelIndex index = ui.tableView->currentIndex(); // индекс выделенной строки в таблице "корзина"
QModelIndex index2 = proxyModel->mapToSource(index); // переводим его из proxyModel в индекс исходной модели
model->setData(cust_model->index(index2.row(), 9), "1"); // изменяем active 
model->submitAll(); 

Удаляем запись навсегда:

QModelIndex index = ui.tableView->currentIndex(); // индекс выделенной строки в таблице "корзина"
QModelIndex index2 = proxyModel->mapToSource(index); // переводим в индекс исходной модели
model->removeRow(index2.row()); // удаляем строку из модели
model->submitAll(); // обновляем базу данных

пятница, 26 сентября 2008 г.

Драйвера в Qt

В стандартной сборке Qt часть драйверов различных модулей внедрены как плагины и при компиляции проекта не включаются в исполняемый файл. Это касается и драйвера SQLite. Т.е. при запуске приложения в системе, где бибилиотека Qt не установлена, нас ждут ошибки, или сообщение - "драйвер не найден". Чтобы решить эту проблему, мы должны либо добавить необходимый драйвер (в случае с SQLite - это qsqlite4.dll, которую надо поместить в директорию sqldrivers в папке с exe-файлом), либо пересобрать Qt, задав с помощью configure включение драйвера непосредственно в библиотеку Qt (для SQLite - это "-qt-sql-sqlite").

вторник, 23 сентября 2008 г.

Реализация раздела "Заказчики". Часть 2

2. Форма для добавления и редактирования данных по заказчикам.

Связать модель с такими виджетами, как TableView или ListView - легко и просто, достаточно только вызвать setModel() и проблема решена. Но как быть, если виджет представляет из себя форму, на которой размещены комбобоксы, лайнедиты и т.п.? Как установить связь менжду этими элементами и SQL-данными? 
Реализовать подобное можно двумя способами: 1) не используя QDataWidgetMapper и 2) используя QDataWidgetMapper. Далее - описание второго способа.
Итак, есть виджет, на котором размещены несколько lineEdit. Каждый из них нам нужно связать с той или иной колонкой из таблицы "customers": 
lineEdit - название заказчика, lineEdit_1 - город заказчика, ну и т.д. 

QDataWidgetMapper *mapper = new QDataWidgetMapper(this); // создаем в конструкторе виджета маппер
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); // определяем стратегию обновления данных
mapper->setModel(model); // назначаем модель с таблицей "customers"

Используя метод addMapping(), установим связь между  lineEdit и колонками таблицы:

mapper->addMapping(ui.lineEdit, 0); // имя заказчика
mapper->addMapping(ui.lineEdit_1, 1); // город
mapper->addMapping(ui.lineEdit_2, 2); // улица
mapper->addMapping(ui.lineEdit_3, 3); // офисный телефон
mapper->addMapping(ui.lineEdit_4, 4); // факс
mapper->addMapping(ui.lineEdit_5, 5); // имя контактного лица
mapper->addMapping(ui.lineEdit_6, 7); // мобильный номер
mapper->addMapping(ui.lineEdit_7, 8); // майл
mapper->addMapping(ui.textEdit, 9); // примечание

После того, как мы связали лайнедиты с табличными колонками, осталось только назначить мапперу табличный индекс. Продемонстрируем это на примере открытия записи заказчика из таблицы "Все заказчики" - метод OpenCustomer(QModelIndex), назначенный в качестве слота сигналу doubleClicked виджета tableView:

connect(ui.tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OpenCustomer(QModelIndex)));

После двойного клика на строке виджета tableView в метод OpenCustomer передается текущий индекс из модели, которая была задана виджету. Остается только передать этот индекс маппер, но... В маппер в качестве модели мы назначили QSqlTableModel, а виджету tableView - QSortFilterProxyModel. Чтобы избежать ошибки, необходимо перевести индекс из QSortFilterProxyModel в индекс QSqlTableModel:

QModelIndex index2 = proxyModel->mapToSource(index); // переводим текущий index из QSortFilterProxyModel в QSqlTableModel
mapper->setCurrentModelIndex(index2); // назначаем индекс мапперу

Теперь в лайнедитах отображаются данные из строки, выделенной в виджете tableView. Выше мы выбрали "ручную" стратегию сохранения, таким образом, для того, чтобы изменения в лайнедитах вступили в силу - необходимо вызвать метод submit().

понедельник, 22 сентября 2008 г.

Реализация раздела "Заказчики". Часть 1

Задачи:

1. Стартовая страница с таблицей "Все заказчики", в которой отображаются записи из таблицы "customers" со значением "active" == 1.
2. Форма для добавления и редактирования данных по заказчикам.
3. "Корзина" с таблицей удаленных заказчиков, где отображаются записи со значением "active" == 0. 

Реализация:

1. Таблица "Все заказчики".

Вся информация по заказчикам хранится в базе данных "customers.s3db", в таблице "customers". Для отображения записей воспользуемся модулем QSqlTableModel, реализующим технологию модель/вид между SQL-таблицами и такими виджетами, как QListView, QTableView и QTreeView. 

QSqlTableModel *model = new QSqlTableModel;
model->setTable("customers");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();

setEditStrategy() определяет метод обновления данных в sql-таблице после их изменения в виджете: 
QSqlTableModel::OnFieldChange - данные обновляются немедленно; 
QSqlTableModel::OnRowChange - новые данные передаются в таблицу после того, как пользователь выделяет другую строку; 
QSqlTableModel::OnManualSubmit - изменения вносятся в момент вызова метода submitAll().
Назначим созданную модель виджету QTableView -

tableView->setModel(model);

- после чего виджет tableView будет отображать все строки и колонки из таблицы "customers". 
Скрыть некоторые колонки можно как на уровне модели (model->removeColumn(1)), так и на уровне виджета (tableView->hideColumn(1)). Мы воспользуемся вторым методом, и спрячем часть колонок, оставив только название заказчика, имя контактного лица, телефон и емайл.

tableView->hideColumn(1); // прячем название города
tableView->hideColumn(2); // прячем название улицы и т.д.

Колонка "active" в таблице "customers" отображает текущее состояние записи о заказчике: если запись удалениа - "active" принимает значение 0, и запись перемещается в таблицу "Корзина", с возможностью восстановления, или окончательного удаления; если значение "active" == 1, то запись отображается в таблице "Все заказчики".
Есть несколько способов реализации фильтрации строк. Опять же на уровне модели (model->setFilter("active = 1")), или с помощью модуля QSortFilterProxyModel, позволяющим установить правила для фильтрации и сортировки данных между моделью и видом.
Зададим фильтрацию по значению "active" для таблицы "Все заказчики", используя QSortFilterProxyModel:

proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model); // указываем в качестве исходной модели QSqlTableModel с таблицей "customers". 
proxyModel->setFilterRegExp(QRegExp("1", Qt::CaseInsensitive, QRegExp::FixedString)); // "верное" значение фильтрации
proxyModel->setFilterKeyColumn(10); // задаем номер колонки, по которой будет происходить фильтрация

После того, как правило фильтрации установленно, назначаем proxyModel виджету:
tableView->setModel(proxyModel); 

В итоге код для таблицы "Все заказчики" будет выглядеть вот так:

proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
proxyModel->setFilterRegExp(QRegExp("1", Qt::CaseInsensitive, QRegExp::FixedString));
proxyModel->setFilterKeyColumn(10);
ui.tableView->setModel(proxyModel);
ui.tableView->hideColumn(1);
ui.tableView->hideColumn(2);
ui.tableView->hideColumn(3);
ui.tableView->hideColumn(4);
ui.tableView->hideColumn(9);
ui.tableView->hideColumn(10);

среда, 17 сентября 2008 г.

QTextCodec(Кодировка)

Дело в том, что в Qt по умолчанию стоит отображение, как символов, так и строк в кодировке Unicode - Utf-8, Utf-16. И это правильно, но скажем если вы работаете под операционной системой Windows то там по умолчанию стоит кодировка cp1251 для России! Т.е. кириллица Windows-code page 1251 .
Создали простой проект на Qt :
…………….
#include "testa1.h"

#include "QtGui"
#include "QApplication"

int main(int argc, char *argv[])
{

QApplication app(argc, argv);
QLabel *label = new QLabel("Здорого эт Юникод", 0);
label->show();
return app.exec();

}
…..

И отобразится что-то вроде -- Çäîðîãî ýò Þíèêîä;

Для нормального отображения нужно сделать следующее, в Qt есть специальный класс QTextCodec проще говоря нам нужно установить в нашем проекте другую кодировку, для этого воспользуемся функцией setCodec();
QTextCodec* codec = QTextCodec::codecForName("CP1251");//создаем указатель на QTextCodex и говорим что его кодировка "cp1251"
QTextCodec::setCodecForCStrings(codec);//устанавливаем для строк CString кодировку cp1251

……………………………………
#include "testa1.h"

#include "QtGui"
#include "QApplication"

int main(int argc, char *argv[])
{

QApplication app(argc, argv);
QTextCodec* codec = QTextCodec::codecForName("CP1251");
QTextCodec::setCodecForCStrings(codec);

QTextCodec* codec = QTextCodec::codecForName("CP1251");//создаем указатель на QTextCodex и говорим что его кодировка "cp1251"
QTextCodec::setCodecForCStrings(codec);//устанавливаем для строк CString кодировку cp1251
QLabel *label = new QLabel("Здорого эт Юникод", 0);

label->show();
return app.exec();

}
…………………….

Результат выполнения: Здорого эт Юникод.

Заключение:
Для изменения и установки какой-либо требуемой кодировки используется класс QTextCodec;
Для изменения кодировки QObject::tr (функция static QString tr) используется функция QTextCodec::setCodecForTr()
Для изменения отображения кодировки символов на локале QTextCodec::setCodecForLocale()