Russian Qt Forum
Ноябрь 22, 2024, 17:44 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО]Быстрое рисование линий инструментом "карандаш"  (Прочитано 13539 раз)
Pritcher
Гость
« : Январь 21, 2016, 21:50 »

Приветствую!

Пытаюсь реализовать рисование линий на виджете, как "карандаш" в Paint, не устраивает скорость отрисовки. Рисование на виджете размером 1000x1000 еще более-менее приемлемое, а вот когда окно становится размером 1920х1080, то линия "не успевает" рисоваться так же быстро, как перемещается курсор.

.h
Код
C++ (Qt)
#pragma once
 
#include <QtWidgets/QWidget>
 
#include <QPen>
 
class MyScene : public QWidget
{
public:
MyScene( QWidget * parent = nullptr );
 
void paintEvent( QPaintEvent * event ) override;
 
protected:
void mousePressEvent( QMouseEvent * event ) override;
void mouseMoveEvent( QMouseEvent * event ) override;
void mouseReleaseEvent( QMouseEvent * event ) override;
 
private:
bool _leftPressed;
QPen _pen;
 
QPointF _startPoint;
QPointF _endPoint;
 
QImage * _image;
};
 

.cpp
Код
C++ (Qt)
#include <QPaintEvent>
 
#include <QPainter>
#include <QImage>
#include <QTimer>
 
const int SZ = 1000;
 
MyScene::MyScene( QWidget * parent ):
QWidget( parent )
{
_pen.setWidth( 1 );
_pen.setColor( Qt::red );
 
_leftPressed = false;
 
_image = new QImage( SZ, SZ, QImage::Format_ARGB32_Premultiplied );
_image->fill( Qt::white );
 
resize( SZ, SZ );
 
QTimer * timer = new QTimer( this );
timer->setInterval( 16 );
 
connect( timer, SIGNAL( timeout() ), this, SLOT( update() ) );
 
timer->start();
}
 
void MyScene::paintEvent( QPaintEvent * )
{
QPainter painter( this );
painter.drawImage( 0, 0, *_image );
}
 
void MyScene::mousePressEvent(QMouseEvent * event)
{
if ( event->button() == Qt::LeftButton ) {
_leftPressed = true;
_startPoint = event->pos();
}
}
 
void MyScene::mouseMoveEvent(QMouseEvent * event)
{
if ( _leftPressed ) {
_endPoint = event->pos();
QPainter painter( _image );
painter.drawLine( _startPoint, _endPoint );
_startPoint = _endPoint;
}
}
 
void MyScene::mouseReleaseEvent(QMouseEvent * event)
{
_leftPressed = false;
}
 
 

Пробовал наследовать MyScene от QOpenGLWidget, использовать в качестве буфера QPixmap вместо QImage, менял частоту срабатывания таймера, делал апдейт непосредственно после отрисовки линии по нужной области — результат один и тот же. В OpenGL не умею, есть ли способы добиться мгновенной отрисовки без задержек не используя OpenGL?

Ну а ответ отрицательный, не могли бы привести пример кода для отрисовки линии средствами OpenGL?

Заранее спасибо.
« Последнее редактирование: Январь 22, 2016, 06:31 от Pritcher » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #1 : Январь 21, 2016, 22:28 »

А для чего эта "жесть" с обнавлением по таймеру?
Ну и вызывайте update из mouseMoveEvent, мосле рисования на backbuffer.
Записан
Bepec
Гость
« Ответ #2 : Январь 21, 2016, 22:30 »

Попробуйте update вызывать с координатами измененного участка.
На данный момент у вас каждый тик отрисовывается вся картинка. При передаче координат измененного участка должен будет перерисовываться только изменённый участок.
Так же вам необходимо будет переписать функцию paintEvent. Чтобы она рисовала не весь рисунок, а только передаваемую в евенте часть.

После этого скорость отрисовки у вас должна возрасти процентов на 90 где то.

Ну потому что вы каждый тик рисуете 1920*1080, а после внесения рекомендованных мною изменений будет отрисовываться где то 20*20. Улыбающийся

to Old:
Там выскакивает проблема слишком частого обновления. MouseMove генерируется на каждый пиксель,а update необходим не чаще чем раз в 10-15 мс Показает язык

PS нужны именно 2 правки - передача участка который нужен обновить и отрисовка только переданного участка. По отдельности эти правки не принесут никакой выгоды Улыбающийся
« Последнее редактирование: Январь 21, 2016, 22:33 от Bepec » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Январь 21, 2016, 22:38 »

to Old:
Там выскакивает проблема слишком частого обновления. MouseMove генерируется на каждый пиксель,а update необходим не чаще чем раз в 10-15 мс Показает язык
Я же вам уже много раз писал, прежде чем писать бред - проверяйте. С чего mouseMove  генерироваться на каждый пиксель?
Записан
Bepec
Гость
« Ответ #4 : Январь 21, 2016, 23:06 »

