Qt/ЧАВО
Часто задаваемые общие вопросы по приемам программирования на Qt и Qt 4.x
Qt
правитьQString
правитьне путать null и empty
QString::null == QString().isNull ();
QString("") == QString().isEmpty();
QString("").isNull(); // returns false
QString("").isEmpty(); // returns true
Почему не выводится русский текст в надписях и заголовке?
правитьВ документации Qt ясно сказано: QString преобразует данные const char * в Unicode с помощью функции fromAscii()
. По умолчанию fromAscii()
трактует символы старше 128 как символы Latin-1, но это можно изменить вызовом QTextCodec::setCodecForCStrings()
. В том числе и при инициализации QString строкой типа «Привет всем!». Чтобы все работало необходимо:
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QTextCodec* codec = QTextCodec::codecForName("Windows-1251");
QTextCodec::setCodecForCStrings(codec);
QLabel* plblText = new QLabel("&Имя (Цифры не принимаются!):");
......
Нужно использовать
QString::fromLocal8Bit("Русский текст");
- Откройте файл MainWindow.qml в qtcreator что бы была возможность редактировать в виде текста
- Переходим в меню «Правка»->"Выбор кодировки". Принудительно выставляем Utf8
- Далее стираем русский текст и пишем его заново без всяких qsTr. Теперь qml файл у нас полностью в utf8
- Компилируем, запускаем.
После этого русский текст отобразился правильно. То есть, отсюда вывод: qml файл должен быть в кодировке utf8
Русские символы в отладчике (VStudio)
правитьQTextCodec::setCodecForCStrings( QTextCodec::codecForName("IBM 866") );
Перевод в виндовский юникод
правитьQString str; '''винда'''=(WCHAR*)str.ucs2();
QTime
правитьЭта статическая функция вызывает слот после данного интервала времени.
правитьQTimer::singleShot( 10*60*1000, &a, SLOT(quit()) );
Повторение действий без замораживания интерфейса
править QTime time;time.start;int x=100;
while(time.elapsed()<x){
qApp->processEvents();
..ваш код..
}
Выполнение повторных действий на протяжении работы программы
править '''protected:'''
void timerEvent(QTimerEvent *ev)
{
..ваши действия..
}
Многопоточность (нити)
правитьИспользовать многопоточность необходимо, когда требуется программировать длительный ресурсоемкий процесс(или несколько процессов), а пользователь мог полноценно работать с программой. QTimer не всегда уместен. В этом случае используют потоки.
Можно маленький пример потоков?
правитьДля создания потока, определите подкласс QThread и заново реализуйте его функцию run()
.
class MyThread : public QThread
{ Q_OBJECT
protected:
void run();
};
void MyThread::run()
{
...
}
! Внимание!! В вышеприведённом фрагменте распространённая Ошибка. Корректный код будет выглядеть примерно так:
class MyWorkerObject: public QObject
{
public:
void run();
};
void MyWorkerObject::run()
{
...
}
QThread thread;
MyWorkerObject obj;
obj->moveToThread(thread);
QObject::connect(thread, &QThread::started, obj, &MyWorkerObject::run);
QObject::connect(worker, &MyWorkerObject::finished, thread, &QThread::quit);
QObject::connect(thread, &QThread::finished, obj, &MyWorkerObject::deleteLater);//From Off documentation
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); //From Off documentation
thread->start();
Сигналы и Слоты Между Потоками
правитьQt поддерживает два типа соединений сигнал-слот:
C прямыми связями — слот выполняется немедленно после возникновения сигнала. Слот выполняется в потоке, испустившем сигнал (который не обязательно является потоком, в котором живет объект).
С постановкой сигналов в очередь — слот выполняется, когда контроль возвращается в цикл обработки сообщений потока, которому принадлежит объект. Слот выполняется в потоке, в котором проживает объект-приемник.
По умолчанию QObject::connect()
устанавливает прямую связь, если отправитель и получатель принадлежат одному потоку, и связь с постановкой в очередь, если отправитель и получатель принадлежат различным потокам. Это можно изменить, передав дополнительный аргумент в connect()
. Помните, что использование прямых связей, когда отправитель и получатель проживают в разных потоках опасно в случае, если цикл обработки сообщений выполняется в потоке, где живет приемник, по той же самой причине, по которой небезопасен вызов функций объекта, принадлежащего другому потоку.
QObject::connect()
само по себе потокобезопасно.
Qt 4.x
правитьКак получить текст ячейки QTableWidget и QTableView?
править(i, j -строка и столбец)
QString buf;
buf = tableWidget->item(i,j)->text();
buf = tableView->model()->data(tableView->model()->index(i,j)).toString();
Как перебрать все QTreeWidgetItem в QTreeWidget? (открыть или закрыть все узлы дерева)
правитьБез рекурсии никак. К сожалению, здесь все не так просто, как хотелось бы.
Итак, допустим, нам надо сделать кнопку, чтобы по нажатию на нее все дерево закрывалось, если оно открыто, или открывалось, если закрыто. Для этого заводим переменную
bool explode;
Далее пишем рекурсивную процедуру такого плана
void MyClass::invertExploder(QTreeWidgetItem* cit)
{
int i;
if (cit == 0 ) return;
if(cit->childCount()>0)
for(i=0;i<cit->childCount();i++)
if(cit->child(i)!=0)
{
if(explode) treeWidget->expandItem (cit->child(i)); // раскрытие
else treeWidget->collapseItem (cit->child(i));// закрытие
invertExploder(cit->child(i)); // самовызов для узла-потомка
}
}
Потом создаем слот, к которому подключаем кнопку
void MyClass::slotInvertExploder() // Думаю здесь довольно понятно
{
int i;
explode = !explode;
if(treeWidget->topLevelItemCount()>0)
for(i=0;i<treeWidget->topLevelItemCount() ;i++)
{
if(explode) treeWidget->expandItem (treeWidget->topLevelItem(i)); // раскрытие
else treeWidget->collapseItem (treeWidget->topLevelItem(i)); // закрытие
invertExploder(treeWidget->topLevelItem(i)); // вызов рекурсивной функции
}
if(explode) toolButton->setArrowType(Qt::DownArrow); //графические примочки
else toolButton->setArrowType(Qt::UpArrow); //их можно вырезать
for(i=0;i<6;i++) treeWidget->resizeColumnToContents (i); // выравнивание по полям(у меня их 6)
}
Как запихнуть в QTreeWidget различные элементы?
правитьКод:
#include <QtGui/QTreeWidget>
#include <QtGui/QCheckBox>
#include <QtGui/QRadioButton>
Tree::Tree(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
ui.setupUi(this);
ui.treeWidget->setColumnCount(1);
QTreeWidgetItem* pItem;
pItem = addItem("1");
pItem = addItem("2");
QTreeWidgetItem* pW01 = addItem(pItem, "");
QTreeWidgetItem* pW02 = addItem(pItem, "");
QTreeWidgetItem* pW03 = addItem(pItem, "");
QTreeWidgetItem* pW04 = addItem(pItem, "");
pItem = addItem("3");
ui.treeWidget->setItemWidget(pW01, 0, new QCheckBox("First property"));
ui.treeWidget->setItemWidget(pW02, 0, new QCheckBox("Second Property"));
ui.treeWidget->setItemWidget(pW03, 0, new QRadioButton("QRadioButton"));
ui.treeWidget->setItemWidget(pW04, 0, new QRadioButton("QRadioButton"));
}
QTreeWidgetItem* Tree::addItem(QString name)
{
QStringList lst;
lst << name;
QTreeWidgetItem* pItem = new QTreeWidgetItem(ui.treeWidget, lst, 0);
return pItem;
}
QTreeWidgetItem* Tree::addItem(QTreeWidgetItem* item, QString name)
{
QStringList lst;
lst << name;
QTreeWidgetItem* pItem = new QTreeWidgetItem(item, lst, 0);
return pItem;
}
Всё очень даже работает. В первом коде виджеты вместо элементов дерева ставились. А в этом в отдельной колонке. Вот код:
#include <QtGui/QTreeWidget>
#include <QtGui/QCheckBox>
#include <QtGui/QRadioButton>
Tree::Tree(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
ui.setupUi(this);
ui.treeWidget->setColumnCount(1);
QTreeWidgetItem* pItem;
pItem = addItem("1");
pItem = addItem("2");
QTreeWidgetItem* pW01 = addItem(pItem, "");
QTreeWidgetItem* pW02 = addItem(pItem, "");
QTreeWidgetItem* pW03 = addItem(pItem, "");
QTreeWidgetItem* pW04 = addItem(pItem, "");
pItem = addItem("3");
ui.treeWidget->setItemWidget(pW01, 0, new QCheckBox("First property"));
ui.treeWidget->setItemWidget(pW02, 0, new QCheckBox("Second Property"));
ui.treeWidget->setItemWidget(pW03, 0, new QRadioButton("QRadioButton"));
ui.treeWidget->setItemWidget(pW04, 0, new QRadioButton("QRadioButton"));
}
QTreeWidgetItem* Tree::addItem(QString name)
{
QStringList lst;
lst << name;
QTreeWidgetItem* pItem = new QTreeWidgetItem(ui.treeWidget, lst, 0);
return pItem;
}
QTreeWidgetItem* Tree::addItem(QTreeWidgetItem* item, QString name)
{
QStringList lst;
lst << name;
QTreeWidgetItem* pItem = new QTreeWidgetItem(item, lst, 0);
return pItem;
}
Каким образом собрать Qt 4.1 без example и demos? Т.е. только средства необходимые для работы.
правитьconfigure.exe -fast
Как собрать плагин для MySQL, MinGW?
правитьПоследние версии MySQL официально не поддерживают сборку под MinGW и соответственно нужной вам библиотеки, в соответствующем формате в поставке нет. Придется сделать ее самому. Примерно так:
- Переходим в каталог с библиотеками MySQL:
cd <путь_к_установленному_mysql>\lib\opt
- Создадим файл DEF (reimp идет вместе с утилитами MinGW и msys):
reimp -d libmysql.lib
- Создаем библиотеку импорта MinGW: В этот момент создается MinGW-совместимая библиотека libmysql.a
dlltool -k --input-def libmysql.def --dllname libmysql.dll --output-lib libmysql.a
- Переходим в каталог с исходными файлами плагина Qt MySQL:
cd <каталог_инсталляции_qt>\src\plugins\sqldrivers\mysql
- Запускаем qmake для генерирования Makefile
qmake -o Makefile "INCLUDEPATH+=<каталог_инсталляции_mysql>\include" "LIBS+=-L<каталог_инсталляции_mysql>\lib\opt -lmysql" mysql.pro
- Собираем плагин
make
- Убеждаемся, что libmysql.dll доступен через path. В случае отсутствия libmysql.dll приложение не сможет загрузить плагин и выдаст сообщение, что нужного плагина нет. При этом в кэш плагинов (в моём случае —
[HKEY_CURRENT_USER\Software\Trolltech\OrganizationDefaults\Qt Plugin Cache 4.2.false]
), будет записана неверная информация. - Если произошла такая неприятность, чистим кэш плагинов, это можно сделать удалив из реестра ветку
[HKEY_CURRENT_USER\Software\Trolltech\OrganizationDefaults]
.
PS: Это было опробовано для MySQL 4.1 (4.1.12a) и OpenSource Win32 Qt4. [Оригинал статьи http://www.qtforum.org/thread.php?postid=52360#post52360]
Как вывести сигнал из плагина?
правитьНиже приведен пример простого плагина, который умеет только вызывать один сигнал.
Интерфейс для подключения плагина
править#ifndef INTERFACE_H
#define INTERFACE_H
#include <QtPlugin>
class PluginInterface : public QObject
{
public:
virtual ~PluginInterface() {}
virtual void someMethod() =0;
signals:
virtual void testSignal() =0;
};
Q_DECLARE_INTERFACE(PluginInterface, "ru.zloiia.PluginInterface")
#endif // INTERFACE_H
Плагин
правитьPro файл
правитьTEMPLATE = lib
CONFIG += plugin
INCLUDEPATH += ../app
DESTDIR = ../plugins
HEADERS += \
plug.h
SOURCES += \
plug.cpp
Описание класса плагина
править#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include "interface.h"
class MyPlugin : public PluginInterface
{
Q_OBJECT
Q_INTERFACES(PluginInterface)
public:
void someMethod();
signals:
void testSignal();
};
#endif // MYPLUGIN_H
Реализация плагина
править#include "plug.h"
void MyPlugin::someMethod()
{
emit testSignal();
}
Q_EXPORT_PLUGIN2(myplugin, MyPlugin)
Как в QListWidget поменять (задать другую позицию) местами элементы?
правитьДля Qt 4.1 и 4.1.1 вот так:
QListWidgetItem* pItem = listWidget->takeItem(K);
listWidget->insertItem(N, pItem);
Как обработать клик на хедере в QtableView ?
правитьСоздается метод класса, например
mySlot(int numCol)
{
... чего-то там ...
}
После этого в конструкторе того же класса пишем:
QHeaderView *pH = tableWidget->horizontalHeader();
connect((QObject*)pH, SIGNAL(sectionClicked (int)), this, SLOT(mySlot(int)));
Как в tableWidget и QTableView получить текст ячейки
править1)
QString buf;
buf=tableWidget->item(i,j)->text();
2)
QString buf;
buf = tableView->model()->data(tableView->model()->index(i,j)).toString();
Текст текущей ячейки можно получить так:
QString buf;
buf = tableView->model()->data(tableView->currentIndex()).toString();