Страницы

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

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

Как сделать мигающее окно

#qt #многопоточность


Делаю сейчас программу, в которой второе окно должно мигать морзянкой сменяя черный
фон белым. Я уже и через таймер попробовал в самом коде окна и в отдельный поток выкладывал.
Сейчас у меня такой вариант(тестовый) и он не работает. Появляется белое окно, потом
проходит время равное сумме всех интервалов таймера и потом окно становится черным,
хотя задумка теста - окно должно мигать несколько раз с интервалом, заданным в таймере

for(int j = 0; j < 3; j++)
{
        this->setPalette(QPalette(Qt::white));
        this->show();
        m_timer->start(2000);
}


коннект для приема сигнала от таймера

QObject::connect(m_timer, SIGNAL(timeout()), this, SLOT(BlackWindow()));

и сам слот

void morzewindow::BlackWindow()
{
    this->setPalette(QPalette(Qt::black));
    this->show();
    m_timer->stop();
}


Может у кого-то была подобная задача реализованная средствами Qt? помогите. Мне как
новичку уже ни одной идеи в голову не приходит. Все что знал, о чем подозревал, все
перепробовал.

UPDATE:

запуск потока и функции в нем:

MorzeBlinkTimer.moveToThread(&MorzeBlinkThread);
    QObject::connect(&MorzeBlinkTimer, SIGNAL(latency(bool)), SLOT(Blink(bool)));
    MorzeBlinkThread.start();
    MorzeBlinkTimer.startBlink(etalon2.GetReadyCodeMorzeForBlink());


функцию запускаю вручную, потому что она принимает указатель на массив с морзянкой.

//слот для смены цвета окна морзянки черный/белый

void morzewindow::Blink(bool BlackWhite)
{
    if(BlackWhite)
    {
        this->setPalette(QPalette(Qt::white));
        this->show();
    }
    else
    {
        this->setPalette(QPalette(Qt::black));
        this->show();
    }
}


и сама функция потока, которая вводит задержку(фрагмент):

void startBlink(int* morze)
{
    for(int i = 0; i < 50; i++)
    {
        switch(morze[i])
        {
        case 0:
            emit latency(true);
            QThread::msleep(iDot);
            emit latency(false);
            QThread::msleep(iPauseSymbol);
            break;
}
}
}

    


Ответы

Ответ 1



Все правильно, пока все функции не отработают и не "встанут" в ожидании событий в графическом интерфейсе - он не обновится. Делать надо отдельным потоком, но там есть тонкости, тоже долго получалось как у вас - что не реагировало окно ни на что, пока не отработают все события. Вот рабочий пример обновления графического интерфейса в отдельном потоке. В основной функции у вас должно быть примерено так: //Starting process in the new thread Worker * pWorker = new Worker; QThread * pThread = new QThread(); pWorker->moveToThread(pThread); connect(pThread, SIGNAL(started()), pWorker, SLOT(slotDummyUpdatingRequest())); // сигнал старта потока соединяем с функцией имеющей задержки connect(pWorker, SIGNAL(sigDummyNextRequestStage()), this, SLOT(slotStageRequestPrint())); // сигнал от объекта осуществляющего задержки на обновление окна соединяем со слотом обновления окна текущего оъекта pThread->start(); И сам слот обновления графики, срабатывающий асинхронно: void UpdatingRequestState::slotStageRequestPrint() { //здесь идет установка внешнего вида элементов, в моем случае используется QML QObject * pList = m_pQmlObject->findChild("requestList"); m_strListView.append(tr("requesting info...")); pList->setProperty("model", m_strListView); } Ну и собственно функция, выполняемая в отдельном потоке, по сигналам которой интерфейс обновляется void Worker::slotDummyUpdatingRequest() { //dummy imitation of the work for (int i = 0; i < 5; i++) { QThread::msleep(500); // задержка emit sigDummyNextRequestStage(); qDebug() << "Updating Request..."; } }

Ответ 2



Реализовано с использованием стандартных потоков (нет необходимости создавать отдельные классы, просто выполняем функцию в отдельном потоке, не прерывая выполнение GUI-потока): #include #include #include #include void blinkBackground(QWidget* w) { for (int i = 0; i < 3; ++i) { // 1 секунду показываем красный цвет. w->setStyleSheet("background-color: red;"); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 0.5 секунды показываем желтый цвет. w->setStyleSheet("background-color: yellow;"); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } } int main(int argc, char** argv) { QApplication app(argc, argv); QWidget w; w.show(); std::thread t(blinkBackground, &w); t.detach(); return app.exec(); } Похожий функционал, но используя QT Threads, можно также реализовать через QtConcurrent::run, например: void blinkBackgroundQt(QWidget* w) { for (int i = 0; i < 3; ++i) { w->setStyleSheet("background-color: red;"); QThread::msleep(1000); w->setStyleSheet("background-color: yellow;"); QThread::msleep(500); } } int main(int argc, char** argv) { ... QtConcurrent::run(blinkBackgroundQt, &w); ... } И третий способ с использованием QThread и отдельного класса был уже описан в другом ответе.

Комментариев нет:

Отправить комментарий