Q_OBJECT special
занятная фишка: нельзя объявлять классы-наследники от QObject вне хедеров (если мы хотим использовать сигналы-слоты). если объявить такой класс в .cpp-шнике, то линковщик будет ругаться на vtable. ибо qmake плохо обрабатывает .cpp-шники...
UPD: один хороший человек подсказал солюшн: надо в конце .cpp-шника сделать #include "myfile.moc". я не проверял, но говорят, что работает.
qt symbian plugins
Не знаю, как у вас, а у меня всегда что-то компилится.
так вот, сегодня собираем плагины под симбиан.
если хочешь собрать плагин под симбиан, то надо сделать вот что. в .pro файле плагина пишем так:
TEMPLATE = lib CONFIG += plugin TARGET = $$qtLibraryTarget(myplugin) symbian: { load(data_caging_paths) TARGET.EPOCALLOWDLLDATA=1 TARGET.UID3 = 0xXXXXXXXX TARGET.CAPABILITY += "LocalServices Location NetworkServices ReadUserData UserEnvironment WriteUserData" # dummy deployment (for qt creator) plugin.sources = myplugin.dll plugin.path = !:/sys/bin DEPLOYMENT += plugin }
UID3 указывается индивидально. например, получить UID можно на сайте SymbianSigned
последние три строки кода нужны для qt creator'а, чтобы он создал .sis файл. нам это не нужно, но криейтор без этого не может.
в принципе, всё. плагин готов (если конечно содержимое у него адекватное). теперь самое простое - деплой вместе с приложением. например, для деплоя плагина в папку !:/Private/XXXXXXXX/plugins (XXXXXXXX - UID приложения), надо в .pro нашей проги написать:
symbian: { plugins.sources = myplugin.dll \ myplugin2.dll plugins.path = ./plugins DEPLOYMENT += plugins }
теперь всё готово. можно собирать. искать плагины надо в QApplication::applicationDirPath() + "/plugins". и можно радоваться жизни.
qt + symbian
итак, чудо из чудес: qt под symbian.
чудо качается в виде Nokia Qt SDK и устанавливается как и обычный qt sdk. при этом всё работает хорошо, даже замечательно - эмулятор, отладка на девайсе... и так далее.
но всё так только до тех пор, пока не потребуется собрать что-то сложное. тут-то и начинается веселье!
замечу, что я до того не имел дела с программированием под симбиан. только qt.
итак!
во-первых, текущая версия Nokia Qt SDK (1.0) не умеет собирать под симбиан проекты с TEMPLATE = subdirs. точнее, что-то как-то собирается, но сплошные ошибки. от этого лучше сразу отказаться.
далее. если хочешь собрать библиотеку, то столкнёшься с такой штукой: qt creator обязательно (!) выполняет в конце make sis. и это не отключить. так что даже если не хочется создавать инсталлятор отдельно для библиотеки, то делать это придётся, если собирать из криейтора. делается это просто, но всё же это излишество.
вот собственно пример:
# экспортируем хедеры BLD_INF_RULES.prj_exports += utilsexport.h \ utils.h # заглушка для qt creator'а, создаём инсталлятор myFiles.sources = utils.dll myFiles.path = !:/sys/bin DEPLOYMENT += myFiles
итак, теперь у нас есть библиотека, лежит она в \Symbian\SDK\epoc32\release\gcce\udeb\ (или \urel\ если собиралась в релизе). но есть и лишний .sis файл... ну да ладно, на него забьём спокойно.
вообще, на этом этапе может возникнуть ошибка борки. но мы это поправим так (из командной строки с подключенными переменными среды из SDK - в главном меню есть ярлык):
abld freeze
после чего собираем снова - и всё, должно заработать.
заметим так же, что есть такое понятие, как капабилитиз, их надо указать, если проект будет хоть что-то делать с сетью, например. подробнее можно почитать тут.
если что-то не работает, то указываем все капабилити, доступные для самоподписанного приложения:
TARGET.CAPABILITY += "LocalServices Location NetworkServices ReadUserData UserEnvironment WriteUserData"
теперь собираем проект, который эту библиотеку цеплять будет.
в проекте пишем стандартные вещи (LIBS += -lutils), прописываем те же капабилитиз, что и у библиотеки. кроме того, опять терзаем DEPLOYMENT, т.к. автоматически в него добавляются только файлы текущего проекта (да и то только если это не библиотека):
utils.sources = utils.dll utils.path = !:/sys/bin DEPLOYMENT += utils
казалось бы, что всё готово. собираем. если всё хорошо, то получаем .sis файл с прогой и библиотекой. чтобы убедиться, что в нём всё это есть, юзаем утилиту dumpsis.
ну что ж, если прога относительно простая, то всё готово, можно заливать на девайс и тестить. или воспользоваться Remote Device Access. должно заработать.
в моём случае такой номер прошёл только с самым простым приложением. а вот с портированием сложного началась веселуха...
всё собралось. я обрадовался. заливаю на девайс - а он мне говорит, что не может дать приложению необходимые права для установки. почему? я ничего такого особого не юзал, чтоб так вот меня отшивать... нехорошо. ладно, почитал, погуглил, сделал Open Signed Online, установилось. ура? ан нет! не запускается. тупо молча не запускается. перевод телефона в дебаговый режим и экспериментирование с кодом ничего не дали.
что выясняется? а выясняется, что qt creator ещё слишком сырой для полноценной разработки под симбиан.
dumpsis + makesis сделали дело. всё заработало. вуаля!
поясняю. получили .sis файл, распаковываем его с помощью dumpsis и упаковываем заново с помощью makesis. круто? конечно круто! теперь опять делаем открытое подписывание и всё наконец-то работает!
чудеса техники.
как выдрать редактор QSS (Qt StyleSheets) из QtDesigner
в QtDesigner'е есть очень хорошая штука - редактор StyleSheet'ов. он соответственно имеет подсветку CSS. а значит, это может быть полезно.
в моём случае это не только полезно, но и нужно, так как избавляет от необходимости с нуля писать эту самую подсветку.
где взять?
качаем исходники Qt, заходим в tools/designer/src/lib/shared/ и находим там файлы stylesheeteditor.cpp и stylesheeteditor_p.h
после их изучения приходим к выводу, что нужны нам другие файлы: csshighlighter.cpp и csshighlighter_p.h
дальше что делать понятно.
с подсветкой синтаксиса всё понятно. но что же делать с валидацией? тут обратим внимание на отвергнутые в начале файлы и увидим там функцию StyleSheetEditorDialog::isStyleSheetValid, которая юзает namespace QCss, который опять таки не публичный и который надо копать...
копаем сюда: src/gui/text/ файлы qcssparser_p.h и qcssparser.cpp. это всё тянет за собой qcssscanner.cpp.
в общем, теперь можно приступать к сборке "с миру по нитке" своего редактора stylesheet'ов с валидацией и подсветкой.
а если хочется ещё и вставку и редактор градиентов........... то надо копать в сторону QtGradientViewDialog. ищите и обрящете! обращем же этот диалог в tools/shared/qtgradienteditor/
пока всё.
UPD: после детального изучения данного вопроса и долгого ковыряния в исходниках Qt, был написан тестовый проект, который включает в себя этот самый редактор QSS.
вот то, что реально вошло в проект и нужно для работы редактора без интеграции с дизайнером:
csshighlighter.*
qdesigner_utils.*
stylesheeteditor.*
[DIR] qtgradienteditor
разумеется, пришлось выбросить работу с ресурсами. кроме того, градиенты хранятся только для текущего запуска. можно сделать их сохранение, но пока не хочется...
наследование
воистину, если серьёзно не хватает функционала класса, единственно верный способ - сабклассинг!
сборка Qt под Windows Mobile (MSVS 2008)
для сборки сабжа использовал следующий батник (раздобыт на просторах инета, модифицирован, собирает так же WebKit и Phonon, всё в релизе и дебаге):
@echo off echo Setting up a Qt environment... set QTDIR=D:\Qt\4.6.2_CE echo -- QTDIR set to D:\Qt\4.6.2_CE set PATH=D:\Qt\4.6.2_CE\bin;C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN;%PATH% echo -- Added D:\Qt\4.6.2_CE\bin to PATH set QMAKESPEC=win32-msvc2008 echo -- QMAKESPEC set to "win32-msvc2008" call "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat" echo -- Start configure configure -platform win32-msvc2008 -xplatform wincewm50pocket-msvc2005 -opensource -stl -webkit -phonon -phonon-backend -multimedia -audio-backend -qt-style-cleanlooks -phonon-wince-ds9 -debug-and-release echo -- Configure ok set INCLUDE=C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\include;c:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Include\Armv4i echo -- set INCLUDE=C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\include;c:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Include\Armv4i set LIB=C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\lib\armv4i;c:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Lib\ARMV4I echo -- set LIB=C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\lib\armv4i;c:\Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Pocket PC SDK\Lib\ARMV4I set PATH=C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_arm;%PATH% echo -- set PATH=C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\bin\x86_arm;%PATH% echo -- Start nmake nmake echo -- end nmake
Qt Balloon Tip
оказывается, в Qt есть таки QBalloonTip!
только спрятан он в src/gui/util/qsystemtrayicon_p.h и src/gui/util/qsystemtrayicon.cpp
его оттуда можно извлечь и переделать, чтобы отвязать от QSystemTrayIcon и позволить ему показываться где надо.
моя реализация как раз компилится.
caps lock
как программно определить, включен ли caps lock?
решение платформозависимо.
Windows:
#include <windows.h> int i = GetKeyState(VK_CAPITAL); bool caps_on = (i == 1);
что угодно, но с иксами (X11), будь то Linux, Unix, etc...:
(тянет за собой libx11-dev, требует -lX11)
#include <X11/X.h> #include <X11/Xlib.h> #include <X11/XKBlib.h> Display * Dpy = XOpenDisplay((char*)0); bool caps_on = false; if (Dpy) { unsigned n; XkbGetIndicatorState(Dpy, XkbUseCoreKbd, &n); caps_on = (n & 0x01) == 1; }
UPD: как показал опыт, в иксах включать достаточно XKBLib.h. при этом если это юзать в QT, то возникают глюки использования QEvent (см. X11/X.h):
#define KeyPress 2 #define KeyRelease 3 #define ButtonPress 4 #define ButtonRelease 5 #define MotionNotify 6 #define EnterNotify 7 #define LeaveNotify 8 #define FocusIn 9 #define FocusOut 10 #define KeymapNotify 11 #define Expose 12 #define GraphicsExpose 13 #define NoExpose 14 #define VisibilityNotify 15 #define CreateNotify 16 #define DestroyNotify 17 #define UnmapNotify 18 #define MapNotify 19 #define MapRequest 20 #define ReparentNotify 21 #define ConfigureNotify 22 #define ConfigureRequest 23 #define GravityNotify 24 #define ResizeRequest 25 #define CirculateNotify 26 #define CirculateRequest 27 #define PropertyNotify 28 #define SelectionClear 29 #define SelectionRequest 30 #define SelectionNotify 31 #define ColormapNotify 32 #define ClientMessage 33 #define MappingNotify 34 #define LASTEvent 35 /* must be bigger than any event # */
это конфликтует с этим (см. qcoreevent.h):
enum Type { /* If you get a strange compiler error on the line with None, it's probably because you're also including X11 headers, which #define the symbol None. Put the X11 includes after the Qt includes to solve this problem. */ None = 0, // invalid event Timer = 1, // timer event MouseButtonPress = 2, // mouse button pressed MouseButtonRelease = 3, // mouse button released MouseButtonDblClick = 4, // mouse button double click MouseMove = 5, // mouse move KeyPress = 6, // key pressed KeyRelease = 7, // key released FocusIn = 8, // keyboard focus received FocusOut = 9, // keyboard focus lost Enter = 10, // mouse enters widget Leave = 11, // mouse leaves widget Paint = 12, // paint widget Move = 13, // move widget Resize = 14, // resize widget Create = 15, // after widget creation Destroy = 16, // during widget destruction Show = 17, // widget is shown Hide = 18, // widget is hidden Close = 19, // request to close widget Quit = 20, // request to quit application ParentChange = 21, // widget has been reparented ParentAboutToChange = 131, // sent just before the parent change is done // ... etc ...
в частности в пунктах FocusIn, FocusOut, KeyPress...
так что если юзать указанный мной подход, надо делать #undef для конфликтующих имён.
#include <X11/XKBlib.h> #undef KeyPress #undef FocusIn // ... etc ...
так что этот подход лишает нас возможности юзать события иксов в QT. что ж, не очень-то и хотелось ))
UPD 2: а вообще лучше это вынести в отдельный файл, тогда конфликтов не будет.