Qt

Ненависти к Qt псто

А вот представим себе такое вот:

  • QGraphicsView и QGraphicsScene
  • Показываем картинку с каким-то увеличением, так что есть скроллбары (или только один)
  • И хотим показать следующую картинку "примерно так же" (в смысле относительного положения окна просмотра относительно всей картинки)
  • И хотим, чтобы когда мы вернулись к предыдущей - позиция сохранялась бы.
Нормальное желание, правда?

Ну вот казалось бы решение:

  • Рассчитать какая (относительная, в координатах 0-1) точка исходной картинки расположена в центре экрана.
  • Рассчитать далее, какая абсолютная точка следующей картинки должна быть в этом самом центре.
  • Дальше - view->centerOn()
Почти работает.

Почти - потому что есть скроллбары, они могут быть, они могут не быть, они могут быть у первой картинки, но не у второй (размеры другие) и наоборот. Скроллбары - меняют центр View (потому что занимают ширину).

И приходится нецензурно закатывать солнце вручную:

  • Если исходно скроллбар есть - запоминаем его относительную позицию (где у нас value() между minimum() и maximum()). Если нет - берем запомненную ранее, когда скроллбар был.
  • Дальше нужно посчитать, будет ли скроллбар при показе следующей (какой размер больше, картинки или viewport()
    • Если не будет, то скроллбар надо явно выключить, потому что если разница в несколько пикселов, то его может включить.
    • Если будет - то явно включить, доверять автоматике нельзя (бывает клево: view ставит скроллбары и зовет resizeEvent(). resizeEvent() знает, что режим у нас fit-to-screen и ресайзит картинку. view - видит что картинка поресайзилась, убирает скроллбары, зовет resizeEvent().....).
  • И если скроллбар будет - то явно ему поставить value (пересчитать из предыдущего относительного)
  • А если не будет - то припрятать относительное value до следующего раза, когда скроллбар появится.
Работает. Можно листать 10 картинок (разного размера и aspect ratio) вперед, потом назад - и вернуться ровно в ту точку/экранную позицию, с которой начинали.

Но, сука, 98 строк кода (считая пробелы). Вместо эдак 8-и, с которыми работает, но примерно.

Q: Qt 5.2 и Retina

Граждане разработчики,

Особенно использующие Qt, вы же тут читаете, я знаю.

Вот есть Qt 5.2 и Маки с ретиной. Надо, значит, чтобы было Щастье.

На самом деле, 99% Щастья есть сходу: если в Info.plist написан NSPrincipalClass, то все стандартные элементы (шрифты, к примеру) рендерятся в ретину и все работает.

Но.

У меня используется свой OpenGL-код, который зовется из QGraphicsScene::drawBackground(). Он, понятно, сходу рисует в четверти окошка в таком случае.

Эксперименты показали, что достаточно поменять одну строчку. Вместо:

glViewport(x,y,w,h);
написать
int dpr = painter->device()->devicePixelRatio();
glViewport(x*dpr,y*dpr,w*dpr,h*dpr);
И все начинает (вроде бы?) работать как надо. Зумится, ротейтится, сдвигается - все вроде как надо.

Так вот, вопрос: Что Я Делаю Не Так?. Не упускаю ли я что-то важное?

P.S. Рассматривание кода Qt-шных примеров не дало ответа. А именно: в части примеров делают именно так. И все работает. А вот в qtbase\examples\widgets\graphicsview\boxes - вообще нет никакого следа devicePixelRatio(), все каким-то чудом работает "само" (и ретина поддерживается нормально)

Про QThread

Несколько дней писал массогабаритный макет многопоточной программы на Qt с использованием QThread

Задача примерно такая: есть пул threads, туда снаружи поступает "задание", нужно выбрать подходящую (по некиим признакам) из простаивающих и скормить задание туда. Threads - долгоживущие, исполняют много заданий.

Имею сказать:

  • Классический способ с переопределением run(), сном там на QWaitCondition и передачей данных через отдельный вызов с блокировкой на QMutex - ужас. Очень жаль, что этот ужас до сих пор существует в документации. Насколько я понимаю, кстати, есть некоторый шанс пропустить очередное "задание на обработку" - если пока внутри run() работают работу, передача параметров случится несколько раз.
  • Описанный в документации же более правильный способ (он там описан первым) - еще более странный. Если обратили внимание, там есть workerThread в Worker, еще один workerThread в Controller и Worker передается в контроллерную workerThread ( worker->moveToThread(&workerThread);). Что этим хотели сказать - неясно.
  • Есть замечательный блог-пост You re doing it wrong , только как делать right - написано, на мой вкус, невнятно (а ссылка на старую запись - битая, впрочем вот верная, но и она помогает плохо.
  • О счастье, есть правильная идея (не в документации Qt): How To Really, Truly Use QThreads; The Full Explanation. Оно немножко недоделано под мой случай (т.к. предполагается, что Worker делает одну задачу и завершается), но в сочетании с вот этим текстом становится совсем хорошо (из последнего текста берем про QMetaObject::invokeMethod, чтобы не делать лишних connect(), которые нафиг не нужны).
Итого, приходим к следующему:

Узок их круг, страшно далеки они от народа

Вот берем Qt 5.1, тащим на Mac OS X 10.7 (так сложилось, это моя девелоперская машина), собираем согласно инструкции.

Далее собираем приложение с этой Qt, деплоим его тоже по инструкции, несем на Mac OS X 10.6 и получаем, получаем... сюрприз:
Неработающее приложение!

То что пишут в mailing lists я приличными словами назвать не могу.

Но только там, в этих рассылках, удается понять, что надо ./configure -no-c++11 и собирать без вебкита (впрочем, у меня деплоится без вебкита т.е. мог бы и с ним собирать). Если же не собирать, а брать готовые библиотеки с сайта Qt, то счастья и вовсе не будет.

И ладно бы речь шла о какой-то старой и никому не нужной версии Mac OS X. Гугление нашло такой вот график:

Взято отсюда, это, конечно, Апрель-2013, но я не думаю, что за 4 месяца что-то сильно поменялось (а у фотографов, по ощущениям, доля 10.6 еще выше). И я бы даже про 10.5 бы не забывал, если бы мог...

А, да, раньше в Qt-шном ./configure был ключик -no-webkit. Как вы думаете, как сейчас собрать Qt без вебкита?

Q: Qt MousePressEvent

Я пока не очень опытный Qt хакер, поэтому спрошу.

Вот есть QGraphicsView, у которого есть стандартная функциональность - можно по нажатию левой кнопки мыши скроллить это самое View (setDragMode(QGraphicsView::ScrollHandDrag)).

А теперь, допустим, я хочу делать то же самое не по левой кнопке, а еще по какой-то, скажем по Shift+правая кнопка.

Могу ли я сделать так:

class myView: public QGraphicsView {
  void mousePressEvent(QMouseEvent *e) {
      if(e->button() == Qt::RightButton && (e->modifiers() & Qt::ShiftModifier)) {
        QMouseEvent simulatedDrag(e->type(),e->pos(),e->globalPos(),Qt::LeftButton,
                                 Qt::LeftButton,Qt::NoModifier);
        QGraphicsView::mousePressEvent(&simulatedDrag);
        e->accept();
       }      
   }
};
(ну и аналогично с mouseReleaseEvent - проверить что отпустили нужную кнопку и фигануть симулированный эвент в базовый класс.

Вопрос: я что-то при этом сломаю?

Нет, я попробовал и вроде все работает, но вдруг я чего-то не заметил?

О синтаксическом сахаре

Есть у меня некий варез и в этом варезе настраивается клавиатурная раскладка (т.е. каждому действию можно сопоставить произвольный клавиатурный аккорд).

В потрохах редактора раскладок содержится примерно такой вот код (по смыслу):

// Инициализация
QKeySequence key; // Текущий shortcut
QPushButton *keybutton = new QPushButton(key.toStrin());
keybutton->setProperty("shortcut",key.toString());
..
// Обработка нажатой кнопки в слоте, который зовется по нажатию:
QObject *sender = QObject::sender();
QString shortcut = sender->property("shortcut").toString(); // Какую кнопку на самом деле нажали
И все работало прекрасно, пока я не решил сделать в этом же месте еще и обработку кнопок мыши, чтобы действие можно было бы назначить и на, к примеру, Ctrl-Shift-RightClick.

Меняем код немножко:

My_KeyOrMouse key; // My_KeyOrMouse - generic-контейнер для QKeySequence или мышиных событий
QPushButton *keybutton = new QPushButton(key.toString()); // Строковое представление есть
keybutton->setProperty("shortcut",key.toString());
..
// Обработка нажатой кнопки в слоте, который зовется по нажатию:
QObject *sender = QObject::sender();
QString shortcut = sender->property("shortcut").toString();
И тут начинаются чудеса: для кнопок все продолжает работать, а для мышиных кнопок - нет, sender->property(..).toString(); возвращает пустую строку.

Разгадка оказалась проста:

Немого кино уже нет, звукового кино еще нет....

Вот есть некая программа, которая активно использует OpenGL.

Используется Qt5 и все было бы хорошо, если бы не моментики:

  • QWidget::showFullScreen() не работает на Mac OS X 10.6
  • Курсор в форме руки - остается таковым и при выносе мыши за окно программы (тоже на Mac, на винде все нормально).
По первому случаю - я засабмитил баг, прямо вот 1-го января. Но он все еще в состоянии Not Evaluated (что неудивительно, если посмотреть на график количества багов в Qt за последние 30 дней). По второму - вроде нашел багрепорт, им как-то занимаются.

Ладно, у меня ничего специфического от Qt5 нету, собираем все то же самое на Qt 4.8.4. Работает (ну, пришлось поменять QOpenGLProgram на QGLProgram и так далее в том же духе, но изменений - мало).

Но:

На операционках, запущенных под VMWare (и Windows и Mac) - валится в QGLFunctions::initializeGLFunctions(), судя по отладчику - GL-контекст в этом месте нехорош, дальше не разбирался).

При этом, Qt5 на этих же виртуальных машинах - работает, возможностей тамошнего OpenGL вполне хватает.

На настоящих железных компьютерах с настоящим OpenGL - версия собранная с 4.8 - работает, а неприятные мне баги на маках - отсутствуют. Фулскрин работает, курсор меняет форму как надо.

Ну и как с ними жить? Баги Qt5 явно быстро не починят. Багу Qt 4.8 - скорее всего тоже не починят. Не, ну я могу gl....() сам порезолвить, но обидно же ж.

Хозяйке на заметку: Qt, OpenGL и PBO

В режиме записок: на этой проблеме впустую потерял дня два минимум, если не больше. Вот, чтобы никогда более, запишу.

Вот есть QGraphicsView, направленный в QGLWidget. Есть еще QGraphicsScene, у которой с помощью drawBackground() рисуем нужное нам (картинку).

Этот самый drawBackground() использует текстуры, одну или много, текстуры залиты через PBO.

Дальше - пытаюсь вывести на эту Scene другие объекты. Ну, как в документации написано, к примеру так:

QLabel *label = new QLabel("Bla-Bla");
scene->addWidget(label);
(ну чуть побольше кода, потому что прозрачность, возможность двигать, но смысл именно такой)

Результат:

  • Если объекты выводятся, окно открывается и т.п. до создания "моих" текстур (которые рисуются на фоне) - то все отлично.
  • Если все разлеглось так, что свои текстуры и PBO я создал до первого показа (даже не создания) объекта на Scene, то жопа, при добавлении элемента к сцене получаем такое:
    texture upload failed, error code 0x502
    
И так пробовал, и сяк и об косяк, потерял не меньше двух дней (ну то есть - не работает, пытаемся создать свой пример, там работает, из примера переносим код к себе - не работает и так с десяток раз). И, внезапно, ответ нашелся:

Если вы работали с QOpenGLBuffer, то прежде чем отдать управление в Qt - сделайте ему release(). Иначе будет нехорошо.

И ведь натыкался я уже на подобное, но с VBO: если не отцепить их, то вообще ничего не работает.

Об эффективном использовании современных CPU

Практика вот к этой презентации:

Берем 36Mpix файлик с D800, распаковываем егонный RAW в 16-битный однокомпонентный битмеп, дальше начинаем процессить.

Процессим без "интерполяции", т.е. 4 пикселя исходного байера образуют один выходной пиксель (режим half_size у LibRaw/dcraw). Получаем такие вот времена:

  1. LibRaw::dcraw_process() плюс формирование RGBA-битмепа: 420ms.
  2. Перепишем этот самый dcraw_process() на SSE3, процессить будем в плавучке (с эмуляцией особенностей dcraw), выдаем такой же 8-битный RGBA: 110ms (и более-менее понятно где еще выиграть миллисекунд 20).
  3. Добавим в предыдущий суп еще: подсчет RAW-гистограммы и сохранение исходного float-битмепа нетронутым (и без дублирования по памяти), т.е. баланс белого и конверсию цвета делаем два раза, один раз для подсчета гистограммы результирующего файла, а второй раз - прямо на вывод. 180ms.
Это все был один поток. Распараллелим его:
  1. "распараллеленный dcraw_process": 130ms (так в RawDigger сделано, тамошний RGB render устроен именно так, но гистограммы и статистика в эти 130ms не входят, равно как и битмеп для показа там готовится иначе и потому дольше).
  2. "распаралеленный ассемблерный dcraw_process": не делал, ожидаю <50ms (потому что вариант с двойным вычислением, как следующий, но без гистограмм - 57ms).
  3. параллельная ассемблерная версия с гистограммами, сохранением float RAW: 75ms
Сравнивая последний вариант с последовательным C-шным, нужно понимать, что в C-шном варианте еще где-то 200ms придется на гистограммы и еще 200 на конверсию int16 - float. То есть реальное ускорение от SSE и параллельной обработки - раз в 10 (75ms против 800). И это оптимизированный C-шный, в LibRaw это место заметно пооптимизировано в сравнении с исходным dcraw.

Минусы: потрачено изрядно времени (несколько дней), окончательного кода 25кб, а промежуточных вариантов было в разы больше. Ну и две баги ловились достаточно мучительно.

Qt+OpenGL benchmarking Q

А вот, я извиняюсь, такой вопрос.

Есть QGrahicsScene (унаследованное от нее) в которой я в drawBackround вывожу OpenGL-ем нечто.

В процессе разбирательств с OpenGL я это нечто имплементировал десятком разных способов и хочу теперь померять, какой из них быстрее.

Но как?

Ну то есть я сделал бенчмарковый вызов, который зумит (еще панорамирует, переключает нужные мне битмепы и т.п., не суть) в таком вот духе:

for(.....){
myview->setZoom(...);
QApplication::processEvents();
}

Но получается вот что:

  • FPS-ов ровно 60 (2000 итераций за 34 секунды), OGLFormat::setSwapInterval(0) не помог.
  • Одно ядро процессора полностью загружено.
  • По профайлеру, загружено оно QWindowsWindow::raise() (~70% по профайлеру), вообще весь прочий код занимает остальные 30% CPU, моего кода вовсе не видно.

Так слона не продать.

Ну то есть понятно, можно в OpenGL-рисовалке рисовать одно и то же 10 (100,1000) раз подряд, но вопрос заключается в том, нет ли более прямого пути, который позволяет Qt-GUI программы побенчмаркать попроще?

Update: если вдруг кому интересно, то проблема решилась глобальным выключением VSync в настройках драйвера (NVidia). FPS-ы сразу сильно выросли, а профайл исполнения стал похож на настоящий.

Про Qt и OpenGL

С помощью профайлера и отладчика узнал прекрасное.

Прекрасное, конечно же, описано в мануале, но кто же их читает:

QGLContext::DefaultBindOption LinearFilteringBindOption | InvertedYBindOption | MipmapBindOption In Qt 4.5 and earlier, bindTexture() would mirror the image and automatically generate mipmaps. This option helps preserve this default behavior.
А я все удивлялся, отчего у меня bindTexture для ~мегапиксельной картинки выполняется миллисекунд 20. Ну конечно, оно переворачивает изображение.

Оторвал. Стало быстрее раз в 10 минимум (на глазок, по профайлеру).

Из другого прекрасного:

  • Если использовать QOpenGLBuffer::bind() и потом, после рисования или заполнения, не сказать ему QOpenGLBuffer::release(), то в QGraphicsView/Scene отваливается отображение элементов, нарисованных стандартным путем (через addItem).
  • Если генерировать структуры руками (glBindTexture/glTexImage2D), но забыть про установку фильтрации, то текстура вовсе не отображается.
Как я уже писал, сколько же есть вещей, которые я предпочел бы не знать.

День прошел не зря.

OpenGL Qs

Сразу предупреждаю: с OpenGL я пытаюсь работать всего неделю (был еще подход к снаряду, но началось лето и я переключился на МонголиеКарелии), поэтому вопросы у меня, вероятно, глупые и вообще про разное.

Вопросов, собственно, три:

1. Допустим, у меня очень простая сцена, два треугольника, образуют прямоугольник, на них натягиваю текстуру (собственно, картинку, которую хочу показать).

Вопрос: есть ли смысл связываться с VBO или 6 пар вызовов glTexCoord2f()/glVertex2f() не будут заметно медленнее? А если прямоугольник не один, а, к примеру, 64 (картинка 8000x8000, а на предельный размер текстуры я заложусь как 1024x1024), будет ли заметный выигрыш, если загнать все в буфер(ы) и дергать рисование меняя только индексы?

Это мне больше для понимания, понятно что как только захочется что-то нарисовать шейдером, так сразу VBO понадобятся.

2. В Qt5 есть (старые) QGL*-объекты, есть новые QOpenGL*.

Кто бы рассказал, в чем разница....

3. Ну и вообще, Qt-шные примеры, что из комплекта, что найденные в сети, какие-то частично безумные. То слишком простые, то вроде простой - а шейдеры там внезапно "#version 330", то - очень хороший пример boxes из поставки - но переусложненный, начинаешь от него куски отпиливать и все разваливается.

Нет ли каких-то Qt-OpenGL tutorials, которые бы с одной стороны были бы "современными" (в смысле используемых Qt-интерфейсов), интересными (не банальный QGLWidget::paintGL()), но и не слишком сложными.

Про Qt5: книжки? примеры? руководства?

По случаю выхода Qt5 Beta2, хочу ею овладеть.

Причем, овладеть по-взрослому, по-мужски!

Ну то есть вот в RawDigger я утомился рисовать собственно GUI на C++, очень хочу делать это декларативно, в грубой форме, на Javascript-е. Особенно это касается всяких форм с большим количеством элементов, но и всего остального гуя - тоже.

Проблема только в том, что я совершенно не представляю себе, как это сделать. Ну то есть этот язык у меня в состоянии "читаю, что-то понимаю, сам написать не могу". При этом, понятно, одним QML+JS у меня никак не обойдется, какие-то core-вещи всяко на C++, а дальше как-то с ними интегрироваться.

Вопрос: а есть ли какие-то систематические источники информации. В свое время пара книжек по Qt4 мне очень помогли. Я их не читал, но пролистал и многое - осознал. Хочу такого же, но для Qt5+QML2. Или не такого же, другого. Каких-то писучих блоггеров, которые про Qt5 пишут, может быть какие-то живые проекты, не знаю. Посоветуйте.

RawDigger для Mac - вторая альфа

Прошу любить, жаловать и скачивать отсюда.

По традиции, расширенно комментирую Changelog:

  • 64/32 бита. Протестирована на 10.5 (32 bit),10.6 (64bit) и 10.7 (64bit), может быть работает и на интеловской 10.4

    Надо сказать, что для удержания дистрибутива в приемлемом размере пришлось пересобрать Qt в урезанном варианте (без Webkit, QDeclarative и много чего еще). Иначе размер .app моментально раздувало до 75M, а это уже перебор.

    macdeployqt можно попросить не копировать лишнего (-no-plugins), но тогда оно не копирует плагины (сюрприз!), а не только QWebKit и прочих. А без плагинов - кой-чего отваливается и программа крэшится, ага.

  • Поправлены размеры шрифтов и контролов в ряде мест (и где были слишком крупные, и где были слишком мелкие).

    Отдельное спасибо за совет с Qt::WA_MacMiniSize. Выглядит не очень, ну так QGroupBox на маке в любом случае выглядит так себе.

  • Добавлено место на правом краю гистограммы, где 5 цифр не влезало
  • Поправлены верхние информационные окошки, все цифры должны (бы) быть видны
  • Работает Drag-n-Drop на иконку приложения (за исключением дропа прямо на образ дистрибутивного диска, где работать и не должен).

    Про это напишу особо ниже.

  • Если About-диалог открыт сразу после запуска программы, то он не закрывается самопроизвольно через несколько секунд.
Так вот, теперь про маковский Drag-n-Drop.

Про Look and Feel

Пользователи мак-версии RawDigger вероятно заметили уже, что окошко гистограмм очень широкое.

А широкое оно оттого, что контролов много. Окну же сказано уменьшаться только до тех пор, пока все контролы видны.

А вот как это отрисовывает Qt под разными ОС (окно завернуто в минимальную ширину):

По клику откроется полный размер.

Сверху вниз:
  • Mac Native (и такой spacing так и задуман) - ширина окна 1088 пикселов и меньше не делается.
  • Результат применения setStyle(QStyleFactory::create("windows")); - 908 пикселов, на 20% меньше.
  • Win7 Native (без каких-то настроек spacing) - 821 пиксел, еще на 10% меньше.
Эксперимент не полностью чистый: маковский десктоп 1920x1200 и никаких настроек шрифтов не делалось, на винде шрифты увеличены (115%), а разрешение монитора 2560x1600. В полностью одинаковых условиях винды, скорее всего, будут еще компактнее (пробовать страшно, потрогав размер шрифта у винды есть риск обратно не вернуться).

Родной маковский выглядит просторнее, но вот в редких случаях хотелось бы иметь возможность сделать все плотненько. Но разумным способом - никак (можно выписать свой StyleSheet, но хочется то бе этого). Имею сказать, что виндового размера контролов лично мне на маке очень не хватает.

Update: Добрые люди подсказали про Qt::WA_MacMiniSize. Результат - 859 пикселов ширины. Чуть хуже винды, но непринципиально. Хотя, конечно, спинбоксы по мне выглядят чуть мелковато.

Qt+Xcode = !

По следам вот этой записи:

Changes 4.8.1 (Qt):

.....
Qt for Mac OS X
....
- Add support for XCode 4 into qmake [QTBUG-17247]
...

Похоже, мой блог читают :)

Update: переваливается через борт и сразу тонет все одно не работает. Примерно то же говно, что и было раньше.

Картинка дня

Кто не понял про что это - смотрите теги :)

