Qt/ЧАВО

Материал из Викиучебника — открытых книг для открытого мира
< 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("Русский текст");
  1. Откройте файл MainWindow.qml в qtcreator что бы была возможность редактировать в виде текста
  2. Переходим в меню «Правка»->"Выбор кодировки". Принудительно выставляем Utf8
  3. Далее стираем русский текст и пишем его заново без всяких qsTr. Теперь qml файл у нас полностью в utf8
  4. Компилируем, запускаем.

После этого русский текст отобразился правильно. То есть, отсюда вывод: 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 и соответственно нужной вам библиотеки, в соответствующем формате в поставке нет. Придется сделать ее самому. Примерно так:

  1. Переходим в каталог с библиотеками MySQL:
    cd <путь_к_установленному_mysql>\lib\opt
    
  2. Создадим файл DEF (reimp идет вместе с утилитами MinGW и msys):
    reimp -d libmysql.lib
    
  3. Создаем библиотеку импорта MinGW:
    dlltool -k --input-def libmysql.def --dllname libmysql.dll --output-lib libmysql.a
    
    В этот момент создается MinGW-совместимая библиотека libmysql.a
  4. Переходим в каталог с исходными файлами плагина Qt MySQL:
    cd <каталог_инсталляции_qt>\src\plugins\sqldrivers\mysql
    
  5. Запускаем qmake для генерирования Makefile
    qmake -o Makefile "INCLUDEPATH+=<каталог_инсталляции_mysql>\include" "LIBS+=-L<каталог_инсталляции_mysql>\lib\opt -lmysql" mysql.pro
    
  6. Собираем плагин
    make
    
  7. Убеждаемся, что libmysql.dll доступен через path. В случае отсутствия libmysql.dll приложение не сможет загрузить плагин и выдаст сообщение, что нужного плагина нет. При этом в кэш плагинов (в моём случае — [HKEY_CURRENT_USER\Software\Trolltech\OrganizationDefaults\Qt Plugin Cache 4.2.false]), будет записана неверная информация.
  8. Если произошла такая неприятность, чистим кэш плагинов, это можно сделать удалив из реестра ветку [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();