Сборка Qt Virtual Keyboard и добавление русской раскладки

Qt Virtual Keyboard Русская раскладка

Qt Virtual Keyboard — это библиотека предоставляющая виртуальную экранную клавиатуру. Она входит в библиотеку Qt начиная с Qt 5.7. Точнее, она и раньше входила, но была доступна только в коммерческой версии.

По умолчанию клавиатура из официальной сборки Qt поддерживает только английскую раскладку. Если нужны раскладки на других языках, то проект Qt Virtual Keyboard нужно пересобрать.

Далее приводится инструкция по сборке Qt Virtual Keyboard и добавлению русской раскладки в Линукс. Все действия выполняются в консоле. Для Виндовс инструкция не приводится, но она похожа.

Библиотека Qt должна быть установлена вместе с исходным кодом. Для этого при установке нужно отменить пункт Sources.

Установка исходного кода Qt

Создадим папку для сборки и перейдем в нее.

mkdir /tmp/build-qtvirtkb
cd /tmp/build-qtvirtkb

Создадим переменную, содержащую путь к папке, в которой установлен Qt.

QTDIR=/opt/Qt5.9.1/5.9.1

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

Сконфигурируем проект Qt Virtual Keyboard с помощью qmake.

$QTDIR/gcc_64/bin/qmake "CONFIG += lang-en lang-ru" $QTDIR/Src/qtvirtualkeyboard
 

Языки раскладок задаются в строке "CONFIG += lang-en lang-ru". Таким образом клавиатура будет поддерживать английскую и русскую раскладки. Полный список языков приведен в официальной документации. Если указать"CONFIG += lang-all", то клавиатура будет поддерживать все возможные языки.

Соберем проект с помощью make.

make

Сборка занимает некоторое время.

Следующая команда установит новую сборку. Нужно учесть, что будут внесены изменения в официальную сборку Qt. Она заменит файлы клавиатуры на те, которые получены во время новой сборки. Предыдущие файлы невозможно будет восстановить.

sudo make install

Готово. Теперь в клавиатуре будет русская раскладка.

Если нужно изменить раскладки, то нужно пересобрать проект следующими командами.

make distclean
$QTDIR/gcc_64/bin/qmake "CONFIG += lang-all" $QTDIR/Src/qtvirtualkeyboard
make
sudo make install

Первая команда нужна, чтобы очистить сборку.

Реклама

Библиотека Qmakelib

Создал библиотеку Qmakelib. Библиотека расширяет возможности Qmake. Утилита Qmake используется для сборки проектов на Qt.

Библиотека выпущена под лицензией MIT, что дает большую свободу ее применения, в том числе в закрытых коммерческих проектах.

Библиотека работает с Qt 4 и Qt 5.

Получить библиотеку можно следующей командой.

git clone https://github.com/bravikov/qmakelib.git

Для использования библиотеки включите ее в свой проект, добавьте следующую строчку в файл .pro.

include(qmakelib/qmakelib.pri)

После включения можно вызывать функции библиотеки. Например.

qtVersionLessThan(5, 0, 0) {
    message("Qt 4")
}
else {
    message("Qt 5")
}

В первый выпуск библиотеки включены функции для проверки версии Qt.

Функции сравнивают версию Qt с версией x.y.z.

  • qtVersionEqualTo(x, y, z)
  • qtVersionLessThan(x, y, z)
  • qtVersionLessThanOrEqualTo(x, y, z)
  • qtVersionGreaterThan(x, y, z)
  • qtVersionGreaterThanOrEqualTo(x, y, z)

где:

  • x — мажорная версия,
  • y — минорная версия,
  • z — патч-версия.

Библиотеку можно протестировать на своей версии Qt если выполнить следующую команду.

qmake qmakelib/test/qmakelib_test.pro

Поиск использования сигналов в Qt Creator

В Qt Creator можно встать курсором на переменную или функцию, вызвать контекстное меню и выбрать «Найти использование».

Qt Creator найти использование

Тогда Qt Creator найдет все места, где используется эта переменная или функция.

Но это не работает на сигналах, которые подключаются по старому стилю, то есть с использование макроса SIGNAL().

connect(
    object1,
    SIGNAL(superSignal()),
    object2,
    SLOT(superSlot())
);

Qt Creator просто не будет ничего искать, если вы попробуете сделать это на функции, которая заключена в SIGNAL().

Кроме того, Qt Creator не найден подключения сигнала если вы попытаетесь поискать в блоке signals в классе.

class SuperClass
{
...
signals:
    superSignal();
}

В этому случае Qt Creator найдет только испускания сигнала (emit).

Решение есть — использовать современный способ подключения сигналов и слотов, без макросов SIGNAL() и SLOT().


connect(
    obj1,
    &SuperClass1::superSignal,
    obj2,
    &SuperClass2::superSlot
);

Данный синтаксис был введен в Qt 5.0 в 2012 году.

Официальное описание сигналов и слотов в Qt на английском.

Удаление объектов в Qt

Эта статья учит избегать утечек памяти и ошибок сегментирования при программировании на C++ с библиотекой Qt.

qt segmetation fault fuuu

Читать далее Удаление объектов в Qt

Правила кодирования в Qt

640px-qt_logo_2016-svg

При использовании Qt я предпочитаю использовать стиль кодирования, который используется в библиотеке, чтобы добиться единообразия кода.

Директивы препроцессора

Символ решетки всегда в начале строки, а имя директивы с отступом.

Пример из файла Qt5.9.0/5.9/gcc_64/include/QtCore/qobjectdefs.h.

# if defined(QT_NO_KEYWORDS)
#  define QT_NO_EMIT
# else
#   ifndef QT_NO_SIGNALS_SLOTS_KEYWORDS
#     define slots Q_SLOTS
#     define signals Q_SIGNALS
#   endif
# endif

Ссылки и указатели

Операторы & и * в обозначении типа смещены вправо и примыкают к имени.

Пример из файла Qt5.9.0/5.9/gcc_64/include/QtCore/qbytearray.h.

class Q_CORE_EXPORT QByteArray
{
    <...>
    QByteArray &prepend(char c);
    QByteArray &prepend(int count, char c);
    QByteArray &prepend(const char *s);
    QByteArray &prepend(const char *s, int len);
    QByteArray &prepend(const QByteArray &a);
    QByteArray &append(char c);
    QByteArray &append(int count, char c);
    QByteArray &append(const char *s);
    QByteArray &append(const char *s, int len);
    QByteArray &append(const QByteArray &a);
    <...>
}

Приватные поля

В имени приватного поля используется префикс m_.

Пример из файла Qt5.9.0/5.9/gcc_64/include/QtCore/qstring.h.

class QLatin1String
{
public:
    <...>
private:
    int m_size;
    const char *m_data;
};

Ссылки

О других правилах кодирования можно узнать по следующим ссылкам.

Красивая разница в Git для файла проекта Qt

Обычно, при добавлении файлов в проект Qt, разница файла проекта (*.pro) в Git выглядит следующим образом.

bad-diff-in-git-qt-pro

Добавили всего 2 файла foo3.h и foo3.cpp, а получили 6 изменений.

Разницу можно сделать намного симпатичней, если в конце каждого файла добавлять слеш, а в конце каждого списка комментарий # END.

good-diff-in-git-qt-pro

Получается при добавлении двух файлов всего 2 изменения.

Такой способ требует полуручного редактирования файла проекта.

Печать HTML-документа в Qt 5.8

23 января 2017 года вышла Qt версии 5.8, в которой появилась поддержка печати полноценных HTML-документов.

До этого возможность напечатать документ тоже была. Можно было:

  • Использовать метод QTextDocument::Print(). Но приходилось ограничиваться небольшими возможностями HTML и CSS.
  • Использовать метод QWebFrame::print(), который существовал пока не вышла Qt 5.6. Потом в Qt был окончательно заменен веб-движок и поддержка печати пропала.
  • Использовать печать в PDF с помощью метода QWebEnginePage::printToPdf(), который появился в Qt 5.7. Но печать в PDF — это не печать через принтер.
  • Вывести видимую часть страницы на печать методом QWebEngineView->render(). Но это плохой обходной путь, так как не вся страница будет выведена на печать и потребуется отобразить страницу.

В Qt 5.8 появился метод QWebEnginePage::print(), который выводит на печать HTML-документы без отрисовки в окне и поддерживает современные возможности HTML, CSS и JavaScript.

Следующий код выводит HTML-документ на принтер.

#include <QDebug>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrinterInfo>
#include <QWebEnginePage>

void MainWindow::on_printButton_clicked()
{
    QPrinter * printer = new QPrinter();

    QPrintDialog printDialog(printer, this);
    if (printDialog.exec() != QDialog::Accepted) {
        return;
    }

    QWebEnginePage * page = new QWebEnginePage;

    page->setHtml("<html><body>Привет<body/></html>");

    connect(
        page,
        &QWebEnginePage::loadFinished,
        [page, printer] (bool ok) {
            if (!ok) {
                qDebug() << "Загрузка документа провалилась."; 
                delete page;
                delete printer;
                return;
            }

            page->print(printer, [page, printer](bool ok) {
                if (ok) {
                    qDebug() << "Документ напечатан.";
                }
                else {
                    qDebug() << "Печать документа провалилась.";
                }
        
                delete page;
                delete printer;
            });
        }
    );
}

В файле проекта (*.pro) нужно подключить два модуля с помощью следующей строчки.

QT += printsupport webenginewidgets

В коде используются лямбда-выражения, которые появились в C++11. Это конструкции вида: [...] (...) {...}, анонимные функции внутри функций. В Qt 5.8 по умолчанию включен C++11.

Класс QWebEnginePage обрабатывает, отрисовывает и печатает документы асинхронно с основным кодом программы, поэтому код в лямбда-функциях выполняется уже после того, как завершится метод on_printButton_clicked().

Надо внимательно следить за удалением объектов, чтобы не возникло утечки памяти и ошибки сегментации, особенно при печати нескольких документов в цикле. Объект принтера может быть одним, а выводимых на печать документов несколько. Тогда объект принтера надо удалять, после печати последнего документа, и не забывать, что печать происходит асинхронно. То есть функция print() завершается еще до вывода документа на печать.

Но и у этого способа печати есть огромный недостаток. К сожалению модуль Qt WebEngine, в который входит класс QWebEnginePage, недоступен при сборке проекта с помощью MinGW в Виндовс. Собрать проект в Виндовс можно только с помощью Visual Studio.

Локализация (перевод) программ на Qt

qt_logo_2016-svg

Локализация — это адаптация программы к культуре какой-либо страны, в частности перевод пользовательского интерфейса.

В Qt есть инструменты для создания мультиязычной программы. Qt позволяет автоматически отобразить интерфейс программы на языке операционной системы, либо сделать так, чтобы пользователь мог выбрать язык интерфейса.

Далее представлена пошаговая инструкция локализации программы. С помощью инструкции достигается максимальная автоматизированность сборки и простота развертывания программы.

Читать далее Локализация (перевод) программ на Qt

Форматная строка для представления даты и времени в разных системах

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

В таблице ниже приведена форматная строка для получения даты и времени в следующем виде:

2016.06.14 23:10:06

(14 июня 2016 год, 23 часа 10 минут 6 секунд. Год из 4 цифр. Месяц, день месяца, часы, минуты и секунды из двух цифр, дополняются нулями. Часы в 24 формате).

Система шаблонов Форматная строка
date (Linux) %Y.%m.%d %H:%M:%S
C/C++ %Y.%m.%d %H:%M:%S
Python %Y.%m.%d %H:%M:%S
SQLite %Y.%m.%d %H:%M:%S
ISO 8601 YYYY.MM.DD hh:mm:ss
Qt yyyy.MM.dd hh:mm:ss
C# yyyy.MM.dd HH:mm:ss

Ошибка линковки при наследовании QObject

Захотел добавить в свой существующий класс поддержку сигналов и слотов. Сделал все как положено, унаследовал QObject, вызвал макрос Q_OBJECT:

class MyClass: public QObject
{
    Q_OBJECT

public:
    MyClass() {};
    virtual ~MyClass() {};
};

Но при сборке получил ошибку линковщика:

ошибка: undefined reference to `vtable for MyClass’

При сборке не вызывалась программа moc для файла, который содержал этот класс.

Проблема решилась вызовом qmake с помощью меню «Сборка -> Запустить qmake» в QtCreator.