Qt - рулит. Ну то есть я не разобрался (пока?) с динамическими библиотеками, Frameworks и прочими страшными словами, поэтому с LibRaw слинковался статикой.

Ну, естественно, повылезало всякого, но умеренно:

Qt: крик души

Как-то я привык, что в Qt есть все, что нужно разумному человеку, но жизнь оказалась богаче.

Представим себе какой-то обычный GUI(Windows)-диалог с настройками. Там галочки, пимпочки, выпадающие списки, общим числом с полсотни-сотню, например (5 табов по 10-15 параметров, так и получится).

Ну, понятно, по OK значения в программе апдейтятся, по Cancel - остаются как были, а значит нужен какой-то backing store и в Qt для этого есть, вроде как, Q_PROPERTY.

Сам диалог мы берем и рисуем за 5 минут (или больше, если 5 табов) в Qt Designer. И нам даже породят код для его генерации (главное в этот код не смотреть!) и будут этот код апдейтить если мы что-то передизайнили. Или даже возьмем QUILoader и код не нужен, нарисуем форму динамически, взяв ui-файл из ресурсов.

А вот дальше начинается сущее мучение:

  • Для каждого элемента надо написать Q_PROPERTY(..) (можно и без нее, но сохранение-чтение с пропертями проще).
  • Для каждой проперти - getter/setter ну и саму переменную для стораджа.
  • Значения надо проинициализировать (в конструкторе). Готового механизма "списком" (key-value) нет. Ну, есть полуготовый, можно QMap<QVariant>, но тоже ничего хорошего.
  • Нужно элемент диалога инициализировать из проперти перед показом диалога; нужно значение проперти обновлять, если в диалоге было нажато ОК.
  • Нужен какой-то механизм сохранения значений/восстановления (внешнее хранение настроек). Опять, детали механизма есть, а готового - нет.
