0 / 0 / 0
Регистрация: 17.03.2016
Сообщений: 28
1

Блокирование потока при изменении размера окна

08.07.2016, 00:57. Показов 1186. Ответов 13

Здравствуйте. Есть форма, в которой находится QLabel и QThread который который постоянно устанавливает новый QPixmap для нее.
Во время ресайза окна нужно как-то заблокировать потоку доступ к QLabel, иначе происходит вылет программы. Пробовал использовать для этого QMutex и QMutexLocker, но так и не понял как они работают. Как из функции ресайза окна заблокировать доступ к QLabel(viewf в коде)? Ниже часть кода:

Изменение размеров окна:
C++ (Qt)
1
2
3
4
5
6
7
8
void camera::resizeEvent(QResizeEvent *event){
    if(camworking){
        viewf->setGeometry(0, 0, this->width(), this->height()); //Нужна блокировка 
        upshadow->setGeometry(0, 0, this->width(), 50);
        downshadow->setGeometry(0, this->height() - 50, this->width(), 50);
    }
    event->accept();
}
Метод run() потока, который устанавливает новый pixmap (viewFinder = viewf из блока выше):
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
void openCVframeWorker::run(){
    cv::Mat inputFrame;
    while(enableUpdateViewfinder){
        cap->read(inputFrame);
        if(!inputFrame.empty()){
            cv::cvtColor(inputFrame, inputFrame, CV_BGR2RGB);
            QImage output((uchar*)inputFrame.data, inputFrame.cols, inputFrame.rows, inputFrame.step, QImage::Format_RGB888);
            viewFinder->setPixmap(QPixmap::fromImage(output)); //Здесь вылетает, если не заблокировать доступ
        }
    }
}
Так-же пробовал блокировать с помощью bool переменной, и с помощью ожидания завершения потока перед изменением, но все эти варианты не дают гарантии от вылета.
Как правильно использовать QMutex в данном случае?
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.07.2016, 00:57
Ответы с готовыми решениями:

Крах программы, при изменении размера окна
Здравствуйте. Играюсь с QPaintEvent'ом. Рисую фрактал простенький и проблема заключается в том,...

Qml изменение размера Canvas при изменении размера окна
Может есть какой нибудь способ, чтобы при изменении размера окна (в моем случае window) изменялся...

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

Изменение размера обьектов при изменении размера графического окна
Можно ли в pascalABC.net сделать следующее: чтобы приизменении размера графического окна изменялись...

13
137 / 107 / 23
Регистрация: 06.10.2008
Сообщений: 451
08.07.2016, 09:52 2
Как вариант:
Не использовать в потоке "viewFinder". А передавать из него QPixmap с помощью сигналов и слотов (Qt::QueuedConnection) в основной поток.
1
19 / 19 / 4
Регистрация: 27.05.2013
Сообщений: 119
08.07.2016, 13:26 3
resizeEvent это если я верно понимаю уже окончание ресайза.
а вам скорее всего нужно заблокировать поток на время самого ресайза
тоесть нужно два события, начало и конец.
А так, как мютексом заблокировать поток могу кинуть если нужно пример, вроде ничего сложного
1
Эксперт С++
8381 / 6142 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.07.2016, 14:41 4
Цитата Сообщение от Mixxxxa Посмотреть сообщение
Во время ресайза окна нужно как-то заблокировать потоку доступ к QLabel,
Изначально не правильный код. Не должно быть прямых обращений(без средств синхронизации) из потока к элементам форм.
1
14 / 13 / 4
Регистрация: 30.09.2015
Сообщений: 130
08.07.2016, 15:01 5
я полагаю вы создали свой клас типа qthread, и прописали к нему коннекты, тогда попробуйте в момент входа в ресайз сделать

