Предлагаю в данную тему скидывать все известные вам интересные фичи и "секреты" Qt. Думаю, так можно собрать неплохую коллекцию интересных возможностей Qt, где каждый сможет найти что-нибудь интересное для себя или узнать новое. Начну сам:
1) Макрос Q_UNUSED позволяет избежать предупреждений по поводу неиспользования какой-то переменной. Пример:
void someFunc(int var) {
Q_UNUSED(var); //тут мы избавлемся от возможного предупреждения от компилятора
}
QString plain = "#include <QtCore>"
QString html = Qt::escape(plain); // html == #include <QtCore>
class SomeClass : public QObject {
Q_OBJECT
Q_PROPERTY(bool prop READ prop WRITE setProp);
private:
bool var;
public:
SomeClass() : var(true) { }
bool prop() const { return var; }
void setProp(bool newValue) { var = newValue; }
};
//а теперь, имея указатель на QObject, мы можем изменять значения переменных унаследованного класса:
SomeClass *sc = new SomeClass;
QObject *obj = sc;
obj->setProperty("prop", true); //тоже самое, что и sc->setProp(true);
P.S. Мне кажется тему можно вверху прикрепить!
Не знаю, возможно, это и известный факт, но мне показалось не совсем обычным такое применение функции read/write. При этом применении она становится аналогом функций Windows Api ::ReadFile/::WriteFile:
_str strIn;
QFile f1("nt.dat");
f1.open(QIODevice::WriteOnly);
f1.write( (const char *)&strIn, sizeof( strIn));
f1.close();
_str strOut;
strOut.n = .0123;
strOut.s = "test";
strOut.y = 1;
QFile f2("nt.dat");
f2.open(QIODevice::ReadOnly);
f2.read( (char *)&strOut, sizeof( strOut));
f2.close();
void*, для 1-го пункта часто имя переменной коментируют, чтоб компиллер не ругался:
void someFunc(int /*var*/) {
...
}
LitkevichВ Yuriy, приколупался лучше бы продолжил идею
char* buf = new char[10];
_str strIn;
strIn.s = buf;
f1.write( (const char *)&strIn, sizeof( strIn));
delete[] buf;
_str strOut;
f2.read( (char *)&strOut, sizeof( strOut));
cout<<strOut.s<<endl; //???
Собственно продолжение. Простенький пример того, что можно сделать с помощью http://doc.trolltech.com/4.4-snapshot/stylesheet.html. Скомпилируйте это у себя и зацените кнопочку:
#include <QtGui>
int main(int argc, char **argv) {
QApplication app(argc, argv);
QPushButton btn;
qApp->setStyleSheet(
"QPushButton {"
"border: 1px solid #000000;"
"border-radius: 10px;"
"background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
"stop: 0 #dedede, stop: 0.5 #434343, stop: 0.51 #000000, stop: 1 #656a6d);"
"min-width: 80px;"
"}"
"QPushButton:pressed {"
"background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
"stop: 0 #cfcccc, stop: 0.5 #333232, stop: 0.51 #000000, stop: 1 #585c5f);"
"}"
"QPushButton:flat {"
"border: none; "
"}"
);
btn.resize(100, 50);
btn.show();
return app.exec();
}
Тоже поделюсь парой интересных моментов.
1) Если вы не используете потоки. но при этом имеется к примеру большой цикл, то интерфейс приложения может блокироваться и не перерисовывается.
Чтобы решить эту проблему можно вызывать метод QApplication::processEvents(); при каждой итерации цикла.
2) Сделать фон любого виджета прозрачным можно так:
listwidget->setFrameShape(QFrame::NoFrame);
listwidget->viewport()->setAutoFillBackground(false);
это может пригодится например, если вы пишете плазмоид для kde4 а в плазме пока нет некоторых нативных прозрачных виджетов =)))
также можно регулировать прозрачность любого окошка с помощью метода QWidget::setWindowOpacity(), который принимает в качестве параметра вещественное число, где 1.0 - полная непрозрачность, а 0.0 - полная прозрачность. Соответственно по умолчанию это значение является равным 1.0
всем привет.
может я собираюсь написать об очевидной штуке, но однако меня она удивила.
1. если соединить один и тот же сигнал с одним и тем же слотом несколько раз(n), и вызвать сигнал один раз, то
слот вызовется столько раз сколько соединений с этим сигналом мы сделали(n)....
2. если разъединить сигнал со слотом - то рушатся все соединения этого сигнала с этим слотом.
... известен ли кому нибудь метод узнать соединен ли сигнал со слотом и если соединен то сколько раз???
Litkevich Yuriy, та ни ма за шо.
Использовать QLatin1String вместо QString где это возможно, т.к. первый быстрее.
QString - конвертирует копирует и конвертирует ASCII строку в Unicode каждый раз, когда ему передается строка в конструкторе.
QLatin1String - класс-обертка над Си строкой (char *). Строка никуда не копируется, поэтому программист должен сам следить за ней.
Имеет смысл использовать отдельно от визуальных компонентов, там где не нужна интернационализация.
Только прирост этот будет незаметен. Так зачем этот геморой?
К теме о сигналах. Бывают случаи, когда надо испустить сигнал внутри обработчика событий, но подобное не работает, т.к. это может привести к зацикливанию и Qt блокирует такие сигналы. В метод connect можно передать дополнительный флаг Qt::QueuedConnection, что говорит Qt вызвать слот для сигнала при следующем цикле QEventLoop (т.е. после выхода из обработчика событий или метода). Такой прием обычно используется для помещения приложения в tray через кнопку minimize.
В Qt есть возможность использовать системные иконки (разные для каждой ОС, определяются динамически). К сожалению в QtDesigner'e почему-то такой возможности нет и подобный метод рассчитан на ручную простановку иконок для каждого элемента. Поможет в этом метод QStyle::standardIcon(). Доступ к методу можно получить через указатель qApp->style()->standardIcon(...);
Выбор иконок не велик, но некоторые могут пригодится: http://doc.trolltech.com/main-snapshot/qstyle.html#StandardPixmap-enum
В Qt можно соединять не только сигнал со слотом, но и сигнал с сигналом. Это приведет к тому, что сигнал запустит второй сигнал. При этом если первый и второй сигналы были подключены к слотам, то они тоже вызываются (естественно, если на нем что-то завязано, сигнал типа clicked() врятли кликнет на кнопку).
Треп перенесен в тему http://www.forum.crossplatform.ru/index.php?showtopic=1772.
Так как он всеже не изкореним в этой теме, то весь треп будет всегда переносится в ту тему...
обнаружил интересное поведение в QTableView
если выделена ячейка в столбце N, то нажимая кнопки букв или цифр на клавиатуре будет осуществлятся навигация по этому столбцу.
например есть таблица:
id RefDes TypeName Layer
52 C12 EMR-35V-47U(7*6.3*2.5) 47,0*35В top
53 C17 EMR-35V-47U(7*6.3*2.5) 47,0*35В top
54 DD2 ADM2483BRW top
55 DD4 ADM2483BRW top
56 FU1 MF-R017 MF-R017 top
57 FU2 MF-R017 MF-R017 top
58 FU3 MF-R017 MF-R017 top
59 R3 CR-0805 10к top
60 R4 CR-0805 10к top
Не знаю куда это отнести к секретам или интересным возможностям. Вроде и не секрет, да и не возможность. А просто любопытная информация мимо которой многие могли бы пройти. Дерево классов Qt 4.3, распечатать и повесить на стенку. В ассистенте его нет, т.к. оно в PDF формате: http://doc.trolltech.com/extras/qt43-class-chart.pdf
ну и секреты у вас
но всё-равно внесу свои пять копеек:
если в кастомном виджете в paintEvent используется `setOpacity(a)` для активного Q(|Style)Painter, где `a<1.0` (например, эффект плавного показа/скрытия виджета), и у виджета имеется родитель, то соседи родителя получат такой же фактор прозрачности через /* кривую */ групповую прозрачность.
чтобы этого избежать, необходимо использовать сохранение/восстановление состояния QPainter:
void MyWidget::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.save();
painter.setOpacity(this->currentOpacityValue());
//painter.drawSomething(...);
painter.restore();
}
Перенес обсуждение не относящееся к данной теме в тему: http://www.forum.crossplatform.ru/index.php?showtopic=2138
Еще один способ вывода отладочных сообщений для GUI приложений. Позволяет не прописывать CONFIG += console в .pro файле.
На qDebug, qWarning, QFatal будет всплывать диалог, вместо того, чтобы писаться в консоль.
MyClass::MyClass(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
#if 1 //0 - если надо выключить
QErrorMessage *emsg = new QErrorMessage(this);
emsg->qtHandler();
#endif
}
Вообще этого будет более чем достаточно
Добавлю метод альтернативный методу QTimer::singleShot(), чтобы выполнить слот при возврате в главный event loop, т.е. после выхода из метода.
QMetaObject::invokeMethod(this, "nashSlot", Qt::QueuedConnection);
Пожалуй вопрос с enum'ом сюда помещу. В общем задача - получить название перечисляемого типа по значению. Решение вопроса в стиле Qt
#include <QtCore/QtGlobal>
#include <QtCore/QtDebug>
#include <QtCore/QMetaObject>
#include <QtCore/QMetaEnum>
class Programmer : public QObject
{
Q_OBJECT
public:
enum Language {ASM, C, CPP, PASCAL, FORTRAN, BASIC, JAVA};
Q_ENUMS(Language)
};
int main(int argc, char *argv[])
{
const QMetaObject &mo = Programmer::staticMetaObject;
int index = mo.indexOfEnumerator("Language");
QMetaEnum me = mo.enumerator(index);
Programmer::Language p = Programmer::CPP;
Programmer::Language l= static_cast<Programmer::Language>(me.keyToValue("CPP"));
qDebug() << me.valueToKey(p) << ":" << l;
return 0;
}
#include "main.moc"
http://www.prog.org.ru/index.php?topic=8884.msg49877#msg49877
Немножко заморочился на тему создания и извлечения zip архивов средствами Qt. Посмотреть что из этого вышло можно тут http://vingrad.ru/blogs/sabrog/2009/03/20/qt-45-rabota-s-zip-arhivami/
SABROG, напиши, пожалуйста, тут о тех двух функциях-то!
INCLUDEPATH += $(QTDIR)/src/gui/text
#include <Qt/private/qzipreader_p.h>
#include <Qt/private/qzipwriter_p.h>
#include <qzip.cpp>
QZipReader zip("file.zip"); // загружаем файл
zip.extractAll("directory"); // извлекаем все что в нем в папку directory
QZipWriter zip("file.zip"); // создаем файл
zip.addDirectory("directory"); // добавляется пустая папка в zip архив с именем directory
....
//в созданную папку "directory" предыдущей командой мы добавляем файл file.ext.
//При этом мы сами должны открыть файл file.ext через QFile, прочитать все содержимое и передать как QByteArray в эту функцию
zip.addFile("directory/file.ext", myByteArray);
zip.close();
Да нет! Я про аналоги getenv!!!!
В Qt есть недокументированные кроссплатформменные функции qgetenv() и qputenv() для получения и установки переменных окружения.
QByteArray qgetenv(const char *varName);
bool qputenv(const char *varName, const QByteArray& value);
qconfig_myconfig.zip ( 826 байт )
: 559
Для тех кто помешан на обезжиривании Qt. Вместе с исходниками Qt для мобильных систем поставляется утилита QConfig, которая позволяет отключать возможности (features).
При этом утилита сама смотрит за зависимостями и отключает зависимые компоненты.
Дистрибутивы для win и *nix идут без этой утилиты. Поэтому, чтобы воспользоваться данной утилитой нам понадобится скачать общий дистрибутив Qt для всех платформ. Сделать это можно в .torrent репозитории http://dist.trolltech.com/torrents/ Качать надо это: http://dist.trolltech.com/torrents/qt-all-opensource-src-4.5.0.zip.torrent
Сразу скажу, что у меня уже стояла Qt собранная статически, поэтому я просто зашел в папку $(QTDIR)/tools/qconfig и вбил заветные команды:
qmake
mingw32-make release
configure.exe -qconfig НАШЕИМЯ [тут идут остальные обычные параметры типа -confirm-license -static -no-exceptions и т.д.]
любопытно
Тянет на статью в wiki.
Лишь одно скажу. Если конфигурировать сразу так без предварительной компиляции
Эх, как бы всё это разгрести. Я уже несколько раз порывался. Но как только начну рисовать набумажке, что и куда, так волосы на голове начинают шевелиться.
Ковырялся с документацией Qt 4.6 и сделал для себя открытие:
Оказвается в Qt 4.4 был введен новый класс компоновки http://doc.crossplatform.ru/qt/4.4.3/qformlayout.html
А его презентация появилась только в 4.5. на странице описания компоновок
А кто-нибудь обратил внимание, что в 4.5 появились смарт-пойнтеры? Классы QSharedPointer & QWeakPointer.
Обнаружил тут, что QImage умеет читать postscript файлы. Обнаружил случайно, смотрел пример из qt4/examples/widgets/imageviewer и вместо png файла кликнул на ps, и был нескозанно удивлен увидев что программа показала его.
На windows у меня не заработало (мо возможно нужно что-то доставить/настроить), но на kubunt-e 9.04 с QT 4.5.0 и ghostscript работает.
Думаю никто не будет против, если я буду использовать эту тему немного не по назначению? А именно как закладки, в каком-то смысле, чтобы не потерять.
_________
В документации по сигналам и слотам есть такая фраза:
class X : public QObject
{
Q_OBJECT
....
signals:
void fooPriority1();
void fooPriority2();
void fooPriority3();
void fooPriority4();
slots:
void emitFoo();
...
};
void X::emitFoo()
{
emit fooPriority1();
emit fooPriority2();
emit fooPriority3();
emit fooPriority4();
}
qsrand(QDateTime::currentDateTime().toTime_t());
Немного про нормализацию сигнатур. Мое внимание привлекло http://qt.gitorious.org/qt/pages/CodingConventions о необходимости нормализовывать все сигнатуры прежде чем использовать connect при изменении исходников Qt.
Нормализация представляет собой парсинг строки, уменьшение её длинны путем удаления лишних пробельных символов. Перестановка ключевых слов для оптимизации поиска нужного сигнала или слота у QObject'a. Подобный разбор происходит каждый раз, когда мы используем connect. Макросы SIGNAL() и SLOT() не дают нам нормализованную строку, они нам дают просто строку типа:
2mysignal(QString, QString)
2mysignal(QString,QString)
Пользователи Qt, которые собирают свои приложения с помощью компилятора gcc наверняка замечали, что при компиляции их приложений используется ключ оптимизации -O2. В первую очередь это связано с тем, что сама библиотека Qt собранная с ключем оптимизации -O3 ведет себя не стабильно. Однако никто вам не запрещает иметь библиотеку Qt собранную с оптимизацией -O2, а вашу программу с оптимизацией -O3 или любой другой. Однако ключи компилятора прописаны в одном из spec файлов. К тому же не удобно каждый раз лезть в исходники Qt и что-то там менять глобально для всех приложений. Я нашел несколько иной выход, это замена ключей компилятора на свои прямо в .pro файле:
#OPTIMIZE += 0 #no optimization
#OPTIMIZE += 1 #code size, execution time
#OPTIMIZE += 2 #code size, exectuion time, performance of generated code
#OPTIMIZE += 3 #as 2 and some more
#OPTIMIZE += s #only size code optimization
OPTIMIZE += 3
CONFIG(release, debug|release){
!isEmpty(OPTIMIZE) {
*-g++*{
OPT += -O
QMAKE_CFLAGS_RELEASE ~= s,-O.,$$join(OPT,,, $${OPTIMIZE}),
QMAKE_CXXFLAGS_RELEASE ~= s,-O.,$$join(OPT,,, $${OPTIMIZE}),
QMAKE_OBJECTIVE_CFLAGS_RELEASE ~= s,-O.,$$join(OPT,,, $${OPTIMIZE}),
message(Selected optimization: $${QMAKE_CFLAGS_RELEASE})
}
}
}
OPTIMIZE += 3 -mtune=core2 -march=core2 -mmmx -msse -msse2 -msse3 -msse4 -mfpmath=sse
-O3 на самом деле не макисальная, а альтернативная оптимизация, и может существенно проигрывать -O2, это и в руководстве по GCC написано и по моей практике так.
Есть ещё -Os - оптимизация по размеру, жмёт основательно, я в контроллерах такую использую.
0x - полная автоматизация. Ее ведь тоже можно использовать?
Не такая уж и опечатка, у человека правильно мозги повернуты
автоматизация в некоторых случаях дает оптимизацю
__fastcall в стиле Qt. В Delphi и MSVC есть аттрибут для функций __fastcall, который позволяет вызывать функции быстрее, т.к. при передаче параметров используются регистры eax, edx и ecx. К сожалению в связи с этим есть некоторые ограничения. Параметров может быть 3 и все они должны иметь целочисленный тип (4 байта). Например:
QString QT_FASTCALL MyClass::myFunc(int par1, ushort par2, uint *par3);
#include <QtCore/QtGlobal>
#if defined(__i386__) || defined(_WIN32) || defined(_WIN32_WCE)
# if defined(Q_CC_GNU)
#if !defined(Q_CC_INTEL) && ((100*(__GNUC__ - 0) + 10*(__GNUC_MINOR__ - 0) + __GNUC_PATCHLEVEL__) >= 332)
# define QT_FASTCALL __attribute__((regparm(3)))
#else
# define QT_FASTCALL
#endif
# elif defined(Q_CC_MSVC) && (_MSC_VER > 1300 || defined(Q_CC_INTEL))
# define QT_FASTCALL __fastcall
# else
# define QT_FASTCALL
# endif
#else
# define QT_FASTCALL
#endif
QListView при инициализации считывает все строки для определения размеров.
На больших наборах данных это очень существенные затраты времени.
Чтобы этого не происходило достаточно воспользоваться setGridSize().
Правда у меня осталась другая проблема - предельное количество строк,
которое может отобразить QlistVIew - 134217724
Это огранечиние класса QVector. При этом объем, занимаемый приложением в памяти 520Mb.
Получил на форуме прикольный номер пользователя - килобайт
Кроссплатформенный метод установки приоритета для приложени. Навеяно этим http://lists.trolltech.com/qt-interest/2006-05/thread00831-0.html.
Вариант 1.
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qApp->thread()->setPriority(QThread::HighestPriority);
return a.exec();
}
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
#include <QtCore/QMetaType>
Q_DECLARE_METATYPE(QThread::Priority)
class CoreApplication : public QCoreApplication
{
Q_OBJECT;
public:
CoreApplication(int& argc, char* argv[], QThread::Priority priority = QThread::InheritPriority)
: QCoreApplication(argc, argv)
{
qRegisterMetaType<QThread::Priority>();
connect(this, SIGNAL(priorityChanged(QThread::Priority)),
SLOT(changePriority(QThread::Priority)),
Qt::QueuedConnection);
if (priority != QThread::InheritPriority)
setPriority(priority);
}
inline void setPriority(QThread::Priority priority) {emit priorityChanged(priority);}
inline QThread::Priority priority() const {return thread()->priority();}
protected slots:
void changePriority(QThread::Priority priority)
{
thread()->setPriority(priority);
}
signals:
void priorityChanged(QThread::Priority priority);
};
int main(int argc, char *argv[])
{
CoreApplication a(argc, argv, QThread::HighestPriority);
return a.exec();
}
#include "main.moc"
#include <QtCore/QCoreApplication>
#include <QtCore/QThread>
class Object : public QObject
{
Q_OBJECT;
public:
Object(QObject *parent = 0) : QObject(parent) {}
void setThreadPriority(QThread::Priority priority)
{
QMetaObject::invokeMethod(this, "changePriority", Qt::QueuedConnection, Q_ARG(int, static_cast<int>(priority)));
}
protected:
Q_INVOKABLE void changePriority(int priority)
{
qApp->thread()->setPriority(static_cast<QThread::Priority>(priority));
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Object object;
object.setThreadPriority(QThread::HighestPriority);
return a.exec();
}
#include "main.moc"
start /REALTIME myprogram.exe
Ну собственно один вариант ещё и в списке рассылке, Где создаётся пользовательское событие.
Выложу сегодня 2 полезных "хака", которые могут пригодится при отладке приложения:
Первый хак - для доступа к приватным классам Qt:
namespace Hack { template <class To, class From> inline To* d_ptr(From* ptr){ return (To*)QObjectPrivate::get(ptr);}}
#include "private/qlineedit_p.h"
...
{
Hack::d_ptr<QLineEditPrivate>(ui->lineEdit)->placeholderText = "Test";
}
#include "private/qtableview_p.h"
...
QLabel* label = new QLabel(ui->tableWidget);
label->setText("<span style=\"color: red\">Bye</span> <span style=\"color: green\">Bye</span>, <span style=\"color: blue\">World!</span>");
label->setAlignment(Qt::AlignCenter);
QTableViewPrivate* tvPrivate = Hack::d_ptr<QTableViewPrivate>(ui->tableWidget);
tvPrivate->cornerWidget->deleteLater();
tvPrivate->cornerWidget = label;
struct StaticQtMetaObject : public QObject
{
static inline const QMetaObject& get() {return staticQtMetaObject;}
};
#include <QtCore/QtGlobal>
#include <QtCore/QtDebug>
#include <QtCore/QMetaEnum>
struct StaticQtMetaObject : public QObject
{
static inline const QMetaObject& get() {return staticQtMetaObject;}
};
int main(int argc, char *argv[])
{
const QMetaObject& mo = StaticQtMetaObject::get();
int index = mo.indexOfEnumerator("Key");
QMetaEnum me = mo.enumerator(index);
Qt::Key myKey = Qt::Key_F35;
qDebug() << me.valueToKey(myKey);
return 0;
}
Думаю что в данной теме необходимо упомянуть об интересной возможности Qt - функции прямого копировани участков памяти :
void *qMemCopy(void* dest, const void* src, size_t n)
inline QString bitsToString(QBitArray& arr) {
QString r;
r.resize(arr.size() / 16); // длина массива должна быть точно кратна размеру символа в UTF-16, 16 битам
qMemCopy(r.data_ptr()->data, arr.data_ptr()->data+1, r.length()*2); // т.к. 1 символ = 2 байта
return(r);
};
inline QBitArray stringToBits(const QString& str) {
QBitArray r(str.length()*16); // 16 бит в символе
qMemCopy(r.data_ptr()->data+1, str.constData(), str.length()*2);
return (r);
}
namespace Hack { template <class To, class From> inline To* d_ptr(From* ptr){ return (To*)QObjectPrivate::get(ptr);}}
#include "private/qlineedit_p.h"
...
{
Hack::d_ptr<QLineEditPrivate>(ui->lineEdit)->placeholderText = "Test";
}
Администратор одного программерского форума удалил мой блог, который я вел 2 года. Там был код, который я выкладывал в постах. Никакие кэши гугла и archive.org не сохранили информацию. В общем, если вы не против, то буду тут периодически выкладывать интересные/полезные решения.
---
Добавление сигнала clicked() в QLabel средствами State Machine Framework:
QStateMachine* machine = new QStateMachine(this);
QState* s1 = new QState(machine);
QMouseEventTransition* mouseTrans =
new QMouseEventTransition(ui->label, QEvent::MouseButtonRelease, Qt::LeftButton, s1);
QObject::connect(mouseTrans, SIGNAL(triggered()), msgBox, SLOT(show()));
machine->setInitialState(s1);
machine->start();
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QtCore/QObject>
class MyClass : public QObject
{
Q_OBJECT
Q_FLAGS(MyMode)
public:
MyClass(QObject* parent = 0);
enum MyModeFlag {
NoOptions = 0,
Option1 = 1L << 0,
Option2 = 1L << 1,
Option3 = 1L << 2,
Option4 = 1L << 3,
Option5 = 1L << 4
};
Q_DECLARE_FLAGS(MyMode, MyModeFlag)
void setMode(MyMode m);
inline MyMode mode() const;
private:
MyMode m_mode;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::MyMode)
inline MyClass::MyMode MyClass::mode() const {return m_mode;}
class QDebug;
QDebug operator << (QDebug debug, MyClass::MyMode mode);
#endif // MYCLASS_H
#include <QtCore/QDebug>
#include <QtCore/QMetaEnum>
#include "myclass.h"
MyClass::MyClass(QObject* parent)
: QObject(parent), m_mode(MyClass::NoOptions)
{
}
void MyClass::setMode(MyMode m)
{
m_mode = m;
}
QDebug operator << (QDebug debug, MyClass::MyMode modes)
{
const QMetaObject& mo = MyClass::staticMetaObject;
int index = mo.indexOfEnumerator("MyMode");
QMetaEnum me = mo.enumerator(index);
debug << me.valueToKeys(modes);
return debug;
}
"Option1|Option3|Option5"
Да, я тоже заметил, что удалили. Хотел инфу кое-какую почитать..и на тебе..А почему удалили, не сказали?
Администратор это объяснил так:
На заметку:
Заполняем Qt контейнер без for:
#include <algorithm>
#include <QtCore/QtGlobal>
#include <QtCore/QtDebug>
#include <QtCore/QList>
struct inc_functor
{
inc_functor() : counter(0) {}
inline int operator()() {return counter++;}
int counter;
};
int main(int argc, char** argv)
{
QList<int> testList;
std::generate_n(std::back_insert_iterator<QList<int> >(testList),
10, inc_functor());
qDebug() << testList;
return 0;
}
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
struct testAttributePredicate {
testAttributePredicate(Qt::WidgetAttribute attrib) : m_attrib(attrib) {}
inline bool operator()(QWidget* widget) {
return widget->testAttribute(m_attrib);
}
Qt::WidgetAttribute m_attrib;
};
...
{
QWidgetList widgets = qApp->allWidgets();
QWidgetList::iterator result =
std::find_if(widgets.begin(), widgets.end(),
testAttributePredicate(Qt::WA_Disabled));
if (result != widgets.end())
qDebug() << (*result)->objectName();
}
#include <QtConcurrentMap>
#include <functional>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QVector<int> test;
test << 1 << 2 << 3;
QtConcurrent::mapped(test, std::bind1st(std::mem_fun(&MainWindow::myMethod), this));
}
int MainWindow::myMethod(int i)
{
qDebug() << i;
return i;
}
а зачем в
struct testAttributePredicate
оператор operator()(QWidget* widget) ?
template<class InputIterator, class testAttributePredicate>
InputIterator find_if ( InputIterator first, InputIterator last, testAttributePredicate obj)
{
for (; first!=last; first++ ) if ( obj(*first) ) break;
// obj(*first) - вызывается перегруженный оператор (). То есть функция заранее ожидает, что я его перегружу.
return first;
}
Реализовал установку приоритета потока в параллельном программировании.
Как многие заметили в Qt есть метод QThread::setPriority(), а вот как задать приоритет потоку запущенному например через QtConcurrent::run() не понятно. В новом стандарте C++0x будет метод std::call_once, который является потокобезопасной функций для выполнения определеннной функции один лишь раз. Аналогичная функция есть и в BOOST'e. Посмотрев на код функции я пришел к выводу, что проще переписать её на Qt, чем заставлять людей тащить с собой BOOST. С другой стороны моя реализация получилась в 2 раза быстрей BOOST'овской, но медленней std::call_once. Связано это со скудными возможностями класса QAtomicInt, там где я бы мог обойтись быстрыми атомарными операциями загрузки (load) и сохранения (store), мне пришлось импровизировать и использовать более медленные атомарные методы (fetchAndStoreAcquire, fetchAndStoreRelease).
#ifndef CALL_ONCE_H
#define CALL_ONCE_H
#include <QtCore/QtGlobal>
#include <QtCore/QAtomicInt>
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
#include <QtCore/QThreadStorage>
#include <QtCore/QThread>
namespace CallOnce {
enum ECallOnce {
CO_Request,
CO_InProgress,
CO_Finished
};
Q_GLOBAL_STATIC(QThreadStorage<QAtomicInt*>, once_flag)
}
template <class Function>
inline static void qCallOnce(Function func, QBasicAtomicInt& flag)
{
using namespace CallOnce;
int protectFlag = flag.fetchAndStoreAcquire((int)flag);
if (protectFlag == CO_Finished)
return;
if (protectFlag == CO_Request && flag.testAndSetRelaxed(protectFlag,
CO_InProgress)) {
func();
flag.fetchAndStoreRelease(CO_Finished);
}
else {
do {
QThread::yieldCurrentThread();
}
while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
}
}
template <class Function>
inline static void qCallOncePerThread(Function func)
{
using namespace CallOnce;
if (!once_flag()->hasLocalData()) {
once_flag()->setLocalData(new QAtomicInt(CallOnce::CO_Request));
qCallOnce(func, *once_flag()->localData());
}
}
#endif // CALL_ONCE_H
#include <QtCore/QtGlobal>
#include <QtCore/QtDebug>
#include <QtCore/QTimer>
#include <QtCore/QTime>
#include <QtCore/QVector>
#include <QtCore/QThread>
#include <QtCore/QtConcurrentMap>
#include <QtCore/QtConcurrentFilter>
#include <QtCore/QCoreApplication>
#include <algorithm>
#include "call_once.h"
enum {Max = 100};
struct run_once
{
void operator()()
{
qDebug() << "Functor: This only once...";
}
};
void func_run_once()
{
qDebug() << "Function: This only once...";
}
struct inc_functor
{
inc_functor() : counter(0) {}
inline int operator()() {return counter++;}
int counter;
};
struct setPriorityFunctor
{
setPriorityFunctor(QThread::Priority priority = QThread::NormalPriority)
: m_priority(priority) {}
inline void operator()()
{
QThread* thread = QThread::currentThread();
thread->setPriority(m_priority);
}
QThread::Priority m_priority;
};
void setLowestPriorityFunction()
{
QThread* thread = QThread::currentThread();
thread->setPriority(QThread::LowestPriority);
qDebug("Current thread %x. Thread set to Lowest priority",
(quintptr)thread);
}
void setHighestPriorityFunction()
{
QThread* thread = QThread::currentThread();
thread->setPriority(QThread::HighestPriority);
qDebug("Current thread %x. Thread set to Highest priority",
(quintptr)thread);
}
int calculate(const int& num)
{
#if 0 // Test once call per thread with function
#if 0 // Set lowest thread priority
qCallOncePerThread(setLowestPriorityFunction);
#else // Set highest thread priority
qCallOncePerThread(setHighestPriorityFunction);
#endif
#else // Test once call per thread with functor
#if 0
qCallOncePerThread(setPriorityFunctor(QThread::HighestPriority));
#else
qCallOncePerThread(setPriorityFunctor(QThread::LowestPriority));
#endif
#endif
return ~num;
}
static QBasicAtomicInt flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
int parityFilter(const int& num)
{
qCallOnce(run_once(), flag);
return num % 2 ? false : true;
}
static QBasicAtomicInt testflag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
QTime t; t.start();
for (int i = 0; i < 1000 * 1000 * 100; ++i)
qCallOnce(run_once(), testflag);
qDebug("%d ms", t.elapsed());
QVector<int> ints;
std::generate_n(std::back_insert_iterator<QVector<int> >(ints),
(int)Max, inc_functor());
// Test qCallOnce
{
QVector<int> results = QtConcurrent::blockingMapped(ints, calculate);
qDebug() << results;
}
// Test qCallOncePerThread
{
QtConcurrent::blockingFilter(ints, parityFilter);
qDebug() << ints;
}
return 0;
}
SABROG, а с Троллями (нокией) пробовали это обсудить? Мож они включат это в свой код?
В старом проекте на Borland Builder C++ у меня были кнопочки со стилем csFramed. Захотелось узнать возможно ли такие сделать в Qt. Нашел флаг для свойства border в qss - groove, но как выяснислось в нем нельзя задать контрастные цвета например черный и белый. То есть задать можно один цвет на основе которого вычисляется второй. Цвета типа черный или белый не подходят, создается просто черный бордюр. Пришлось написать собственную версию:
QPushButton {
/*top right bottom left (clockwise)*/
background-color: #d6d3ce;
border-width: 2px 3px 3px 2px;
border-style: solid;
border-color:
qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 white, stop:0.5 white, stop:0.51 #848284, stop:1 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:0, y2:1, stop:0 white, stop:0.33 white, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 white, stop:0.33 white, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:0, y2:1, stop:0 white, stop:0.5 white, stop:0.51 #848284, stop:1 #848284);
}
QPushButton:default{
border-width: 3px 4px 4px 3px;
border-color:
qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 white, stop:0.33 white, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:0, y2:1, stop:0 white, stop:0.25 white, stop:0.26 black, stop:0.50 black, stop:0.51 black, stop:0.75 black, stop:0.76 #848284, stop:1 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 white, stop:0.25 white, stop:0.26 black, stop:0.50 black, stop:0.51 black, stop:0.75 black, stop:0.76 #848284, stop:1 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:0, y2:1, stop:0 white, stop:0.33 white, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284);
}
QPushButton:pressed{
border-width: 3px;
border-color:
qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 #848284, stop:0.33 #848284, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:0, y2:1, stop:0 white, stop:0.33 white, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 white, stop:0.33 white, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284)
qlineargradient(spread:pad, x1:1, y1:1, x2:0, y2:1, stop:0 #848284, stop:0.33 #848284, stop:0.34 black, stop:0.67 black, stop:0.68 #848284, stop:1.0 #848284);
}
Продолжил издеваться над кнопками и qss:
QPushButton {
font-weight: bold;
border: 1px solid black;
border-radius: 7px;
color: white;
background-color:
qradialgradient(spread:pad, cx:0.51, cy:-1.0, radius:2, fx:0.50, fy:0.0, stop:0.53 #81beff, stop:0.54 #268fff, stop:1 #268fff);
}
QPushButton:hover {
color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 black, stop:0.5 white);
}
QPushButton:pressed {
padding: 3px 0px 0px 3px;
background-color:
qradialgradient(spread:pad, cx:0.51, cy:-1.0, radius:2, fx:0.50, fy:0.0, stop:0.51 #0061ff, stop:0.52 #268fff, stop:1 #268fff);
}
QPushButton:default {
border-width: 2px;
}
QPushButton:focus {
border: 4px double black;
}
Обнаружил любопытный спецэффект: если в качестве подменю (QMenu) задать элементу другое предыдущее по иерархии меню, то при выборе пункта все предыдущие подменю изчезают с экрана и показывается указанное ))
К примеру:
----------------
m1
----------------
A1 > (m2)
A2
A3
----------------
отделено от темы "http://www.forum.crossplatform.ru/index.php?showtopic=5334"
----------------
m2
----------------
A4
A5 > (m1)
A6
----------------
Выбор пунктов A1>A5 покажет на экране опять таки меню m1
---------------------------------------------------
Уточнил - не всё так радужно.
#include <QMenu>
QMap<QString,QAction*> map;
const char* text=0;
//менюшка первого уровня
QMenu& m1=*new QMenu(this);
text="11"; map[text]=m1.addAction(text);
text="12"; map[text]=m1.addAction(text);
text="13"; map[text]=m1.addAction(text);
//менюшка второго уровня
QMenu& m2=*new QMenu(this);
text="21"; map[text]=m2.addAction(text);
text="22"; map[text]=m2.addAction(text);
text="23"; map[text]=m2.addAction(text);
//менюшки третьего уровня
QMenu& m3_1=*new QMenu(this);
text="311"; map[text]=m3_1.addAction(text);
text="312"; map[text]=m3_1.addAction(text);
text="313"; map[text]=m3_1.addAction(text);
text="314"; map[text]=m3_1.addAction(text);
QMenu& m3_2=*new QMenu(this);
text="321"; map[text]=m3_2.addAction(text);
text="322"; map[text]=m3_2.addAction(text);
text="323"; map[text]=m3_2.addAction(text);
QMenu& m3_3=*new QMenu(this);
text="331"; map[text]=m3_3.addAction(text);
text="332"; map[text]=m3_3.addAction(text);
text="333"; map[text]=m3_3.addAction(text);
//связываем вложенные меню
map["12"]->setMenu(&m2);
map["21"]->setMenu(&m3_1);
map["22"]->setMenu(&m3_2);
map["23"]->setMenu(&m3_3);
map["311"]->setMenu(&m1);
map["311"]->setText("open m1");//откроется меню первого уровня
map["312"]->setMenu(&m2);
map["312"]->setText("open m2");//ничего не произойдёт
map["313"]->setMenu(&m3_1);
map["313"]->setText("open m3_1");//ничего не произойдёт, только подсветка прыгнет наверх
map["314"]->setMenu(&m3_2);
map["314"]->setText("open m3_2");//откроется ещё один уровень вложенности (стандартное поведение)
//отображаем меню
m1.popup(cursor().pos());
Заметил интересную особенность при сериализации списка своих данных через оператор QDataStream в QSettings. Дело в том, что в принципе QDataStream умеет сериализовать QList, но для типа, который будет содержать контейнер нужно определять свои операторы <</>>. Предположим мы это сделали. Но при попытке сохранить список в QSettings мы получим ошибку, что тип не зарегестрирован как мета-тип:
error: ‘qt_metatype_id’ is not a member of ‘QMetaTypeId<QList<MyStruct> >’
Q_DECLARE_METATYPE(QList<MyStruct>)
QVariant::load: unable to load type 260.
QVariant::save: unable to save type 260.
qRegisterMetaTypeStreamOperators<QList<MyStruct> >("QList<MyStruct>");
struct MyStruct
{
QString name;
qint32 key;
};
Q_DECLARE_METATYPE(MyStruct)
Q_DECLARE_METATYPE(QList<MyStruct>)
QDataStream& operator<<(QDataStream& ostream, const MyStruct& ms)
{
ostream << ms.name << ms.key;
return ostream;
}
QDataStream& operator>>(QDataStream& istream, MyStruct& ms)
{
istream >> ms.name >> ms.key
return istream;
}
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
QSettings qsettings("settings.ini", QSettings::IniFormat);
qRegisterMetaTypeStreamOperators<MyStruct>("MyStruct");
qRegisterMetaTypeStreamOperators<QList<MyStruct> >("QList<MyStruct>");
QList<MyStruct> msList;
MyStruct ms = {"MyStruct name", 123};
msList << ms;
qsettings.setValue("ListMyStruct", qVariantFromValue(msList));
return 0;
}
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of qsql*model.h . This header file may change from version to version
// without notice, or even be removed.
//
// We mean it.
//
[quote name='Litkevich Yuriy' date='5.2.2009, 19:45' post='14041']
обнаружил интересное поведение в QTableView
если выделена ячейка в столбце N, то нажимая кнопки букв или цифр на клавиатуре будет осуществлятся навигация по этому столбцу
Здравствуйте! В QListWidget тоже присутствует такое поведение, при нажатии на букву, список перемещаеться на заглавную (нажатую) букву.
Вот, так может знает кто возможность отключения такого поведения , по причине , что при этом нету реакции на keyPressEvent(QKeyEvent *pe) . Реагирует только на кнопки Ф1 - Ф 12 , шифт, таб, и т.п
Понадобилось отследить изменения в файле, который находится в шаре на удаленном компьютере. К сожалению, QFileSystemWatcher может отслеживать только файлы и директории находящиеся на жестком диске. Но есть недокументированная возможность использовать опрос (polling), который можно включить таким образом:
QFileSystemWatcher watcher;
watcher.setObjectName(QLatin1String("_qt_autotest_force_engine_poller"));
watcher.addPath(....);
Если вы пишите плагины для QtDesigner и хотите что бы на форме виджет не просто отрисовывался, а вел себя как настоящий виджет, присвойте ему имя вида
comboBox->setObjectName("__qt__passive_xxx");
, где xxx - это любая строка. Для эксперимента, киньте на форму комбобокс, добавьте в него пару итемов, после чего задайте имя в формате описанном выше. Посмотрите как изменилось поведение виджета.
В Wiki, на Developer Network нашел интересный вариант размещения окна по центру:
#include <QtGui/QStyle>
#include <QtGui/QDesktopWidget>
...
window->setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter, window->size(), qApp->desktop()->availableGeometry()));
Уважаемый Sabrog,
вы показали как записывать в ini - qsettings.setValue("ListMyStruct", qVariantFromValue(msList));. Был бы вам очень признателен, если бы вы в ваш пример добавили как считать записанные данные из ini файл, а то что то не особо получается...
Обсуждение вынес в отдельную тему: http://www.forum.crossplatform.ru/index.php?showtopic=9232
QMetaObject::invokeMethod(this, "nashSlot", Qt::QueuedConnection);
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)