И так - 75 (или сколько там настроек) раз. Ну то есть сериализацию/десериализацию можно циклом, затем и Q_PROPERTY, а все остальное - ручками.

Или не ручками, скажите мне, что я пропустил что-то в Qt!!!

Нет, я понимаю, что цивилизованный мир сажает на эту работу индуса (а нецивилизованный - студента), тот легко напишет 75 геттеров-сеттеров методом Copy-Paste, по 750 штук в день. Но ведь не может быть, чтобы это место не было уже автоматизировано в Qt?

Про UI

А вот, к примеру, есть такое вот окошко настроек у какой-то программы ([Preview] - это потому что в Qt Designer, не обращайте внимания):

Ну то есть пользователь может выбрать, что сохранять настройки между запусками программы он хочет (или не хочет).

Но тут есть такой логический перескок: допустим, галка в какой-то момент была поставлена и настройки на выходе программы - сохранились. Вместе с этой галкой, естественно. Потом пользователю надоело и он эту галку снял. Дальше происходит следущее:

  • На выходе - настройки не сохраняются (галка снята).
  • На новом запуске - поднимаются старые настройки.
  • В старых настройках галка "сохранять на выходе" - опять поставлена. Потому что только так, на выходе программы, настройки попадают в сохраненное место.

Кто виноват и что делать? Я вижу такой вот, не вполне тривиальный алгоритм:

  1. Если галка "сохранять на выходе" была снята, то по нажатию ОК мы идем в сохраненные настройки и сохраняем там только состояние этой галки, более ничего не меняем.
  2. Нужно добавить отдельную кнопку Save Settings, которая сохраняла бы текущее положение кнопок (т.е. можно поиграть настройками, нажать Save, потом Cancel - сохраненная копия обновится, а рабочая - нет)
  3. Поставить галку "сохранять на выходе", нажать Save, снять галку, нажать OK - приведет к тому, что в сохраненной копии настроек "сохранять на выходе" станет Off.
Конечно, есть еще вариант, когда галки этой нет, а настройки сохраняются всегда (прямо по нажатию кнопки OK), но он неинтересный.

QT/MVC

А зря меня пугали Qt-шным QModelIndex и вообще тамошним MVC.

Оно там чумовое, очень удобное, логичное и вообще мне нравится.

То есть, конечно, вся иерархия немножко перетяжеленная, но примеров из Advanced Qt Programming вполне достаточно, даже соответствующие главы из книжки можно целиком не читать.

Pages

Subscribe to Qt