Я бред не пишу, вы голословно меня обижаете.
Действие: Зажатие и движение слева направо мышью.
Код:
Код:
void MainWindow::mouseMoveEvent(QMouseEvent * event)
{
    qDebug() << event;
}

void MainWindow::mousePressEvent(QMouseEvent * event)
{
    qDebug() << event;
}

void MainWindow::mouseReleaseEvent(QMouseEvent * event)
{
    qDebug() << event;
}
Вывод:
Код:
QMouseEvent(MouseButtonPress, LeftButton, localPos=95,219, screenPos=855,589)
QMouseEvent(MouseMove, buttons=LeftButton, localPos=96,219, screenPos=856,589)
QMouseEvent(MouseMove, buttons=LeftButton, localPos=97,219, screenPos=857,589)
QMouseEvent(MouseMove, buttons=LeftButton, localPos=98,219, screenPos=858,589)
QMouseEvent(MouseMove, buttons=LeftButton, localPos=99,219, screenPos=859,589)
QMouseEvent(MouseMove, buttons=LeftButton, localPos=100,219, screenPos=860,589)
QMouseEvent(MouseMove, buttons=LeftButton, localPos=101,219, screenPos=861,589)
QMouseEvent(MouseButtonRelease, LeftButton, localPos=101,219, screenPos=861,589)


PS с того, что это механика QWidget. При каждом изменении положения указателя генерируется событие MouseMove. По умолчанию mouseMove генерируется только при зажатой кнопке мыши, но можно включить tracking и тогда оно будет генерироваться без кнопки.
« Последнее редактирование: Январь 21, 2016, 23:10 от Bepec » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #5 : Январь 21, 2016, 23:14 »

Вы попробуйте мышью подвигать более размашисто, сразу увидите разрывы.
Записан
Bepec
Гость
« Ответ #6 : Январь 21, 2016, 23:23 »

Да, но это исключение. Более я думаю что это внутренняя оптимизация, т.к. цикл событий будет перегружен если выдавать при таких масштабных движениях столько событий.
 
Тем более что в данном вопросе это без разницы.
Проведя линию в 1000 пикселей за 0,3с., вы вызовите 40-60  циклов перерисовки. Как думаете это поможет ТСсу?

Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #7 : Январь 21, 2016, 23:26 »

Да, но это исключение. Более я думаю что это внутренняя оптимизация, т.к. цикл событий будет перегружен если выдавать при таких масштабных движениях столько событий.
 
Тем более что в данном вопросе это без разницы.
Проведя линию в 1000 пикселей за 0,3с., вы вызовите 40-60  циклов перерисовки. Как думаете это поможет ТСсу?


Не все вызовы update заставляют окно перерисовываться. Попробуйте вместо однократного вызова update, вызывать его в цикле 10 раз. Окно все равно перерисуется единожды.
Записан
Bepec
Гость
« Ответ #8 : Январь 22, 2016, 00:25 »

С этим не спорю, а вот извинений по поводу бреда жду.

Хотелось бы уточнить что имеет в виду ТС под отставанием рисования. К примеру задержка рисования при среднем скорости мыши - есть почти везде. Мб именно её он считает за "тормоза"?
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #9 : Январь 22, 2016, 00:31 »

Верес, если достаточно резко дергать мышкой, то mouseMoveEvent вызовется не для каждого пикселя на пути курсора — отсюда и «отставание рисования»
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Bepec
Гость
« Ответ #10 : Январь 22, 2016, 00:50 »

В проекте ТСса эта проблема решена тем, что у него берётся первая и последняя точка и рисуется линия. Так что этот вариант отпадает. Первая и последняя точка есть всегда, промежуточные вот да, пропадают.

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

Но это уже надо ТСса спросить. Мб у него комп слабый или ещё какие тормоза он имеет в виду.

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

« Последнее редактирование: Январь 22, 2016, 00:53 от Bepec » Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #11 : Январь 22, 2016, 01:49 »

А если в paintEvent обновлять не все изображение, а только кусок, который включает в себя последнюю проведенную линию...?
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #12 : Январь 22, 2016, 05:44 »

С этим не спорю, а вот извинений по поводу бреда жду.
А какие извинения вы ждете, если пишите бред? Разве вы первый раз утверждали то, что не соответствует действительности?

Уже надоело опровергать ваши заявления, которые не понятно для чего вы делаете? Вовсе не обязательно отвечать во всех темах, тем более в которых не разбираетесь.
« Последнее редактирование: Январь 22, 2016, 05:48 от Old » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #13 : Январь 22, 2016, 05:47 »

А отстование у ТС, скорее всего, из-за "странного" способа обновления окна по таймеру.
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #14 : Январь 22, 2016, 06:26 »

Исходникик программы рисования на с++/Qt
Записан

Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.096 секунд. Запросов: 23.