Показаны сообщения с ярлыком Qt. Показать все сообщения
Показаны сообщения с ярлыком Qt. Показать все сообщения

воскресенье, 23 мая 2010 г.

Qt и условная сборка qmake

Попытаюсь сэкономить кому-нибудь время,силы и нервы.
В одном из Qt проектов (.lib) нужно было сделать так, чтобы при сборке в режиме debug сгенерированная dll помещалась в дерикторию debug, а при сборке в режиме release - в директорию release.
Решение состояло в том, чтобы прописать в pro-файле следующее:
CONFIG += designer plugin debug
TEMPLATE = lib
TARGET = $$qtLibraryTarget($$TARGET)
.....................

debug {
DLLDESTDIR += ../MyApp/debug
message(1)

}
release {
DLLDESTDIR += ../MyApp/release
message(2)
}
Но почему-то сгенерированная dll помещалась всегда в обе папке, независимо от режима сборки. И на консоль выдавались оба сообщения - message(1) и message(2)

Дело было в том, что переменная CONFIG уже содержала в себе значения и debug, и release.
Результат выполнения message($$CONFIG) такой:
Project MESSAGE: lex yacc warn_on debug uic resources rtti_off exceptions_off stl_off incremental_off thread_off windows release ReleaseBuild Release build_pass qt warn_on release incremental flat link_prl precompile_header autogen_precompile_source copy_dir_files debug_and_release debug_and_release_target embed_manifest_dll embed_manifest_exe debug shared stl exceptions rtti mmx 3dnow sse sse2 def_files release ReleaseBuild Release build_pass designer plugin debug
Решение состоит в использовании функции CONFIG и выглядит следующим образом:
CONFIG( debug, debug|release ) {
DLLDESTDIR += ../MyApp/debug
message(1)
} else {
DLLDESTDIR += ../MyApp/release
message(2)
}
Теперь будет выполняться только единственная ветвь в зависимости от режима сборки.

воскресенье, 28 марта 2010 г.

QLabel & QPainter. Рисование на картинке

Случилась как-то задача. Нужно было загружать картинку и потом рисовать на ней всякой разное мышкой.
В роли виджета для загрузки картинки я сделал унаследованный от QLabel виджет с переопределенным событием
void RenderingLabel::paintEvent(QPaintEvent* pe){}
Мышка отлично рисовала, но проблема была в том, что фоновая картинка не отображалась. Как позже выяснилось, нужно было вызвать базовое событие paintEvent. Т.е. все должно выглядеть вот так:
void RenderingLabel::paintEvent(QPaintEvent* pe)
{
 QLabel::paintEvent(pe); // базовое событие
 QPainter painter(this);
        // А тут рисуем что хотим
}
Вот и все дела)

воскресенье, 7 марта 2010 г.

Создание собственных виджетов с интеграцией в Qt Designer (Custom widget plugin)

В данном посте я создам виджет,а именно, в нем будет присутствовать QListWidget, кнопки перемещения элемента списка на позицию вверх и вниз, кнопка удаления. Так же в нем присутствует метод привязки данных и добавления отдельного элемента (QString). Такой элемент управления мне понадобился на одном из проектов, причем в нескольких местах, поэтому, я решил оформить его именно как отдельный элемент управления (User Control в .NET). Я не буду приводить код релизации виджета. Вместо этого сконцентрируемся на написании кода, необходимого для оформления виджета как плагина и успешной интеграции в Qt Designer и Qt Creator

Для начала создадим Qt GUI проект. Лично я сначала делаю это в Qt Creator, а потом генерирую проект для Visual Studio 2008 с помощью интегратора.
Поместим на форму QListWidget, три QPushButton, QLabel и скомпилируем и запустим проект. Видим, что все, что мы поместили на форму, отобразилось так, как мы и хотели. Теперь надо оформить все это в плагин.

В Qt Creator выбираем проект пользовательского виджета (в VS2008 - Qt4 Designer plugin).
Допустим в прошлом проекте у нас класс назывался ExtendedListWidget. В проекте плагина укажем такое же имя класса. Получим 4 файла
  • ExtendedListWidget.h
  • ExtendedListWidget.cpp
  • ExtendedListWidgetplugin.h
  • ExtendedListWidgetplugin.cpp

Содержимое *.pro-файла должно быть примерно таким:
CONFIG += designer plugin debug_and_release
TARGET = $$qtLibraryTarget($$TARGET)
TEMPLATE = lib
QT += svg
QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer
HEADERS = extendedlistwidgetplugin.h \
ui_extendedlistwidget.h \
extendedlistwidget.h

SOURCES = extendedlistwidgetplugin.cpp \
extendedlistwidget.cpp
RESOURCES = icons.qrc

# install
target.path = $$[QT_INSTALL_PLUGINS]/designer
sources.files = $$SOURCES $$HEADERS *.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/designer/extendedlistwidgetplugin
INSTALLS += target sources

Заменяем ExtendedListWidget.h и ExtendedListWidget.cpp на одноименные файлы из предыдущего проекта.

Чтобы избавиться от сообщений типа
warning C4273: 'staticMetaObject' : inconsistent dll linkage
в заголовке ExtendedListWidget.h пишем макрос перед именем класса

