Уважаемые, если у кого есть время, желание итд, пожалуйста просмотрите проект домашней бухгалтерии https://github.com/Sheridan/HAcc
В логику можно не вникать, мне хочется знать что там может быть не так, неправильно, или некрасиво.
Спасибо заранее
Здравствуйте, Sheridan, Вы писали:
S>Уважаемые, если у кого есть время, желание итд, пожалуйста просмотрите проект домашней бухгалтерии https://github.com/Sheridan/HAcc S>В логику можно не вникать, мне хочется знать что там может быть не так, неправильно, или некрасиво.
Про логику
1. Зачем синглетонов напихал?
2. Здесь <HAcc / trunk / src / model> чего такое???
file ccontractors.cpp April 21, 2011 Создание и редактирование валюты [Sheridan]
Как получается, что контрагенты создают и редактируют валюты?
3. Здесь <HAcc / trunk / src / model / ccurrencyes.h>
S>Уважаемые, если у кого есть время, желание итд, пожалуйста просмотрите проект домашней бухгалтерии https://github.com/Sheridan/HAcc S>В логику можно не вникать, мне хочется знать что там может быть не так, неправильно, или некрасиво. S>Спасибо заранее
выражение m_actions[atype][id] повторяется дважды-трижды (в зависимости от ифа), а ведь это каждый раз двойной поиск по мапам, т.е. операция совсем небыстрая в общем случае.
Плюс непонятно, что будет, если generateAction() вернет NULL, если такое может быть, конечно.
S>Уважаемые, если у кого есть время, желание итд, пожалуйста просмотрите проект домашней бухгалтерии https://github.com/Sheridan/HAcc S>В логику можно не вникать, мне хочется знать что там может быть не так, неправильно, или некрасиво. S>Спасибо заранее
1) Не понравилась конвертация string->money,amount. Надо использовать QLocale::decimalPoint, ну и плюс хранение денег просто в double без отдельного класса, это та еще головная боль при поиске копеек.
2) Много макросов.
3) Не внятное владение указателями на объект в CFileDialogs
QFileDialog *CFileDialogs::fileDialog(...)
{
QFileDialog *dlg = new QFileDialog(HACC_WINDOW);// у dlg как я понимаю есть родитель
}
SFileDialogResult CFileDialogs::getOpenFileName(const QString &title, const QString &extentions)
{
QFileDialog *dlg = fileDialog(title, extentions);// здесь создали объект и сделали ему родителя
dlg->setFileMode(QFileDialog::ExistingFile);
return execFileDialog(dlg, title, extentions);// здесь на прямую удалили dlg
}
Мне все равно как форматируются исходники и по какому принципу называются классы, но такое встречаю первый раз , ненадолго впал в ступор
4) Заходя в src/model думал будут наследники QAbstractModel.
5) При первом запуске программа не смогла поместится на экран, создавая доки используй tabifyDockWidget.
6) В модальные диалоги передавай parent, чтобы не было лишних движений в (как называется то место где все программы появляются после запуска?) Ну и убери знак (?) в диалогах.
Кроме того в программе присутствуют бесконечные delete, даже для диалогов. В Qt же есть отличный механизм удаления объектов, унаследованных от QObject.
Вот, например:
WAbstractScrollArea::~WAbstractScrollArea()
{
delete m_wArea; // Это лишнее...
}
void WAbstractScrollArea::buildSelfUi()
{
setVerticalScrollBarPolicy (Qt::ScrollBarAsNeeded );
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_wArea = new QWidget(this); // ...потому что m_wArea - наследник QObject
m_wArea->setLayout(m_lArea);
setViewport(m_wArea);
}
Если не нужно наследоваться от QObject, есть ещё QScopedPointer, QSharedPointer.
Здравствуйте, sheep2k, Вы писали:
S>Кроме того в программе присутствуют бесконечные delete, даже для диалогов. В Qt же есть отличный механизм удаления объектов, унаследованных от QObject.
Привык самостоятельно следить за удалением созданного. Отвыкать нет никакого желания, да и опасно, есть шанс в один прекрасный момент выстрелить себе в ногу.
Здравствуйте, VVP, Вы писали:
VVP>Здравствуйте, Sheridan, Вы писали:
S>>Уважаемые, если у кого есть время, желание итд, пожалуйста просмотрите проект домашней бухгалтерии https://github.com/Sheridan/HAcc S>>В логику можно не вникать, мне хочется знать что там может быть не так, неправильно, или некрасиво.
VVP>Про логику VVP>1. Зачем синглетонов напихал?
Надо было в одном все городить?
VVP>2. Здесь <HAcc / trunk / src / model> чего такое??? VVP>
file ccontractors.cpp April 21, 2011 Создание и редактирование валюты [Sheridan]
Как получается, что контрагенты создают и редактируют валюты?
В коммит попало какоето изменение в указанном файле
VVP>3. Здесь <HAcc / trunk / src / model / ccurrencyes.h> VVP>
Здравствуйте, Sheridan, Вы писали:
S>Привык самостоятельно следить за удалением созданного. Отвыкать нет никакого желания, да и опасно, есть шанс в один прекрасный момент выстрелить себе в ногу.
Как раз самостоятельное удаление — это и есть стрельба себе по ногам. Потому что утечки будут всякий раз при возникновении необработанного исключения.
За освобождением ресурсов должны следить RAII-обёртки.
I>Здравствуйте, Sheridan, Вы писали:
S>>Уважаемые, если у кого есть время, желание итд, пожалуйста просмотрите проект домашней бухгалтерии https://github.com/Sheridan/HAcc S>>В логику можно не вникать, мне хочется знать что там может быть не так, неправильно, или некрасиво. S>>Спасибо заранее
Зачем столько вспомогательных GUI классов? Чем стандартные не угодили? Писал бы на qml я бы еще понял, там с этим не всегда хорошо.
Здравствуйте, jazzer, Вы писали:
J>Плюс непонятно, что будет, если generateAction() вернет NULL, если такое может быть, конечно.
Это обрабатывается несколько позже, в итоге возвращается new QAction("Somewhere bug", 0);
J>checkSpetialPurposeTag -> checkSpecialPurposeTag (и прочие Spetial) J>CSingleTone -> CSingletone J>CTransactionsPools -> CTransactionPools, transactions_pool -> transaction_pool
Fixed.
J>выражение m_actions[atype][id] повторяется дважды-трижды (в зависимости от ифа), а ведь это каждый раз двойной поиск по мапам, т.е. операция совсем небыстрая в общем случае.
По другому практически никак. Смысл в том, что есть действие не существует, оно создается и возвращается. Если существует, то просто возвращается. Типа синглтонов.
Здравствуйте, Igore, Вы писали:
I>Зачем столько вспомогательных GUI классов? Чем стандартные не угодили? Писал бы на qml я бы еще понял, там с этим не всегда хорошо.
Всмысле? Я беру стандартные и компоную из них нужные мне. Например кнопка с выпадающим списком-табличкой и индикацией выбранного на кнопке.
Здравствуйте, Igore, Вы писали:
I>1) Не понравилась конвертация string->money,amount. Надо использовать QLocale::decimalPoint,
Смысл запятую в точку преобразовать и поудалять все кроме чисел и точки. Зачем лишний вызов?
I>ну и плюс хранение денег просто в double без отдельного класса, это та еще головная боль при поиске копеек.
мысль...
I>2) Много макросов.
Ничего не поделаешь, мне очень удобно с макросами.
I>3) Не внятное владение указателями на объект в CFileDialogs
Согласен, невнятное. Но работает правильно
I>Мне все равно как форматируются исходники и по какому принципу называются классы, но такое встречаю первый раз , ненадолго впал в ступор I>
Смысл — совпадающие части выровнять. Изза этого сразу видно различие между строками.
I>5) При первом запуске программа не смогла поместится на экран,
о0 15"?
I>создавая доки используй tabifyDockWidget.
А, понял. Возможно. Может mdi по умолчанию?
Здравствуйте, Sheridan, Вы писали:
J>>выражение m_actions[atype][id] повторяется дважды-трижды (в зависимости от ифа), а ведь это каждый раз двойной поиск по мапам, т.е. операция совсем небыстрая в общем случае. S>По другому практически никак. Смысл в том, что есть действие не существует, оно создается и возвращается. Если существует, то просто возвращается. Типа синглтонов.
не, это ты не понял.
тебя операторы с толку сбивают, похоже.
давай я перепишу на вызовах функций:
Здравствуйте, jazzer, Вы писали:
J>теперь проблема видна?
Я это понимал и раньше. Терперь давай тебе объясню:
QAction * CBases::constructAction(EActionsTypes atype, const hacc::TDBID &id, QObject *reciever, const char * method)
{
if(В массиве есть элемент?)
{
QAction *gAction = generateAction(atype, reciever, method);
gAction->setEnabled(HACC_DB->isOpen());
connect(HACC_DB, SIGNAL(stateChange(bool)), gAction, SLOT(setEnabled(bool)));
Нету? ок, создаем и добавляем. = gAction;
}
return Теперь есть в любом случае, возвращаем;
}
Имхо любая попытка оптимизации тут приведет лишь к лишним вызовам.
Через отдельную переменную? Ее ндо инициализировать элементом массива, а затем обратно положить в массив если NULL был.
Сделать проверку не на NULL а на contains(id) — в итоге три проверки вместо одной:
Пока что больше вариантов не вижу. Имхо у меня хоть и от двух до трех вызово тяжелых обсчетов, но это самый приемлемый вариант. Проще некуда.
Но предложения выслушаю.
Здравствуйте, Centaur, Вы писали:
C>Как раз самостоятельное удаление — это и есть стрельба себе по ногам. Потому что утечки будут всякий раз при возникновении необработанного исключения.
Необработанное исключение должно подразумевать окошко об ошибке и аварийное завершение программы. Этого у меня тоже, конечно, нет. Но с этой точки зрения утечки — фигня.
Если я правильно понимаю, в финальном мапе у тебя лежат указатели, и вызов m_actions[atype][id] имеет тип QAction*& (ссылка на указатель).
Поэтому надо ее просто закэшировать и дальше пользоваться этой ссылкой, и тогда у тебя будет всего один поиск по мапам:
Здравствуйте, Sheridan, Вы писали:
S>Здравствуйте, Igore, Вы писали:
I>>1) Не понравилась конвертация string->money,amount. Надо использовать QLocale::decimalPoint, S>Смысл запятую в точку преобразовать и поудалять все кроме чисел и точки. Зачем лишний вызов?
Замени разделитель в своей локали на другой, и посмотри как будет работать программа, собственно вариантов 2:
а) Используешь свою локаль устанавливая ее перед чтением записью данных
b) Используешь QLocale::decimalPoint
I>>5) При первом запуске программа не смогла поместится на экран, S>о0 15"?
Кхм, 2 монитора, 1-ый 24'', второй 19'', при первом запуске программа по ширине расползлась на 2 монитора. При закрытии программы не было сохранения позиций QWidget.saveGeometry()
I>>создавая доки используй tabifyDockWidget. S>А, понял. Возможно. Может mdi по умолчанию?
Сгруппируй элементы так чтобы пользователь запуская программу мог сразу работать, а не перетаскивать элементы под свое виденье.
Здравствуйте, Igore, Вы писали:
I>b) Используешь QLocale::decimalPoint qApp->keyboardInputLocale() — эту? Неоднозначно.
I>При закрытии программы не было сохранения позиций QWidget.saveGeometry()
Странно, должно быть, посмотрю...
I>Сгруппируй элементы так чтобы пользователь запуская программу мог сразу работать, а не перетаскивать элементы под свое виденье.
Ок, сейчас попробую...
Здравствуйте, Igore, Вы писали:
I>Кхм, 2 монитора, 1-ый 24'', второй 19'', при первом запуске программа по ширине расползлась на 2 монитора. При закрытии программы не было сохранения позиций QWidget.saveGeometry()
Ок, сделал такое. Но как то непонятно оно потом отрабатывает...
1й запуск — ок. Сохранило геометрию. 2й запуск — читаем геометрию — доклеты переколбашены в другом порядке о0
Здравствуйте, Sheridan, Вы писали:
C>>Как раз самостоятельное удаление — это и есть стрельба себе по ногам. Потому что утечки будут всякий раз при возникновении необработанного исключения. S>Необработанное исключение должно подразумевать окошко об ошибке и аварийное завершение программы. Этого у меня тоже, конечно, нет. Но с этой точки зрения утечки — фигня.
Ну это если совсем необработанное. Но может быть так, что в этой функции отрабатывает new, потом возникает исключение, delete не отрабатывает, исключение ловится где-то выше по стеку, программа продолжает работать с утекшим ресурсом.
Здравствуйте, Centaur, Вы писали:
C>Ну это если совсем необработанное. Но может быть так, что в этой функции отрабатывает new, потом возникает исключение, delete не отрабатывает, исключение ловится где-то выше по стеку, программа продолжает работать с утекшим ресурсом.
В любом случае это ошибка, и она требует исправления а не обработки.
Здравствуйте, Sheridan, Вы писали:
S>Здравствуйте, Igore, Вы писали:
I>>Зачем столько вспомогательных GUI классов? Чем стандартные не угодили? Писал бы на qml я бы еще понял, там с этим не всегда хорошо. S>Всмысле? Я беру стандартные и компоную из них нужные мне. Например кнопка с выпадающим списком-табличкой и индикацией выбранного на кнопке.
Я про:
class WImage : public QLabel
class WIcon : public ui::images::WImage, public hacc::CIDItem
class WIconButton : public ui::icons::WIcon // Какой это button, это clickLabel какой тоclass WControlLabel : public QLabel
class WLabelButton : public QLabel
class WStyledWidget : public QWidget
class DProgress : public QDialog// Есть QProgressDialog
Не увидел использования QTableView(QTableWidget) для отображения табличных данных, а это (сортировка, перетаскивание колонок, и т.д. из коробки)
Можно также использовать, QTableView + QItemDelegate::createEditor.
Здравствуйте, Sheridan, Вы писали:
C>>Ну это если совсем необработанное. Но может быть так, что в этой функции отрабатывает new, потом возникает исключение, delete не отрабатывает, исключение ловится где-то выше по стеку, программа продолжает работать с утекшим ресурсом.
S>В любом случае это ошибка, и она требует исправления а не обработки.
Не все исключения суть ошибки, и не все ошибки требуют исправления. В частности, ошибки пользовательского ввода, ошибки прав доступа, ошибки связи с внешними ресурсами могут обнаруживаться где-нибудь внутри, ловиться где-то выше, показываться пользователю — и на следующий виток главного цикла.
I>class WImage : public QLabel
I>class WIcon : public ui::images::WImage, public hacc::CIDItem
I>class WIconButton : public ui::icons::WIcon // Какой это button, это clickLabel какой то
I>class WControlLabel : public QLabel
I>class WLabelButton : public QLabel
I>class WStyledWidget : public QWidget
I>class DProgress : public QDialog// Есть QProgressDialog
I>
Стандартные меня не устраивали. Отнаследовался и реаоизовал нужное. Либо в планах реализовать.
I>Не увидел использования QTableView(QTableWidget) для отображения табличных данных, а это (сортировка, перетаскивание колонок, и т.д. из коробки)
В репе уже закомментировано, ибо действительно не нужно.
I>Можно также использовать, QTableView + QItemDelegate::createEditor.
Можно, но я не разобрался как мне повторить таблевьювом тот функционал, который я на плашках нарисовал
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, Sheridan, Вы писали:
C>>>Ну это если совсем необработанное. Но может быть так, что в этой функции отрабатывает new, потом возникает исключение, delete не отрабатывает, исключение ловится где-то выше по стеку, программа продолжает работать с утекшим ресурсом.
S>>В любом случае это ошибка, и она требует исправления а не обработки.
C>Не все исключения суть ошибки, и не все ошибки требуют исправления. В частности, ошибки пользовательского ввода, ошибки прав доступа, ошибки связи с внешними ресурсами могут обнаруживаться где-нибудь внутри, ловиться где-то выше, показываться пользователю — и на следующий виток главного цикла.
Верно. Но в данный момент мы разговариваем в контексте "создали объект, да фигня какаято творится". У меня там с этим либо все нормально, либо еще не доделал. В любом случае пользовательский ввод фильтровать конечно надо, ты прав. Но это как бы не на эксцепшенах принято делать... Хотя конечно варианты есть.
C>>Не все исключения суть ошибки, и не все ошибки требуют исправления. В частности, ошибки пользовательского ввода, ошибки прав доступа, ошибки связи с внешними ресурсами могут обнаруживаться где-нибудь внутри, ловиться где-то выше, показываться пользователю — и на следующий виток главного цикла. S>Верно. Но в данный момент мы разговариваем в контексте "создали объект, да фигня какаято творится". У меня там с этим либо все нормально, либо еще не доделал. В любом случае пользовательский ввод фильтровать конечно надо, ты прав. Но это как бы не на эксцепшенах принято делать... Хотя конечно варианты есть.
Пользователь попросил сделать что-нибудь с файлом, на который у него нет прав. На чём, как не на исключениях, это делать?
Здравствуйте, Centaur, Вы писали:
S>>Верно. Но в данный момент мы разговариваем в контексте "создали объект, да фигня какаято творится". У меня там с этим либо все нормально, либо еще не доделал. В любом случае пользовательский ввод фильтровать конечно надо, ты прав. Но это как бы не на эксцепшенах принято делать... Хотя конечно варианты есть.
C>Пользователь попросил сделать что-нибудь с файлом, на который у него нет прав. На чём, как не на исключениях, это делать?
Здравствуйте, Centaur, Вы писали:
C>Пользователь попросил сделать что-нибудь с файлом, на который у него нет прав. На чём, как не на исключениях, это делать?
В данном случае да, исключения пригодятся. И этот случай у меня обработан