Просмотр сообщений
|
Страниц: [1] 2 3 ... 57
|
2
|
Qt / Model-View (MV) / Re: не работает QAbstractTableModel::index()
|
: Февраль 03, 2017, 21:46
|
Вы можете в своей модели сделать сигнал beforeInsertRows( row, col, QVariant& data ) Этот сигнал связывать со слотом приложения, где будут доступны и эта модель и модель с теми данными, которые нужны для вставки в эту модель. Тогда модели друг о друге не знают, глобальных переменных нет но они могут использовать данные друг друга при необходимости.
|
|
|
3
|
Qt / Вопросы новичков / Re: QT База данных отчет (reports)
|
: Февраль 02, 2017, 19:34
|
Правильно ли я понимаю, что по вашему мнению все кто пользуются генераторами отчетов идиоты ?
Нет не правильно, если бы идиотизмом занимались только идиоты, жизнь была бы куда рациональнее. И это тоже мое мнение. И я думаю оно к истине близко. И нет желания что-то тут мусолить больше. Иди в болталку - открой тему Виндовс против Линукс или что-то в этом духе - и отжирайся там. А модератора прошу почистить этот срам.
|
|
|
4
|
Qt / Вопросы новичков / Re: QT База данных отчет (reports)
|
: Февраль 02, 2017, 19:22
|
Я это написал это не для кармы Улыбающийся Просто ваша формулировка IMHO была несколько некорректной. +1 сообщение к твоей карме ))))) +1 несодержательное и захламляющее тему - давай тролль жги!!!!!! А модератор пусть удалит это все) P.S.: Моя формлуировка IMHO - ну не может быть некорректной, т.к. это мое видение ситуации.
|
|
|
6
|
Qt / Вопросы новичков / Re: QT База данных отчет (reports)
|
: Февраль 02, 2017, 18:29
|
На мой взгляд все эти убогие генераторы отчетов с собственными редакторами - идиотизм.
Идиотизм - считать, что обладаешь абсолютным знанием и знаешь единственно верное решение. Ты если читаешь - читай внимательно, тролль, набивающий карму счетчиком сообщений. - Если написано "На мой взгляд" - это уже никак не претендует на абсолютное знание. Да и вообще пошел отсюда толстый. )))
|
|
|
7
|
Qt / Вопросы новичков / Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
|
: Февраль 02, 2017, 18:26
|
У QTreeView есть опция, ставится прямо в дизайнере rootIsDecorated. Но иногда она не решает всех проблем, например, если надо, чтобы были соседние ветки корневыми, тогда в БД или другой древовидной модели заводится еще один рут, а опция ставится в true.
По узлам у которых нет родителей - возможно прийдется править модель, быстро с ходу не скажу, это просто абстракция, мне кажется во всех таких случая проще, чтобы у них был один общий родитель - самый верхний рут, который показывать или нет уже определяем через эту опцию. Иначе надо будет реализовывать оосбенное поведение для ветвей без родителей, что может и не очень сложно, но будет не сразу понятно в коде.
|
|
|
11
|
Qt / Вопросы новичков / Re: QT База данных отчет (reports)
|
: Февраль 01, 2017, 16:15
|
Да мы вроде все тут с юзерами работаем. Вот в том и дело, что юзеру проще открыть документ в редакторе похожем на ворд и там поправить что-то, чем осваивать неудобные редакторы шаблонов для отчетов с их бендами и скрытой логикой, которую может понять только программист.
Я очень много в Делфи работал с ФастРепорт, вижу что и сейчас тенденция использования таких систем генерации отчетов сохранена. Когда уже в конец надоело работать с этим г.., перешел на простой компонент, который делал отчеты на базе шаблонов из РТФ - и просто в шоке был от такого насколько жизнь может быть проще.
Я даже для Qt сначала сделал генерацию из RTF шаблона, но там когда дело касается таблиц возникают необнозначности при парсинге самого RTF, формат построен таким образом, что предполагалось его парсить прямо на лету переводя команды из документа в команды курсора. И HTML в связке с QTextDocument оказался очень быстрым и удобным решением, который можно перевести в любые форматы.
|
|
|
12
|
Qt / Вопросы новичков / Re: Множественное подключение к БД
|
: Февраль 01, 2017, 02:25
|
QSqlDatabase является синглтоном, поэтому при правильном подходе у тебя будет одно пподключение.
Справедливости ради - не является QSqlDatabase is a value class. Changes made to a database connection via one instance of QSqlDatabase will affect other instances of QSqlDatabase that represent the same connection. Use cloneDatabase() to create an independent database connection based on an existing one.
То есть если нужен функционал QSqlDatabase можно его смело создавать в том месте где это надо и работать с ним, он лишь представляет переменную объект для работы с бд. Внутри ссылается на те же данные, что и другие QSqlDatabase с таким же именем подключения. Для нескольких подключений (к разным бд например) соответственно просто используются разные имена подключений.
|
|
|
13
|
Qt / Вопросы новичков / Re: QT База данных отчет (reports)
|
: Февраль 01, 2017, 02:10
|
Может создать форму, внутри отображение html теги, для вывода данных. как вы решаете проблему.
Самый распространенный вариант решения - html. QTextDocument + QTextEdit. Или QWebView. Можно напрямую формировать отчет работая с Excel, Word, OO, LO. Вариантов дохрена. Согласен, самый простой вариант сделать генератор отчетов на базе HTML c шаблонами. На мой взгляд все эти убогие генераторы отчетов с собственными редакторами - идиотизм. Можно сделать и простой редактор для отчетов - буквально пару кнопок добавить в кт-пример, для реализации вставки таблиц и объединения ячеек. Ниже простой пример генератора отчетов, рабочий. Читается шаблон, есть методы для замены в шаблоне текстовых переменных, заполнения таблиц из контейнера или из другой модели. Функционал можно наращивать под потребности бесконечно и главное легко. Шаблон отчета всегда можно просмотреть глазами и сторонними редакторами т.к. это HTML. Его может быстро подправить любой человек (не программист) - например исправить грамматические ошибки или сделать аналог на другом языке. Средствами Qt сразу работает как документ ODF или HTML. #pragma once
#include <QString> #include <QTextDocument> #include <QTextCursor> #include <QAbstractItemModel>
class CReportMaker { private: QString m_sOfficePath; QString m_sBrowserPath; QString m_sReportPath; // Instance static CReportMaker * s_pInstance;
public: enum exportFileType { eftHTML, eftODT, eftCount }; typedef QHash<QString, QVariant> TableRowDesc;
QString eftToString( exportFileType eftVal ); QString appByEFT( exportFileType eftVal );
// Instance inline static CReportMaker * instance() { return s_pInstance; }
CReportMaker(); ~CReportMaker();
bool loadReportTemplate( QTextDocument& textDoc, const QString& sFName );
void doSimpleReplacement( QTextDocument& textDoc, QHash<QString, QVariant>& simpleReplacement ); void doTableReplacement(QTextDocument& textDoc, const QString &sTableName, QVector<TableRowDesc> tableReplacement ); void doTableReplacement(QTextDocument& textDoc, const QString &sTableName, const QAbstractItemModel& model );
void saveAndOpen( const QTextDocument& textDoc, exportFileType eftVal, const QString& sFName ); };
// Shortcuts inline CReportMaker * reportMaker() { return CReportMaker::instance(); }
#include "ReportMaker.h"
#include "FileUtils.h" #include "SettingsManager.h" #include <QTextDocumentWriter> #include <QProcess> #include <QTextCodec> #include <QTextTable> #include <QDebug> #include <StringUtils.h>
CReportMaker * CReportMaker::s_pInstance = 0;
QString CReportMaker::eftToString(CReportMaker::exportFileType eftVal) { static const QString eftStrings[ eftCount ] = { "html", "odt" }; return eftStrings[ eftVal ]; }
QString CReportMaker::appByEFT(CReportMaker::exportFileType eftVal) { switch ( eftVal ) { case eftHTML: return m_sBrowserPath; case eftODT: return m_sOfficePath; default: return ""; } }
CReportMaker::CReportMaker() { Q_ASSERT( !s_pInstance );
// Save instance pointer s_pInstance = this;
// ********************************************** CXmlSettings * pXml = settingsManager()->xml(); pXml->beginGroup("report_settings"); m_sOfficePath = pXml->value( "OfficeProgram", "libreoffice" ).toString(); m_sBrowserPath = pXml->value( "BrowserProgram", "firefox" ).toString(); m_sReportPath = pXml->value( "ReportPath", dataPath() + "Reports/" ).toString(); pXml->endGroup(); }
CReportMaker::~CReportMaker() { Q_ASSERT( s_pInstance ); s_pInstance = 0; }
bool CReportMaker::loadReportTemplate( QTextDocument &textDoc, const QString &sFName) { if ( !QFile::exists( sFName ) ) { qCritical() << "File not found:" << sFName; return false; }
QFile file( sFName ); if ( !file.open(QFile::ReadOnly) ) { qCritical() << "Failed to report open file:" << sFName; return false; }
QByteArray data = file.readAll();
QTextCodec *codec = Qt::codecForHtml(data); QString str = codec->toUnicode(data);
if ( !Qt::mightBeRichText(str) ) { qCritical() << "Failed to parse HTML report file:" << sFName; return false; }
textDoc.setHtml( str );
return true; }
void CReportMaker::doSimpleReplacement( QTextDocument &textDoc, QHash<QString, QVariant>& simpleReplacement) { QHashIterator<QString, QVariant> i(simpleReplacement); while ( i.hasNext() ) { i.next(); QString sLetter = i.key(); QVariant val = i.value();
QTextCursor cur = textDoc.find( sLetter ); while ( !cur.isNull() ) { QTextCharFormat cfmt = cur.charFormat(); cur.deleteChar(); cur.setBlockCharFormat( cfmt ); cur.insertText( val.toString() ); cur = textDoc.find( sLetter, cur ); } } }
void CReportMaker::doTableReplacement( QTextDocument &textDoc, const QString& sTableName, QVector<CReportMaker::TableRowDesc> tableReplacement) { QTextCursor cur = textDoc.find( sTableName ); if ( !cur.isNull() ) { QTextCharFormat cfmt = cur.charFormat(); cur.deleteChar(); cur.setBlockCharFormat( cfmt ); while ( !cur.currentTable() ) cur.movePosition( QTextCursor::Right );
QTextTable * pTable = cur.currentTable();
// заполняем ассоциацию имен колонок к их номерам, в последней строке таблицы должны в ячейках быть только имена выводимых колонок QHash<int, QString> fieldByColumn; QHash<int, QTextCharFormat> cfmtByColumn; int nLastRow = pTable->rows()-1; for ( int nCol = 0; nCol < pTable->columns(); ++nCol ) { QTextCursor curStartCell = pTable->cellAt( nLastRow, nCol ).firstCursorPosition(); curStartCell.select( QTextCursor::WordUnderCursor ); fieldByColumn.insert( nCol, curStartCell.selectedText() ); cfmtByColumn.insert( nCol, curStartCell.charFormat() ); }
pTable->removeRows( nLastRow, 1 );
for ( int i = 0; i < tableReplacement.count(); ++i ) { pTable->appendRows( 1 );
TableRowDesc row = tableReplacement.at( i );
int nLastRow = pTable->rows()-1; for ( int nCol = 0; nCol < pTable->columns(); ++nCol ) { QTextCursor cur = pTable->cellAt( nLastRow, nCol ).firstCursorPosition();
// Для этого поля не был запомнен номер колонки ( не была указана колонка с таким именем в первой строке таблицы шаблона ) if ( !fieldByColumn.contains( nCol ) ) continue;
QString sText = row.value( fieldByColumn.value( nCol ) ).toString(); cur.setBlockCharFormat( cfmtByColumn.value( nCol ) ); cur.insertText( sText ); } } } }
void CReportMaker::doTableReplacement(QTextDocument &textDoc, const QString &sTableName, const QAbstractItemModel &model) { QTextCharFormat defaultFormat; defaultFormat.setFontPointSize(12);
QTextCharFormat headerFormat; headerFormat.setFontPointSize(12); headerFormat.setFontWeight(QFont::Bold);
QTextTableFormat tableFormat; tableFormat.setCellPadding(2.0); tableFormat.setHeaderRowCount(1); tableFormat.setBorderStyle( QTextFrameFormat::BorderStyle_Solid ); tableFormat.setBorderBrush( Qt::black ); tableFormat.setWidth( 10 );
QVector<QTextLength> constraints; constraints << QTextLength() << QTextLength() << QTextLength(); tableFormat .setColumnWidthConstraints(constraints); tableFormat .setWidth(QTextLength(QTextLength::PercentageLength, 100));
QTextCursor cur = textDoc.find( sTableName ); if ( !cur.isNull() ) { QTextCharFormat cfmt = cur.charFormat(); cur.deleteChar(); cur.setBlockCharFormat( cfmt );
cur.insertTable(1, model.columnCount(), tableFormat);
// заголовок таблицы for ( int i=0; i < model.columnCount(); ++i ) { cur.insertText( model.headerData(i, Qt::Horizontal).toString(), headerFormat ); cur.movePosition(QTextCursor::NextCell); }
// таблица for (int row = 0; row < model.rowCount(); ++row) { cur.currentTable()->appendRows(1); cur.movePosition( QTextCursor::PreviousRow ); cur.movePosition( QTextCursor::NextCell );
for ( int col=0; col < model.columnCount(); ++col ) {
QVariant vVal = model.data( model.index(row, col) );
QString sVal = VariantToStringIFDT( vVal );
cur.insertText( sVal, defaultFormat ); cur.movePosition( QTextCursor::NextCell ); } } } }
void CReportMaker::saveAndOpen(const QTextDocument &textDoc, CReportMaker::exportFileType eftVal, const QString &sFName) { // создаем папку для отчетов если ее не было QDir dir( m_sReportPath ); if ( !dir.exists() ) dir.mkpath( m_sReportPath );
QString fileName = m_sReportPath + sFName + "." + eftToString( eftVal );
QTextDocumentWriter writer(fileName); //writer.setFormat("HTML"); // по непонятной причине вызов не требуется writer.write(&textDoc);
QStringList args; args << fileName;
QProcess * app = new QProcess; app->start( appByEFT( eftVal ), args); }
|
|
|
14
|
Qt / Вопросы новичков / Re: Из SqlQueryModel через QAbstractProxyModel в деревянную модель? Нет сил
|
: Февраль 01, 2017, 01:17
|
Да, это делается наследованием от QStandardItemModel или даже AbstractItemModel, кроме того для каждого итема будет маленькая обертка ItemProxy, которая будет связью между данными в ветке дерева и самой моделью, которая является интерфейсом QT. Соответственно будут методы для перехода от индекса к элементу прокси и наоборот, они будут нужны например при реализации метода data - да и всех остальных.
Во вложении кидаю свою модель, но она работает с моими компонентами БД, я выкинул модуль QtSql у себя, т.к. он не имеет нормальной поддержки транзакций. Если приложите усилия, то сможете адаптировать под любые свои цели или взять как пример. Смысл думаю там понятен будет. По возможности на вопросы готов отвечать.
|
|
|
15
|
Разное / Говорилка / Re: Все программеры на дельфях такие неадекватные?
|
: Январь 21, 2017, 18:22
|
Думаю, это не так. И про средний уровень, и про C++. Паскаль - разрабатывался как учебный язык, и его популярность объясняется только количеством книжек, изданных в это время. Средний уровень тоже определяется этим. Думаю это так. Паскаль удобен для обучения т.к. лишает программиста на начальном уровне лишних возможностей управления памятью и оптимизацией (за которую и в С++ некоторым надо руки отрубать), в то же время там есть и стек и куча и нормальные указатели - там вообще есть практически все, что нужно для большинства задач. Его нераспространенность определяется в первую очередь отсутствием компиляторов под всевозможные платформы как это есть для С и С++, что сложилось исторически. Синтаксис его сложнее, чем C (слишком много букв), синтаксис не определяется количеством букв, для меня нет разницы чем ограничена область видимости - begin и end-ом или фигурными скобками - суть одна - абсолютно. Более того begin и end лучше читаются глазами и их даже сложнее пропустить в сложном запутанном коде. перейти с него на C или C++ сложно, я бы сказал, невозможно, как с бэйсика Я в свое время перешел без проблем и знаю еще 2 десятка программистов, которые перешли. А еще знаю людей которые изначально писали под С для микроконтроллеров, но их код откровенное говно и этих людей вообще сложно назвать программистами, т.к. они не знают и не умеют пользоваться основами, которые знают даже студенты вузов. Хорошим примером могут служить бесконечные любительские разработки под ардуино и подобные проекты, когда видишь такие исходники то и приходит на ум что людям стоило бы понять основы программирования прежде чем ляпать свои варианты решения, и Паскаль тут отлично бы подошел. Одна точка в конце программы чего стоит ничего не стоит - в чем с ней трудности?
|
|
|
|
|