#include<qtdesigner/qdesignerexportwidget> 
class QDESIGNER_WIDGET_EXPORT ExtendedListWidget: public QWidget
{
//......
}
Сами заголовочные файлы добавлять в файл проекта не надо, иначе рискуем получить что-то типа
path/to/program/release/moc_analogclock.cpp:40: error: ExtendedListWidget::staticMetaObject' : definition of dllimport static data member not allowed
Заголовочные файлы нужно просто поместить туда, где они смогут быть найденными препроцессором. Например, рядом с исходниками плагина.
Запускаем, получаем ExtendedListWidgetplugin.dll (нужна release), потому как Qt Creator и Qt Designer собраны (как правило) в release mode.
  • Помещаем полученную библиотеку в $(QTDIR)\..\bin\designer (для Qt Creator)
  • В $(QTDIR)\plugins\designer помещаем libExtendedListWidgetplugin.dll и libExtendedListWidgetplugin.lib (для Qt Designer)
  • А также помещаем libExtendedListWidgetplugin.dll рядом в программой, использующий данный плагин

воскресенье, 17 января 2010 г.

Некоторые особенности QScrollArea

Столкнулся с таким интересным виджетом как QScrollArea. С помощью него можно отображать прокручивающееся содержимое, допустим, картинку или текст, или список виджетов.

Для того, чтобы вовнутрь QScrollArea добавить другой виджет нужно сделать примерно следующее:
// Заранее созданная в setupUi() scrollArea
QLabel *l1 = new QLabel("label1"); 
scrollArea->setWidget(l1);
Метод QScrollArea::setWidget устанавливает наш лейбл l1 в качестве дочернего для scrollArea.

А что, если мы хотим добавить пару лейблов вместо одного.

Вот такой код уже работать правильно не будет - появится только последний лейбл:
QLabel *l1 = new QLabel("label1");
QLabel *l2 = new QLabel("label2"); 
scrollArea->setWidget(l1); 
scrollArea->setWidget(l2);

Для того, чтобы получить два лейбла, нужно использовать слои:
QLabel *l1 = new QLabel("label1"); 
QLabel *l2 = new QLabel("label2");
QVBoxLayout *labelLayout= new QVBoxLayout(scrollArea);
labelLayout->addWidget(l1);
labelLayout->addWidget(l2);
Теперь лейблы будут размещены один под другим.
Либо просто назначить лейблы дочерними по отношению к QScrollArea
QLabel *l1 = new QLabel(scrollArea);
QLabel *l2 = new QLabel(scrollArea);
l1->setText("label1");
l2->setText("label2");
Можно сделать еще и следующим образом:
QLabel *l1 = new QLabel("label1");
QLabel *l2 = new QLabel("label2");
QLabel *l3 = new QLabel("label3");
QVBoxLayout *layout = new QVBoxLayout(scrollArea);
layout ->addWidget(l2);
layout ->addWidget(l3);
ui->scrollArea->setWidget(l1);
Получится 2 лейбла на слое и один не на слое.
Раньше был такой баг - если написать
ui->scrollArea_2->setWidget(l1);
QVBoxLayout *l = new QVBoxLayout(scrollArea);
l->addWidget(l2);
l->addWidget(l3);
то два последних лейбла не отобразятся. Я использую версию Qt4.6, и здесь такого бага уже не наблюдается.

Интересно использование виджета, унаследованного от QScrollArea
Возможно у меня какие-то ошибки, но выяснил следующее...
Допустим имеем:
class RenderArea: public QScrollArea
{
.....
}
то для того, чтобы добавить лейблы надо написать примерно так:
RenderArea::RenderArea(QWidget * pParent) :
    QScrollArea(pParent)
{
    QLabel *l1 = new QLabel(this);
    QLabel *l2 = new QLabel(this);
    l1->setText("label1");
    l2->setText("label2");
    ..............
}
только надо еще разместить их аккуратно, чтобы не перекрывались.
Размещение с помощью setWidget делается как и раньше:
QLabel *l1 = new QLabel("Hello");
this->setWidget(l1);
Либо через слой, если больше одного размещаемого виджета
QLabel *l1 = new QLabel();
QLabel *l2 = new QLabel();
l1->setText("label1");
l2->setText("label2");
QVBoxLayout *layout = new QVBoxLayout(this);
layout ->addWidget(l1);
layout ->addWidget(l2);
и все прекрасно работает.

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

суббота, 16 января 2010 г.

Qt и QPainter::drawPoint

В данный момент работаю с графикой в Qt. Нужно было рисовать точки.
В книге нашел примерно такой пример отрисовки точки (пример упрощу до рисования одной точки)
QPainter painter(this);
painter.setPen(QPen(Qt:black, 3));
painter.drawPoint(QPointf(12, 12));
В данном примере должна рисоваться точка с координатами (x = 12, y = 12). Но должна, да не обязана, как выяснилось. После некоторого время непонимания, решил попробовать поменять толщину пера на 1px.
painter.setPen(QPen(Qt:black, 1));
И точки начали рисоваться. Вот такая вот штука. Хотя здесь один разработчик говорит, что точка всегда рисуется толщиной в 1 пиксель, несмотря на толщину пера.