potok->blocksignals(true); а на выходе potok->blocksignals(false);
и да, как сказал оратор выше, это костыли
1
0 / 0 / 0
Регистрация: 17.03.2016
Сообщений: 28
08.07.2016, 18:48  [ТС] 6
Цитата Сообщение от mevn Посмотреть сообщение
Не использовать в потоке "viewFinder". А передавать из него QPixmap с помощью сигналов и слотов (Qt::QueuedConnection) в основной поток.
Сделал. В итоге интерфейс снова начал тормозить. Поэтому и перенес эту функцию в поток.

Цитата Сообщение от Olex Посмотреть сообщение
А так, как мютексом заблокировать поток могу кинуть если нужно пример, вроде ничего сложного
Если можно, в ЛС

Цитата Сообщение от Avazart Посмотреть сообщение
Изначально не правильный код. Не должно быть прямых обращений(без средств синхронизации) из потока к элементам форм.
А как сделали бы Вы? Я еще новичок, многих тонкостей не знаю.

Цитата Сообщение от SkaDi Посмотреть сообщение
potok->blocksignals(true); а на выходе potok->blocksignals(false);
Пробовал блокировать переменной, но не всегда срабатывает.
0
Эксперт С++
8381 / 6142 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.07.2016, 19:11 7
Цитата Сообщение от Mixxxxa Посмотреть сообщение
Я еще новичок,
Читал бы книги...
0
19 / 19 / 4
Регистрация: 27.05.2013
Сообщений: 119
08.07.2016, 19:13 8
Цитата Сообщение от Mixxxxa Посмотреть сообщение
Если можно
примерно так. Но нужно определить правильный сигнал где наичнается
изменение размеров (может быть кто то подскажет) и сделать lock(); а уже в resizeEvent unlock().

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMutex>
#include <QThread>
#include <QMainWindow>
 
namespace Ui {
class MainWindow;
}
 
class mThread : public QThread{
 
public :
 
      QMutex *mutex;
      mThread( );
      void run();
} ;
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
    QMutex m_mutex;
    mThread m_thread;
 
   virtual bool event(QEvent * event){
        QMainWindow::event(event);
    }
 
    virtual void resizeEvent(QResizeEvent *ev){
       
        //тут блокировка и разблокировка 
       //как если бы изменение размеров происходило
       //в QMainWindow::resizeEvent(ev);
        m_mutex.lock();
 
        QMainWindow::resizeEvent(ev);
 
        m_mutex.unlock();
 
    }
 
private slots:
 
 
private:
    Ui::MainWindow *ui;
};
 
#endif // MAINWINDOW_H
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_thread.mutex = &m_mutex;
    m_thread.start();
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
mThread::mThread()
{
 
}
void mThread::run()
{
 
    while(1){
        mutex->lock();
        //какая то работа в треде
        sleep(1);
        mutex->unlock();
    }
}
 Комментарий модератора 
Код С++\Qt оформляется с помощью тега CPPQT.
1
Эксперт С++
8381 / 6142 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.07.2016, 20:01 9
Мютекс тут вряд ли поможет, лучше попробовать пересылать QImage сигнал/слотом из потока в главное окно, а там уже в слоте помещать QImage в QLabel.

Единственно... только сомневаюсь что вы правильно сможете это сделать учитывая что вы используете метод наследования QThread.
0
0 / 0 / 0
Регистрация: 17.03.2016
Сообщений: 28
08.07.2016, 20:19  [ТС] 10
Цитата Сообщение от Olex Посмотреть сообщение
примерно так.
Как я понял, нужно создать в основном классе мутекс и его же передать в поток, чтобы и он, и основное окно могли его блокировать?

Цитата Сообщение от Avazart Посмотреть сообщение
лучше попробовать пересылать QImage сигнал/слотом из потока в главное окно, а там уже в слоте помещать QImage в QLabel
Сделал. Но при этом сильно падает производительность:

Функция в потоке:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
void openCVframeWorker::run(){
    cv::Mat inputFrame;
    while(enableUpdateViewfinder){
        cap->read(inputFrame);
        if(!inputFrame.empty()){
            cv::cvtColor(inputFrame, inputFrame, CV_BGR2RGB);
            QImage image((uchar*)inputFrame.data, inputFrame.cols, inputFrame.rows, inputFrame.step, QImage::Format_RGB888);
            QPixmap output = QPixmap::fromImage(image);
            emit resultReady(output);
        }
    }
}
Функция приемник:
C++ (Qt)
1
2
3
void camera::setViewfPixmap(const QPixmap &pic){
    viewf->setPixmap(pic);
}
Цитата Сообщение от Avazart Посмотреть сообщение
сомневаюсь что вы правильно сможете это сделать учитывая что вы используете метод наследования QThread
Сейчас найду рабочее решение и перепишу на другой вариант (создание потока и передача функции в этот поток)
0
19 / 19 / 4
Регистрация: 27.05.2013
Сообщений: 119
08.07.2016, 21:13 11
Цитата Сообщение от Mixxxxa Посмотреть сообщение
Но при этом сильно падает производительность:
попробуй передвать указатели, должно быть быстрее
только потом память не забудь освободить
C++
1
2
 QPixmap *pm = new QPixmap;
*pm = QPixmap::fromImage(image);
1
Эксперт С++
8381 / 6142 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
08.07.2016, 23:40 12
openCVframeWorker - это что? Наследник QThread или QObject("рабочий")?

Цитата Сообщение от Mixxxxa Посмотреть сообщение
Сейчас найду рабочее решение
Вы только искать умеете? Или может начнете думать?
0
0 / 0 / 0
Регистрация: 17.03.2016
Сообщений: 28
10.07.2016, 01:58  [ТС] 13
В принципе тему можно закрывать. Проблему решил передачей некоторых функций в поток.
Теперь при ресайзе окна появляется сигнал, который передается функции в потоке, и она уже производит нужные манипуляции с объектом. В таком варианте не нужны никакие блокировки.

Функция ресайза окна:
C++ (Qt)
1
2
3
4
5
6
7
8
void camera::resizeEvent(QResizeEvent *event){
    if(camworking){
        emit resizeViewfinder(this->width(), this->height()); //Сигнал передает данные о новом размере
        upshadow->setGeometry(0, 0, this->width(), 50);
        downshadow->setGeometry(0, this->height() - 50, this->width(), 50);
    }
    QWidget::resizeEvent(event);
}
Принимающий слот:
C++ (Qt)
1
2
3
void openCVframeWorker::resizeViewfinder(int w, int h){
    viewf->setGeometry(0, 0, w, h); //Изменяет размер
}
Цитата Сообщение от Avazart Посмотреть сообщение
Наследник QThread или QObject("рабочий")
В начале, был наследником Qthread, сейчас уже наследуется от QObject.
0
Эксперт С++
8381 / 6142 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
12.07.2016, 18:43 14
Цитата Сообщение от Mixxxxa Посмотреть сообщение
таком варианте не нужны никакие блокировки.
Откуда такая уверенность?
C++
1
2
3
void openCVframeWorker::resizeViewfinder(int w, int h){
    viewf->setGeometry(0, 0, w, h); //Изменяет размер
}
Если viewf это компонент формы, то нет так нельзя делать из другого потока.

Цитата Сообщение от Mixxxxa Посмотреть сообщение
В начале, был наследником Qthread, сейчас уже наследуется от QObject.
Странно.
Нужно смотреть код, но думаю можно было бы попробовать применить QAtomicPointer http://doc.qt.io/qt-5/qatomicpointer.html
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
12.07.2016, 18:43
Помогаю со студенческими работами здесь

Артефакт при изменении размера окна
Создал панель на основе класса CDockablePane, все бы ничего если бы при изменении его размеров оно...

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

Изменение Форм при изменении размера окна
Доброй ночи Подскажите пожалуйста как правильно реализовать изменение (положение) форм и элементов...

Изменение меню при изменении размера окна
Здравствуйте. Видел на одном из сайтов такой прием, когда окно во весь экран меню имеет обычный вид...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru