Страницы

Поиск по вопросам

Показаны сообщения с ярлыком qt5. Показать все сообщения
Показаны сообщения с ярлыком qt5. Показать все сообщения

суббота, 11 апреля 2020 г.

Сессии, авторизация

#cpp #qt #сессия #qt5 #auth

                    
Пишу небольшое клиент-серверное приложение на Qt5, встал вопрос об авторизации.
Подскажите актуальные алгоритмы для безопасной авторизации и генерации ID сессии,
был бы рад полистать готовые реализации и примеры.
    


Ответы

Ответ 1



Частично на этот вопрос отвечает " RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication ".Возможно, доступное по этой ссылке. В целом, передавайте хешированный ключ с солью (т.е. по каналу связи следует передавать только хеш-сумму). На стороне сервера хешируйте ключ пользователя с той же солью и сравнивайте хеши. Такой вид аутентификации используется в линукс при авторизации, например. Смотрите также "дайджест-аутентификация". Upd: @Timofey Bondarev, спасибо за ценное замечание.

Ответ 2



Категорически не рекомендую использовать всякие srand() + rand() для генерации чувствительных данных. На винде вполне можно использовать CryptGenRandom из CryptoAPI. В линухах, говорят, /dev/urandom.

Как должны правильно взаимодействовать модель и QSortFilterProxyModel?

#cpp #qt #qt5 #qml

                    
Приветствую! 
Ситуация следующая:
Есть моделька, основанная на QAbstractItemModel, так как данных достаточно много,
получаю их с помощью предназначенного для этого canFetchMore и fetchMore
и когда просто модель отображается в ListView (qml), всё замечательно, данные подгружаются
по мере пролистывания.

Теперь на эту модельку сверху вешаю прокси, на основе QSortFilterProxyModel
в ней для теста отбираю строки (переопределив filterAcceptsRow) по какому нибудь
полю, не важно. 

Дальше начинаются проблемы. 
При установленной фильтрации во вьюшке выводятся не все возможные значения!
т.е. выводятся только загруженные в fetchMore в данный момент. 
Т.е. в fetchMore гружу по 100 записей, не выводятся ни одной, т.к. целевые значения
будут прогружены начиная с 500.
и прогрузки дальше не происходит т.к. логично, что вьюшка не считает необходимым
загружать ещё т.к. всё умещается и не надо пролистывать но и прокси моделька не считает
нужным прогрузить дальше, либо как-то сообщить основной модели - мне нужны записи с
вот такими значениями.

Подскажите, пожалуйста, как быть? 
Не, я согласен, что лучше всего будет выбирать нужные значение через запрос к базе,
что бы не грузить лишнего,
но как тогда лучше сделать связь с основной моделью? 

т.е. например я в fetchRow основной модели прогрузил записи от 0 до 100, в прокси
модели нужно выбирать, которые располагаются начиная с 500, ок, я говорю основной модели
- прогрузи ка записи с вот такими значенияи, если есть.
Ок, гружу. 

Но возникает следующая проблема - если запись например 555 добавлена в модель, то
при скролинге вьюшки, она попросит записи с 500 по 600 и я тогда снова добавлю запись
555. т.е. получается будет дублирование. 
Запоминать записи, которые грузил? что-то костылём попахивает. 
Может есть красивый выход из ситуации?

Спасибо, даже за подсказки, на что смотреть!
    


Ответы

Ответ 1



На мой взгляд, тут может быть только три варианта для решения проблемы. Первый - самый бестолковый, если данных очень много. Предполагает, что модель-источник должна загрузить сразу все данные и не использовать fetchMore в принципе. Второе решение может быть основано на переопределении метода fetchMore() у прокси с тем условием, что будет сразу же (рекурсивно) повторять запрос на чтение новых строк из исходной модели до тех пор, пока количество строк в прокси после filterAcceptsRow() не достигнет нужного числа, либо исходная модель не прочитает все данные. Фактически, это решение почти столь же бестолковое, что и первое, так как потребуется полное считывание всех данных исходной модели при определённых условиях фильтрации. Третье решение предполагает использование фильтрации данных непосредственно в модели-источнике. Обратите внимание, что все SQL-модели из состава Qt имеют возможность фильтровать данные самостоятельно и в общем случае не нуждаются в каких-либо прокси. Если модель-источник является таблицей в БД, то имеет смысл использовать классы, специально предназначенные для работы с подобными источниками, а не заниматься наследованием абстрактной модели. Если же модель-источник не является таблицей в БД, а, например, представляет из себя некий файл, то фильтрация данных должна быть добавлена в эту исходную модель и производиться непосредственно при вызове fetchMore() с тем, чтобы выдать минимальное количество данных, соответствующих условиям фильтрации.

вторник, 31 марта 2020 г.

Имитация нажатии клавиши

#cpp #qt #winapi #visual_cpp #qt5


Имитацию нажатии клавиши делаю так: 

keybd_event('C', 0,0,0);
keybd_event('C', 0,KEYEVENTF_KEYUP,0);


Как сделать что бы имитация нажатии клавиши было только в определенном окне
    


Ответы

Ответ 1



Нет Windows ОС под рукой, чтобы проверить, но все же, попробуйте. HWND wndHndl = FindWindow(_T("ApplicationName"), NULL); PostMessage(wndHndl, WM_KEYDOWN, VK_A, 0);

воскресенье, 29 марта 2020 г.

Нужно ли добавлять .ui файлы в список исходников cmake?

#cpp #qt #qt5 #cmake #qt_designer


Нужно ли добавлять .ui файлы в список исходников cmake?

То есть писать 

add_executable(my_target main.cpp main.h main.ui)


или 

add_executable(my_target main.cpp main.h)


?
    


Ответы

Ответ 1



Как уже написали, в add_executable указывать *.ui-файлы не обязательно. При включённом set(CMAKE_AUTOUIC ON) cmake сам просмотрит все *.cpp файлы на предмет наличия в них include'ов вида ui_*.h и сам обработает соответствующие *.ui файлы. При сборке без AUTOUIC (по каким-либо причинам), .ui файл необходимо передать макросу qt5_wrap_ui(), который явно создаст команду для сборки ui_*.h, а хедер уже сам подтянется по зависимостям к исходнику, который его включает. С другой стороны это не ошибка, add_executable (и прочие) допускают указание в списке исходников файлы, которые непосредственно не участвуют в сборке; в данном случае они не добавляются в качестве зависимости к конкретной цели. Обычно мотивацией к этому является использование IDE. В этом случае проект для оной, сгенерированный cmake, будет включать их в качестве «дополнительных исходников», и они будут отображаться в списке файлов связанных с целью наряду с остальными. Также, человек, поддерживающий проект, может захотеть указать их просто «для себя», чтобы было явно видно при сборке какого файла используется конкретный ui.

Ответ 2



ui файлы не нужно перечислять в add_executable или add_library - это лишено смысла. Эти файлы обрабатываются с помощью uic, так что это он должен знать о том, где искать эти файлы (именно искать). Если ui файлы находяться в тоже директории, то все норм, а если в другой, то нужно установть опцию: set(CMAKE_AUTOUIC_SEARCH_PATHS "paht/to/uic/files")

Ответ 3



На сегодняшний день я не слышал о прямой поддержке .ui файлов в add_executable(). В этой команде перечисляются лишь исходники, которые CMake умеет "собирать" - .c,.cpp,.h,.o,.asm. Файлы .ui обрабатываются специальным макросом qt5_wrap_ui() из модуля Qt5Widgets. См. документацию.

Реализация сигналов и слотов в своём классе

#cpp #qt #qt5


Начал изучать Qt по книге М.Шлее и дошёл до сигналов и слотов, сам механизм понятен.
Попробовал написать простой класс реализующий этот механизм, но Qt Creator выводит
похожие ошибки  


  .../Error in " Util.asciify("build-...-Debug")":-1: error: TypeError:
  Property 'asciify' of object
  Core::Internal::UtilsJsExtension(0x155bb00) is not a
  function/.../tests.cpp:19: undefined reference to
  `SS_Primer::introduce_yourself()'


Класс компилируется

class SS_primer : public QObject {
        Q_OBJECT
    public:
        void send_signal() { emit introduce_yourself(); }
    public slots:
        void show_name() { std::cout << "I'm a slot" << std::endl; }
    signals:
        void introduce_yourself();
};


А этот код не хочет(

bool Test::SignalSlot() {
    SS_primer primer;
    QObject::connect( &primer, SIGNAL(introduce_yourself()), &primer, SLOT(show_name()) );
    primer.send_signal();
    return true;
}


Пробовал создавать объект класса через new, делал send_signal() static функцией принимающей
указатель. 
    


Ответы

Ответ 1



Вангую: Вы сделали все это дело в одном файле, не так ли? Вам следовало повнимательнее почитать Шлее, иначе бы Вы были бы вкурсе, что такое и, главное, как работает метакомпилятор. Короче разнести объявление и реализацию как положено и все заработает. PS Эти ошибки выводит не мифический Qt, а линкер - он вам прямо говорит, что не может найти ваш сигнал. Его действительно нет - можете даже создать динамическую библиотеку и проверить nm-ом. Это из-за того, что moc не отработал. PSS используйте новый синтаксис сигналов-слотов - он гораздо удобнее (за исключением перегруженный слотов) и при ошибках, связанных с неправильным подключением, вы получите больше корректной информации.

суббота, 21 марта 2020 г.

QtС++. Доработать поиск файлов в директории и поддиректориях

#cpp #алгоритм #qt #qt5 #поиск


Есть код:

 // Получение списка файлов в папке
    QStringList nameFilter;
        QDir dir(MTEPathTMP);
        nameFilter.clear();
        nameFilter << "*.png";

        QFileInfoList list = dir.entryInfoList( nameFilter, QDir::Files );
        QFileInfo fileinfo;

        nameFilter.clear();
        foreach (fileinfo, list) nameFilter << fileinfo.absoluteFilePath();


Он ищет файлы по маске в директории.

НО! Он не умеет смотреть в поддиректории. Как можно его доработать, чтоб он мог искать?
    


Ответы

Ответ 1



Уже обсуждалось тут. Я бы рекомендовал не изобретать велосипед с рекурсивной функцией, а применить готовый класс QDirIterator со специальным флагом в параметрах. QDirIterator it("/sys", QStringList() << "scaling_cur_freq", QDir::NoFilter, QDirIterator::Subdirectories); while (it.hasNext()) { QFile f(it.next()); f.open(QIODevice::ReadOnly); qDebug() << f.fileName() << f.readAll().trimmed().toDouble() / 1000 << "MHz"; }

воскресенье, 15 марта 2020 г.

OpenGL Освещение

#cpp #qt #opengl #qt5


Проблема: некорректно работает освещение, выглядит так, будто источник света перемещается
параллельно с вращением объекта. По идее источник света должен быть статичным. Объект
может вращается вокруг своего центра с помощью мыши (и функции glRotated()).
Код:  

//Инициализация света, находится в методе initializeGL()
//Часть параметров такие же как и стандартные
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; 
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightSpecular[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 10.0f, 10.0f, 10.0f, 1.0f };
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); //Я предположил, что загрузка единичной матрицы мне поможет, но нет
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpecular);
glEnable(GL_LIGHT1); //Источник света один


//Отрисовка фигуры
void Canvas::drawAll() //Отрисовка всех фигур
{
   names = 0;
   for(int i = 0; i < figures; i++)
   {
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      glTranslated(motionX, motionY, zoom); //motionX/Y вычисляются при перемещении
курсора при нажатой ПКМ
      glRotated(rotationX, 1.0, 0.0, 0.0); //rotationX/Y также, только при ЛКМ
      glRotated(rotationY, 0.0, 1.0, 0.0);
      if(allFigures[i]->visible)draw(allFigures[i]);
   }
}


Пишу на Qt5.3. Вот как это выглядит: ссылка
    


Ответы

Ответ 1



Оказалось что это ответ: Похоже на глючные нормали

пятница, 13 марта 2020 г.

Снятие фокуса с кнопки

#cpp #qt #gui #qt5


Как снять фокус с кнопки при нажатии на пустую область формы(область формы, где нет
ни одного виджета)?
    


Ответы

Ответ 1



В обработчике нажатия на форму напишите setFocus();, или, если это QMainWindow наследник, тогда centralWidget()->setFocus();. Таким образом фокус перейдёт с кнопки на виджет. Например, это можно сделать так: void MainWindow::mousePressEvent(QMouseEvent *) { centralWidget()->setFocus(); } Т.е. Вы переопределяете виртуальную функцию mousePressEvent в Вашем QMainWindow

понедельник, 24 февраля 2020 г.

Завершение работы QRunnable

#cpp #qt #qt5


Использую QThreadPool и QRunnable. Как завершить работу QRunnable, если тот из очереди
уже перешёл в состояние выполнения?

В QThreadPool имеется метод, позволяющий изымать из пула объекты выполнения, но только
тех из них, что всё ещё находятся в очереди.

По идее, в наследнике QRunnable нужен некий флаг (наподобие QThread::requestInterruption()),
который можно было бы переключать из вне, а уже объект выполнения смотрел бы время
от времени значение этого флага. Соответственно, если настала пора закругляться, то
и завершал бы свою работу.

Однако в этом случае нужно хранить список объектов QRunnable, чтобы иметь возможность
установки флага, и в итоге иметь вероятность краха программы, если QThreadPool кого-либо
из них заблаговременно уничтожит. Отказываться от QRunnable::autoDelete() == true совсем
не хочется.

Есть ли возможность как-то решить эту проблему, не уходя в сторону QThread и не изменяя
QRunnable::autoDelete() == true, так как уж очень подкупает удобство использования
QThreadPool?
    


Ответы

Ответ 1



Если Вас не устраивает функция отмены в наследнике QRunnable, тогда можно сделать по другому. Пусть наследник имеет конструктор, который принимает указатель на QAtomicInteger. Ещё будет конструктор, которые не будет принимать этот указатель — по умолчанию, в классе, он будет равен nullptr. Внутри метода run если указатель не нулевой, и его значение по указателю(полученное через load()) равно, скажем, 1, тогда задание было отменено и мы немедленно завершаем выполнение. Как Вы уже поняли, этот указатель будет предоставляться тем кодом, что создаёт QRunnable и его значение будет выставляться там же. Код может выглядеть так: class MyRunnable: public QRunnable { public: MyRunnable(QAtomicInteger* cancelationToken): m_CancelationToken{cancelationToken} { } void run() override { while(true) { if(m_CancelationToken && m_CancelationToken->load() == 1) return; } } private: QAtomicInteger* m_CancelationToken = nullptr; }; Где-то в коде: QAtomicInteger cancel; auto runnable = new MyRunnable(&cancel); ... cancel = 1;

Приведение const char* к char*

#cpp #qt5


Пытаюсь с QByteArray получить указатель на данные с помощью data(), 
ругается:


ошибка: invalid conversion from 'const char*' to 'char*' [-fpermissive]
char * TempPtrBuff = ARes.data();



В документации пишется, что возвращается char *.

Почему может возникать ошибка?
    


Ответы

Ответ 1



Результат вывода QByteArray::data() зависит от константности метода, в котором производится вызов обозначенной функции. Проще говоря: void MyClass::method() { char *data = ARes.data(); } void MyClass::method() const { const char *data = ARes.data(); } Соответственно, если вывод QByteArray::data() отличен от желаемого, то измените константность метода или осуществите приведение типа, например, тем же const_cast().

Ответ 2



QByteArray::data() имеет перегрузки по наличию константности у объекта QByteArray, для которого данная функция вызывается. Если контекст использования результата вызова data() подразумевает возможность изменения данных через полученный указатель, то нужно использовать именно неконстантный объект QByteArray и использовать тип char* для переменной. Если при этом возникает ошибка как в Вашем вопросе, значит Вы собираетесь изменить данные константного объекта. Это говорит об ошибке в проектировании объемлющего класса (исхожу из предположения, что QByteArray в Вашем случае является членом класса). Если результат data() не предполагается изменять, то на константность объекта QByteArray можно не обращать внимания, а просто использовать const char* для переменной. Попытка убрать константность через const_cast может кончится плачевно (UB), если используемый объект действительно константен. Пример, актуальный для любого типа T: T obj; const T& cref = T; T& ref = const_cast(cref); // OK, т.к. cref реально ссылается на неконстантный объект const T obj; const T& cref = T; T& ref = const_cast(cref); // Плохо, т.к. cref реально ссылается на константный объект Попытка модифицировать obj через ссылку ref во втором случае приводит к неопределенному поведению. Другой способ избежать ошибки в строке инициализации TempPtrBuff - использовать auto: auto TempPtrBuff = ARes.data(); Но это всё равно не даст возможности модифицировать константный объект.

Поддержка уникальности строк в QStringLiteral

#cpp #qt #qt5


Из справки известно, что QStringLiteral размещает текст непосредственно в исполняемом
файле в области только для чтения. Однако я не нашёл информации о том, что в случае
использования одинаковых строк в разных местах кода проекта, эти строки будут храниться
по уникальности значения. Или каждый экземпляр строки будет сохранён отдельно?

Допустим, имеется сетевой запрос к некоему внешнему ресурсу. Этот запрос имеет строковую
команду, скажем, "https://ru.stackoverflow.com/". Также есть два класса: class A и
class B. В обоих требуется выполнять указанный запрос:

class A {
    void getSo() {
        sendRequest(QStringLiteral("https://ru.stackoverflow.com/"));
        // Далее выполняем что-то специфическое для класса A.
    }
};

class B {
    void getSo() {
        sendRequest(QStringLiteral("https://ru.stackoverflow.com/"));
        // Далее выполняем что-то специфическое для класса B.
    }
};


Вопрос заключается в том, что именно попадёт в исполняемый файл: две строки с адресом
запроса или одна? Или я неверно понимаю принцип работы указанного макроса?
    


Ответы

Ответ 1



Стандартом не оговорено. Зависит от компилятора и настроек. Например, в Visual C++ 2015 имеется опция (зависящая от использованных параметров оптимизации) /GF включить объединение строк только для чтения Так что эти литералы будут объединены. Но если скомпилировать без этого ключа или с с /GF-, то в exe'шнике каждая займет свое место (при отключенной оптимизации - включение оптимизации автоматически включает эту опцию).

вторник, 18 февраля 2020 г.

Можно ли в Qt из pro файла выдрать VERSION?

#cpp #qt #qt5


Можно ли в Qt из pro файла выдрать VERSION? И потом использовать его как константу
например.
    


Ответы

Ответ 1



Можно добавить VERSION в DEFINES. pro: VERSION = 1.2.3 DEFINES += VERSION=\\\"$$VERSION\\\" cpp: qDebug() << VERSION; вывод: 1.2.3

воскресенье, 16 февраля 2020 г.

Поддержка уникальности строк в QStringLiteral

#cpp #qt #qt5


Из справки известно, что QStringLiteral размещает текст непосредственно в исполняемом
файле в области только для чтения. Однако я не нашёл информации о том, что в случае
использования одинаковых строк в разных местах кода проекта, эти строки будут храниться
по уникальности значения. Или каждый экземпляр строки будет сохранён отдельно?

Допустим, имеется сетевой запрос к некоему внешнему ресурсу. Этот запрос имеет строковую
команду, скажем, "https://ru.stackoverflow.com/". Также есть два класса: class A и
class B. В обоих требуется выполнять указанный запрос:

class A {
    void getSo() {
        sendRequest(QStringLiteral("https://ru.stackoverflow.com/"));
        // Далее выполняем что-то специфическое для класса A.
    }
};

class B {
    void getSo() {
        sendRequest(QStringLiteral("https://ru.stackoverflow.com/"));
        // Далее выполняем что-то специфическое для класса B.
    }
};


Вопрос заключается в том, что именно попадёт в исполняемый файл: две строки с адресом
запроса или одна? Или я неверно понимаю принцип работы указанного макроса?
    


Ответы

Ответ 1



Стандартом не оговорено. Зависит от компилятора и настроек. Например, в Visual C++ 2015 имеется опция (зависящая от использованных параметров оптимизации) /GF включить объединение строк только для чтения Так что эти литералы будут объединены. Но если скомпилировать без этого ключа или с с /GF-, то в exe'шнике каждая займет свое место (при отключенной оптимизации - включение оптимизации автоматически включает эту опцию).

Можно ли в Qt из pro файла выдрать VERSION?

#cpp #qt #qt5


Можно ли в Qt из pro файла выдрать VERSION? И потом использовать его как константу
например.
    


Ответы

Ответ 1



Можно добавить VERSION в DEFINES. pro: VERSION = 1.2.3 DEFINES += VERSION=\\\"$$VERSION\\\" cpp: qDebug() << VERSION; вывод: 1.2.3

суббота, 8 февраля 2020 г.

Qt 5 парсинг JSON

#json #qt5 #qt #cpp


Имею QByteArray, содержащий следующий JSON:

{
    "response": {
        "count": 2,
        "items": [
            {"name": "somename", "key": 1"},
            {"name": "somename", "key": 1"}
        ]
    }
}


Нужно пропарсить и получить необходимые данные:

  QJsonDocument itemDoc = QJsonDocument::fromJson(answer);
  QJsonObject itemObject = itemDoc.object();

  qDebug() << itemObject;

  QJsonArray itemArray = itemObject["response"].toArray();
  qDebug() << itemArray;


Первый дебаг выводит содержание всего QByteArray, записанное в itemObject, второй
дебаг не выводит ничего.  

Подскажите, может, нужно парсить иначе или почему этот способ не работает?
    


Ответы

Ответ 1



Может проблема из-за невнимательности. response у Вас это не Array, а Object. Потому itemObject["response"].toArray() писать неверно!

среда, 5 февраля 2020 г.

Что происходит когда сокет записывает данные в то время, когда с другой стороны читаются предыдущие данные?

#cpp #qt5 #tcp #сокеты


К примеру у меня есть сокет, который в цикле (2 итерации к примеру) записывает данные
подряд. При этом на другом конце (где этот сокет прослушивается) в это время происходит
считывание. Так вот, что будет когда происходит вторая попытка записи данных в сокет,
когда на другом конце еще считывается первая часть пересланых данных?
    


Ответы

Ответ 1



Если сокет блокирующий и на чтение запрошено больше данных, чем Вы отправляете - будет ждать "второй итерации". Если сокет неблокирующий - вычитает, сколько сможет, и затем Вам снова придется опрашивать сокет. В связи с комментарием @VTT хочу дать немного более развернутый ответ. Если вызывается одна из функций read/recv/recvfrom для блокируемого сокета и при этом в буфере нет никаких данных - сокет переходит в спящее состояние до тех пор, пока не придут какие-либо данные. Достаточно одного байта. Тем не менее, мы можем задать флаг MSG_WAITALL - в этом случае мы будем ждать до тех пор, пока не будет доступно фиксированное (запрошенное нами) количество байт. В случае неблокируемого сокета - если не удовлетворены условия ввода - то ф-ия вернет управление установив ошибку EWOULDBLOCK. Если вызывается одна из функций write/send/sendto - данные копируются из буфера приложения в буфер отправки сокета. Для блокируемого сокета - если в буфере отправки недостаточно места, процесс переходит в состоянии оидания до тех пор, пока это самое место не освободится. Для неблокируемого сокета - если в буфере отправки недостаточно места - ф-ия вернет управление, установив ошибку EWOULDBLOCK. Комбинируйте и предполагайте наиболее вероятный результат того, чем же все-таки окончится посылка двух сообщений :)

Ответ 2



В общем случае, попытки записи и чтения данных будут не связаны. Вторая попытка записи может происходить совершенно независимо от поведения (или даже от наличия) партнера на другой стороне. Более того, когда вызов функции записи на первой итерации успешно вернется, нет оснований полагать, что только что отправленные данные на самом деле куда-то ушли. Если активирован алгоритм Нейгла, то только что посланные данные могут спокойно сидеть в буфере на стороне отправителя. Даже если подкрутить настройки (допустим TCP_NODELAY), то данные на момент второго вызова записи могут еще быть где-то в пути, или сидеть в буфере на принимающей стороне.

Qt: возможен ли неявный connect?

#cpp #qt #qt5


Мне дали доработать приложение написанное с использованием Qt. В приложении есть
некий диалог унаследованный от QDialog. В этом диалоге есть QPushButton по имени btnCheck.
Так же есть обработчик нажатия на эту кнопку:

private slots:
void on_btnCheck_clicked();


И нигде в этом проекте не вызывается connect связывающий сигнал clicked кнопки btnCheck
со слотом on_btnCheck_clicked в этом диалоге. Поиск по файлам всего проекта находит
всего лишь два вхождения слова on_btnCheck_clicked: при объявлении и при определении
этой функции.

При этом фактически связь есть - при нажатии на кнопку вызывается этот обработчик.

Подскажите пожалуйста, как кроме вызова connect можно связать сигнал и слот? Просмотрел
документацию, но там ничего про это не нашёл.
    


Ответы

Ответ 1



В "Signals & Slots", есть ссылка automatic connections там написано, что, для этого надо чтобы имя слота было объявлено специальным образом: void on__();

Ответ 2



Судя по всему, в проекте используются UI файлы, которые обрабатываются uic, генерирующим код подключения автоматически. Подробнее можно почитать в Widgets and Dialogs with Auto-Connect

четверг, 23 января 2020 г.

Вытягивания виджетов

#cpp #qt #gui #qt5 #интерфейс


Я работаю в qt5. Эта кнопка("addButton")  отвечает за создание этих кнопок("GreenButton")
. В слоте addButton создается GreenButton:

void SearchForm::on_AddButtonButton_pressed()
{
     Editor.pobj = new GreenButton(this);
}


Код GreenButton:

QPoint delta;

    void mousePressEvent(QMouseEvent* e)
        {
            delta.rx()   = e->pos().x();
            delta.ry()   = e->pos().y();
        }

        void mouseMoveEvent(QMouseEvent* e)
        {

            setGeometry(
                    geometry().x()  + e->pos().x() - delta.x(),
                    geometry().y()  + e->pos().y() - delta.y(),
                    width(),
                    height()
            );
        }

        explicit GreenButton(QWidget *parent = 0 ) 
        {


            setGeometry(QCursor::pos().x() - parent->geometry().x() - 8,
                        QCursor::pos().y() - parent->geometry().y() - 8,
                        111,
                        111
            );
            show();
            QMouseEvent event1(QEvent::MouseButtonPress,  this->pos(), Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);

            QApplication::sendEvent(this, &event1);
        }


GreenButton создается , перемещается мышью. Как сделать чтобы при нажатии на addButton
и не отпускании ее перемещался GreenButton?
Я думал поможет искуственное создание событий, но не помогло:

QMouseEvent event1(QEvent::MouseButtonPress,  this->pos(), Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
QApplication::sendEvent(this, &event1);

    


Ответы

Ответ 1



Т.к. у нас есть форма, на которой размещена «добавляющая кнопка», и на ту же форму мы добавляем другие кнопки, предлагаю воспользоваться следующей стратегией: Устанавливаем фильтр сообщений на нашу «добавляющую» кнопку. Будем ловить нажатие и перемещение мыши. Во время нажатия будем создавать новую кнопку и запоминать её. Во время появления события перемещения, будем перемещать нашу кнопку. Всё это довольно просто реализовать: MainWindow.h: #pragma once #include class QPushButton; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget* parent = 0); bool eventFilter(QObject* obj, QEvent* event); private: QPushButton* m_CurrentButton; }; MainWindow.cpp: #include #include #include #include #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { auto widget = new QWidget(this); auto addButton = new QPushButton("add", widget); setCentralWidget(widget); addButton->installEventFilter(this); } bool MainWindow::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::MouseButtonPress) { auto mouseEvent = static_cast(event); m_CurrentButton = new QPushButton("new", centralWidget()); auto localPoint = mapFromGlobal(mouseEvent->globalPos()); m_CurrentButton->move(localPoint); m_CurrentButton->show(); return true; } if(event->type() == QEvent::MouseMove) { auto mouseEvent = static_cast(event); auto localPoint = mapFromGlobal(mouseEvent->globalPos()); m_CurrentButton->move(localPoint); return true; } return QObject::eventFilter(obj, event); } На базе этого кода, Вы можете адаптировать свой код.

Ответ 2



Сначала решение: class MyForm: public QWidget { QTimer * Ticker ; QPushButton * MovingButton; public: MyForm(QWidget * parent = nullptr) : QWidget (parent ) , Ticker (nullptr) , MovingButton(nullptr) { Ticker = new QTimer(this); connect(Ticker, &QTimer::timeout, this, &MyForm::moveButton); } ~MyForm() { stopMoving(); } public slots: void addPressed() { MovingButton = new QPushButton(this); // настраиваем новую кнопку MovingButton->show(); // Начинаем перемещение через пол секунды Ticker->setSigngleShot(true); Ticker->setInterval(500); Ticker->start(); } void addReleased() { stopMoving(); // останавливаем движение } void moveButton() { if(MovingButton) { if(Ticker->singleShot()) // ускоряем таймер до 30 мс { Tciker->setSignleShot(false); Ticker->setInterval(30); } // двигаем кнопку MovingButton->move(MovingButton->pos() + QPoint(8,8)); } } private: void stopMoving() { MovingButton = nullptr; Ticker->stop(); } }; Здесь addPressed() и addReleased() слоты которые должны быть подключены с сигналам кнопки AddButton pressed() и released() соответственно. Работает код следующим образом: В обработчике нажатия addPressed() создаем новую кнопку и запоминаем указатель на нее в MovingButton, потом стартуем таймер Ticker на пол секунды по окончании которого выполняем перемещение. Пол секунды нужно для того чтобы была пауза перед началом движения. В обработчике таймера Ticker moveButton() ускоряем таймер до 30 мс а также перемещаем текущую кнопку MovingButton если таковая имеется. В обработчике отпускания addRelease() просто зануляем указатель на перемещаемую кнопку MovingButton и останавливаем таймер Ticker - таким образом останаваливаем движение.

Ответ 3



предложу необычный вариант: - AddButton сделать наследником от GreenButton - Как только AddButton кликнули, что означает добавление, AddButton меняет своё рисование, на рисование предка. То есть, начинает рисоваться, как GreenButton. - Новый AddButton на месте старого можно сделать как в начале таскания, так и по его окончанию - зависит от сценария

Вращение изображения в PyQt5

#python #python_3x #qt5 #pyqt5


Нужно открыть картинку и вращать ее по часовой стрелке по команде. Вот мой код, в
который нужно вставить данную фичу:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
from PyQt5.QtWidgets import (QWidget, QInputDialog,
    QPushButton, QApplication, QTextEdit, QLabel, QLineEdit,QFrame )
from PyQt5.QtGui import QBrush, QPalette, QPixmap, QPainter, QPen, QImage
from PyQt5.QtCore import Qt, QTimer, QPointF, QRect
from PIL import Image


class Collector(QWidget):

    def __init__(self):
        super().__init__()
        self.timer = QTimer()
        self.timer.timeout.connect(self.process_timeout)
        self.timer.start(10)  # 50 -- период в милисекундах
        self.phi = 0
        self.lbl = QLabel(self)

    def process_timeout(self):
        if self.phi == 0:
            self.phi += 5
        elif self.phi == 5:
            self.phi -= 5
        self.update()
    def showInputTc_h(self):
        text, ok = QInputDialog.getText(self, "input Dialog", "Enter data:")
        if ok:
            self.textEdit_Tc_h.setText(str(text))

    def showInputTr(self):
        text, ok = QInputDialog.getText(self, "input Dialog", "Enter data:")
        if ok:
            self.textEdit_Tr.setText(str(text))

    def showInputTt(self):
        text_Tt, ok = QInputDialog.getText(self, "input Dialog", "Enter data:")
        if ok:
            self.textEdit_Tt.setText(str(text_Tt))

    def lable_text_button(self):
        Tt = QPushButton("Tt", self)
        Tt.move(480, 130)
        Tc_h = QPushButton("Tc-h", self)
        Tc_h.move(400, 10)
        Tr = QPushButton("Tr", self)
        Tr.move(900, 530)

        self.textEdit_Tt = QLineEdit(self)
        self.textEdit_Tt.setGeometry(QRect(100, 90, 81, 31))
        self.textEdit_Tt.setObjectName("textEdit")
        self.textEdit_Tt.move(400, 130)
        Tt.clicked.connect(self.showInputTt)

        self.textEdit_Tr = QLineEdit(self)
        self.textEdit_Tr.setGeometry(QRect(100, 90, 81, 31))
        self.textEdit_Tr.setObjectName("textEdit")
        self.textEdit_Tr.move(800, 530)
        Tr.clicked.connect(self.showInputTr)

        self.textEdit_Tc_h = QLineEdit(self)
        self.textEdit_Tc_h.setGeometry(QRect(100, 90, 81, 31))
        self.textEdit_Tc_h.setObjectName("textEdit")
        self.textEdit_Tc_h.move(300, 10)
        Tc_h.clicked.connect(self.showInputTc_h)

    def get_image_size(self, img):
        im = Image.open(img)
        (width, height) = im.size
        return (width, height) # вернем ширину и висоту

    def draw_y(self, qp, x0, y0, range_int, const_y):
        for i in range(range_int):
            y0 -= 20 * i
            x1 = x0
            y1 = y0 + 10
            qp.drawLine(QPointF(x0, y0), QPointF(x1, y1))
            y0 = const_y

    def draw_x(self, qp, x0, y0, range_int, const_x):
        for i in range(range_int):
            x0 += 20 * i
            y1 = y0
            x1 = x0 + 10
            qp.drawLine(QPointF(x0, y0), QPointF(x1, y1))
            x0 = const_x

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        pen = QPen(Qt.red, 1)
        qp.translate(0, self.height())
        qp.scale(1, -1)
        qp.setPen(pen)
        pomp = QPixmap()
        QFrame.paintEvent(self, e)

        # width1 = 992,
        # height = 679
        list_y = [(292, 627, 12), (292, 320, 4), (485, 595, 2), (183, 183, 7), (465,
40, 3)]
        list_x = [(150, 637, 7), (310, 385, 6), (486, 607, 27), (183, 64, 14), (480,
64, 6), (690, 64, 16)]
        for y in list_y:
            self.draw_y(qp=qp, x0=y[0], y0=y[1]+self.phi, range_int=y[2], const_y=y[1]+self.phi)

        for x in list_x:
            self.draw_x(qp=qp, x0=x[0]+self.phi, y0=x[1], range_int=x[2], const_x=x[0]+self.phi)

        pen = QPen(Qt.blue, 1)
        qp.setPen(pen)
        list_y_cold = [(5, 627, 15), (240, 386, 3), (183, 317, 4), (296, 183, 2),
(485, 312, 3), (652, 562, 15)]
        list_x_cold = [(10, 347, 3), (113, 347, 3), (199, 347, 6), (345, 347, 4),
(296, 153, 37), (485, 272, 26), (656, 570, 18)]
        for y_cold in list_y_cold:

            self.draw_y(qp=qp, x0=y_cold[0], y0=y_cold[1]+self.phi, range_int=y_cold[2],
const_y=y_cold[1]+self.phi)

        for x_cold in list_x_cold:
            self.draw_x(qp=qp, x0=x_cold[0]+self.phi, y0=x_cold[1], range_int=x_cold[2],
const_x=x_cold[0]+self.phi)
        qp.end()

def main():
    app = QApplication(sys.argv)

    w = Collector()
    palette = QPalette()
    palette.setBrush(QPalette.Background,       QBrush(QPixmap("images/scheme.jpg")))
    size = w.get_image_size("images/scheme.jpg")
    w.setMaximumSize(size[0], size[1])
    w.setMinimumSize(size[0], size[1])
    w.setWindowTitle('Sun')
    w.setPalette(palette)
    w.lable_text_button()
    w.show()

    sys.exit(app.exec())

if __name__ == '__main__':
    main()

    


Ответы

Ответ 1



Чтобы вращать картинку, отображаемую с помощью QPixmap, можно QTransform().rotate() использовать. Код, основанный на ответе @Jean-Sébastien: #!/usr/bin/python3 """Usage: rotate-image """ from PyQt5.Qt import QImage, QLabel, QPixmap, QTransform, QWidget, Qt class ImageRotor(QWidget): def __init__(self, image_path, parent=None): super().__init__(parent) self.label = QLabel(self) self.image = QImage(image_path) # keep original image for rotation self.angle = 0 self.label.setAlignment(Qt.AlignCenter) # NOTE: keep image on screen pm = QPixmap(self.image) self.resize(pm.width(), pm.height()) # fit window to image self.label.setPixmap(pm) self.setWindowTitle('PyQt5 Image Rotor') def keyPressEvent(self, event): # on any key self.angle += 45 if event.key() == Qt.Key_Down else -45 t = QTransform().rotate(self.angle) self.label.setPixmap(QPixmap(self.image).transformed(t)) return super().keyPressEvent(event) if __name__ == '__main__': import sys from PyQt5.Qt import QApplication if len(sys.argv) < 2: # wrong arguments sys.exit(__doc__) # print usage app = QApplication(sys.argv) w = ImageRotor(sys.argv[1]) # center on screen w.move(app.desktop().screen().rect().center() - w.rect().center()) w.show() sys.exit(app.exec_()) При нажатии на любую клавишу, изображение, указанное в командной строке, вращается на 45 градусов. Если нажать на клавишу ↓ («вниз»), то по часовой стрелке вращение. начальный размер окна подгонятся под изображение используется выравнивание по центру, чтобы при повороте изображение не убегало сохраняется оригинальное изображение, чтобы повторные повороты не искажали бы картинку

среда, 22 января 2020 г.

Qt5 кроскомпиляция из под Windows в ARM

#windows #qt #qt5 #arm #кросс_компиляция


Пытаюсь настроить Qt Creator (qt5.10.1) что бы можно было компилировать в нём проекты
для ARM систем.  

Но не знаю с чего начать, в интернете много каких-то мануалов, но все они не понятны
и сложны.  

Почему надо делать множество настроек (лезть  в конфиги кумейк.конф), когда можно
было бы создать простейший установщик и не париться?  



Установил  


  gcc-arm-none-eabi-7-2018-q2-update-win32.exe 


Прописал компилятор С:  


  arm-none-eabi-gcc.exe (директория ..\GNU_Tools_Arm_Embedded\7_2018-q2-update\bin)


Прописал компилятор С++:  


  arm-none-eabi-g++.exe (директория ..\GNU_Tools_Arm_Embedded\7_2018-q2-update\bin)


Прописал отладчик:  


  \GNU_Tools_Arm_Embedded\7_2018-q2-update\bin\arm-none-eabi-gdb.exe


Но где взять СMake? Где взять профиль Qt (для gcc-arm-а)?



Учёл ответ Павла и попробовал для начала собрать Qt из исходников по примеру  (для
начало на винду) 

C:\Qt\qt5\qt-everywhere-src-5.10.1\configure -platform ARM
+cd qtbase
+C:\Qt\qt5\qt-everywhere-src-5.10.1\qtbase\configure.bat -top-level -platform ARM 
Host platform 'ARM' is invalid. Aborting.


Попробовал так :

call configure.bat  -recheck-all -static -release -prefix C:\Qt\qt5\qt-relise-5_10_1
-opensource -confirm-license -nomake tools -nomake examples -nomake tests


Но увы снова не заработало

Cannot detect host toolchain. Please use -platform. Aborting.






Дополнил вызовом -platform linux-arm-gnueabi-g++


    


Ответы

Ответ 1



Вам нужно собрать Qt из исходников под вашу целевую операционную систему, либо попробовать найти у кого-то уже собранный. Обратите внимание: не для конкретного процессора, а для процессора+ОС.