Есть Qt widget-based приложение, хочется сделать красивый UI.
Порылся в интернете нашел файл со стилями которую хочу взять за основу.
Но столкнулся вот с такой проблемой:
Так как виджетов в приложении создается много, то наблюдается такая штука, если применять стили, например так:
app.exe -stylesheet=darkorange.stylesheet
то приложение начинает оочень долго запускаться.
Если я правильно понимаю что происходит, то происходит компиляция стиля для каждого виджета отдельно, отсюда и тормоза.
Вопрос, можно ли как это это ускорить?
Например написанием своего наследника QStyle, подумал так потому что например есть станадртные стили которые можно выставить например так:
Здравствуйте, nen777w, Вы писали:
N>Вообще очень интересно эти две штуки QSS и QStyle они взаимозаменяемы, или дополняют друг друга?
В основе стилей всегда лежит класс QStyle, даже если стиль описан с помощью QSS (QStyleSheetStyle). В свою очередь любой объект стиля можно проксировать (QProxyStyle).
Следовательно они дополняют друг друга, но тут есть одно "НО": реализация QStyleSheetStyle не идеальна для "скрещивания" с другими объектами стилей — не всегда получается ожидаемое
Да и когда все виджеты в приложении отрисовываются через QSS отрисовка заметно приседает, очень показателен resize'инг окна.
N>Если я правильно понимаю что происходит, то происходит компиляция стиля для каждого виджета отдельно, отсюда и тормоза.
Объект стиля установленный приложению устанавливается всем виджетам этого приложения — никакой дополнительной "компиляции" не происходит.
Тут дело может быть в следующем методе:
static void updateWidgets(const QList<const QWidget *>& widgets)
{
if (!styleSheetCaches->styleRulesCache.isEmpty() || !styleSheetCaches->hasStyleRuleCache.isEmpty() || !styleSheetCaches->renderRulesCache.isEmpty()) {
for (int i = 0; i < widgets.size(); ++i) {
const QWidget *widget = widgets.at(i);
styleSheetCaches->styleRulesCache.remove(widget);
styleSheetCaches->hasStyleRuleCache.remove(widget);
styleSheetCaches->renderRulesCache.remove(widget);
}
}
for (int i = 0; i < widgets.size(); ++i) {
QWidget *widget = const_cast<QWidget *>(widgets.at(i));
if (widget == 0)
continue;
widget->style()->polish(widget);
QEvent event(QEvent::StyleChange);
QApplication::sendEvent(widget, &event);
widget->update();
widget->updateGeometry();
}
}
Который вызывается для каждого виджета "знакомящегося" со стилем:
N>Вопрос, можно ли как это это ускорить?
Написание собственного класса стиля будет идеальным решением, тем более что нет необходимости реализовывать все с нуля:
наследуемся от какого либо класса из стандартных стилей и корректируем отображение нужных элементов под себя — благо все методы виртуальны и исходники (как образец) всегда под рукой
N>>Вопрос, можно ли как это это ускорить? __>Написание собственного класса стиля будет идеальным решением, тем более что нет необходимости реализовывать все с нуля: __>наследуемся от какого либо класса из стандартных стилей и корректируем отображение нужных элементов под себя — благо все методы виртуальны и исходники (как образец) всегда под рукой
Спасибо за развернутый ответ. Т.е. если я понял правильно нужно унаследоваться от QProxyStyle и вперёд писать свой стиль.
Не скромный вопрос... а есть ли где то что то уже готовое? Я нашел пример в доке, и вроде бы ничего такого сложного, но всё же взять что то готовое и допилить до своих нужд, проще чем писать все с 0-я.
Здравствуйте, nen777w, Вы писали:
N>Есть Qt widget-based приложение, хочется сделать красивый UI.
N>то приложение начинает оочень долго запускаться. N>Если я правильно понимаю что происходит, то происходит компиляция стиля для каждого виджета отдельно, отсюда и тормоза.
N>QApplication::setStyle(QStyleFactory::create("plastique")); N>[/ccode]
N>Вообще очень интересно эти две штуки QSS и QStyle они взаимозаменяемы, или дополняют друг друга?
Тут хотелось бы отметить что:
— установив stylesheet родительскому виджету этот стиль так же используется и в дочернем как база;
— задавая стиль виджету через QSS (свойство stylesheet) создается новый объект стиля QStyleSheetStyle который проксирует стиль уже имеющийся у виджета.
Таким макаром как мне представляется можно нагородить кучу не быстрых объектов класса QStyleSheetStyle которые будут так или иначе использоваться при отрисовки одного виджета (хотя тут я не уверен на все 100).
Здравствуйте, nen777w, Вы писали:
N>Спасибо за развернутый ответ. Т.е. если я понял правильно нужно унаследоваться от QProxyStyle и вперёд писать свой стиль.
Если ограничиться какими то простыми вещами — да, проксирование это то что нада.
Если речь идет о собственном представлении комбинированного контрола то тут уже может быть придется писать свой стиль.
N>Не скромный вопрос... а есть ли где то что то уже готовое? Я нашел пример в доке, и вроде бы ничего такого сложного, но всё же взять что то готовое и допилить до своих нужд, проще чем писать все с 0-я.
Если найдете готовые решения стилей буду рад ссылке (думается мне что такие вещи в нете не валяются)
В проксировании ещё кроется один подвох:
— стиль с которым связали проксирующий "знает" об этом;
— знать стить может только об одном проксирующем стиле.
Установив стиль приложению он будет использоваться для всех виджетов.
Следовательно: установив один проксирующий стиль скажем для QLineEdit, а другой проксирующий стиль для QComboBox (с поддержкой ввода) — отображение QLineEdit будет другим.
И ещё, QSS (да и сами виджеты) в плане кастомизации — вещь очень ограниченная в плане анимации интерфейсов. В лучшем случае у вас будет несколько состояний (normal/hover/pressed и т.п.) — и для них свои стили, между которыми и будет проходить переключение. А вот задать анимацию переключения через QSS не получится (как, например, "плавно" подсвечивается стандартная виндовая кнопка при наведении мыши).
Я как-то пробовал добиться похожего поведения через комбинирование QSS и QProxyStyle, но это получалось жуткое костылестроение. А реализовывать свою полноценную систему стилей (переопределяя QStyle) с реализацией анимации — достаточно сложно.
SaZ>И ещё, QSS (да и сами виджеты) в плане кастомизации — вещь очень ограниченная в плане анимации интерфейсов. В лучшем случае у вас будет несколько состояний (normal/hover/pressed и т.п.) — и для них свои стили, между которыми и будет проходить переключение. А вот задать анимацию переключения через QSS не получится (как, например, "плавно" подсвечивается стандартная виндовая кнопка при наведении мыши). SaZ>Я как-то пробовал добиться похожего поведения через комбинирование QSS и QProxyStyle, но это получалось жуткое костылестроение. А реализовывать свою полноценную систему стилей (переопределяя QStyle) с реализацией анимации — достаточно сложно.
Да мне я думаю не нужно анимаций.
Хочется добиться что бы приложение выглядело как Photoshop.
Помоему и UI некоторых продуктов Adobe на Qt сделан?
Здравствуйте, nen777w, Вы писали:
N>Да мне я думаю не нужно анимаций. N>Хочется добиться что бы приложение выглядело как Photoshop. N>Помоему и UI некоторых продуктов Adobe на Qt сделан?
Я когда-то писал вот эту прогу. Там кастомизации через QSS ну очень много. Программа маленкая, но было замечено следующее:
— Любые градиентные фоны долго рисуются. Особенно при изменении размеров окна.
— Возможности кастомизации tab контрола очень ограниченные.
— Периодические проблемы с подгонкой размеров контролов. Лэйауты вели себя далеко не всегда так, как задумано.
— Достаточно сложно оказалось побороть баг в Qt.
— Иерархию стилей / структуру именования контролов нужно сразу продумывать очень тщательно. Возможно, не стоит пихать все стили в один файл.
— QStyle::drawControl работает далеко не всегда.
— QGroupBox кастомизируется очень неадекватно. Нужно много плясать с margin/padding.
Небольшие хинты, которые мне помогли:
— Если стиль завязан на какой-либо property, то чтобы контрол конкретно обновлял свои стили, то нужно дёргать polish()+unpolish().
— Если виджет лежит в неймспейте, то в qss в имени класса вместо :: нужно использовать --.
— Вообще тут много интересного.
— Фоновые картинки (для всего контрола) порой проще задавать через border-image.
— Для кнопок, если нужно менять отображение текста при hover событиях (например, сделать hyperlink) нужно использовать QToolButton вместо QPushButton.