Обязательно ли Qt :: paintEvent быть реентерабельным?

Могу ли я поместить рисовальщика в переменные класса? :

protected:
QPainter *myPainter;

...

void MyWidget::paintEvent(QPaintEvent *event)
{
    myPainter = new QPainter(this);

Почему вы хотите это сделать? Почему бы не положить его в стопку?

shoosh 11.10.2008 10:16

Приложение рисует морские флаги. Я хочу создать дюжину методов для рисования элементов флага и объединить их в paintEvent. Мне нужны такие методы, как «DrawWedge ()», а не «DrawWedge (QPainter * painter)».

danatel 11.10.2008 23:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
2 037
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

void MyWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    // use painter
    ...
    // paint object automatically closes and paint on desctruction
}

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

Harald Scheirich 11.10.2008 14:53

«Обычно QPainter используется внутри события рисования виджета: создайте и настройте (например, установите перо или кисть) рисовальщика. Затем нарисуйте. Не забудьте уничтожить объект QPainter после рисования».

mxcl 14.10.2008 18:56

Если вы пытаетесь избежать передачи виджета рисовальщика нескольким вызовам подпрограмм, вы, вероятно, можете обойтись указателем на рисовальщика в качестве переменной класса. Как уже упоминалось, вы все равно должны создавать / уничтожать его в функции paintEvent. Лично я, вероятно, просто передал бы его вспомогательным функциям, но вы могли бы сделать это и так.

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

Спасибо за ваш ответ. Под повторным входом я подразумеваю эту конкретную ситуацию: 1) обработчик paintEvent сохраняет QPainter в переменную класса. 2) обработчик paintEvent вызывает подпрограммы для рисования чего-либо 3) одна из подпрограмм вызывает метод Qt 4) этот метод Qt рекурсивно генерирует другое событие paintEvent

danatel 16.10.2008 19:06
Ответ принят как подходящий

Новый anser для более конкретного решения проблемы повторного входа ...

данатель оставил следующий комментарий к это сообщение (частично):

By reentrancy I mean this specific situation: 1) paintEvent handler saves a QPainter to a class variable. 2) paintEvent handler calls subroutines to draw something 3) one of the subroutines calls a Qt method 4) this Qt method generates another paintEvent recursively

Ответ на этот вопрос состоит в том, что это должно быть приемлемо, если только вы не сделаете что-то действительно странное. (И если вы сделаете что-то столь странное, Qt, скорее всего, предупредит вас или прервет работу.) Я думаю, что все еще может быть некоторая путаница в том, что вы подразумеваете под повторным входом, но генерация paintEvent не остановит поток выполнения текущего действия, чтобы немедленно обработать это событие. Вместо этого (как и все события) оно будет поставлено в очередь для последующей обработки. Пока вы не выполняете многопоточность и не вызываете processEvents, порядок выполнения кода, пока вы находитесь в одной из своих собственных функций, должен быть очень простым.

В качестве примера давайте проследим ваши шаги и рассмотрим их более подробно.

  1. Foo::paintEvent() обработчик создает QPainter и устанавливает Foo::m_painter_p у него.
  2. Foo::paintEvent() звонки Foo::paintAntarticaFlag().
  3. Foo::paintAntarticaFlag(): а) использует Foo::m_painter_p, затем б) вызывает то, что вызывает Foo::update(), затем в) использует еще немного Foo::m_painter_p.
  4. Foo::update(), который на самом деле является методом Qt, генерирует событие paintEvent для Foo.

Вышеупомянутая последовательность подходит, поскольку обновление создает мероприятие, что означает отложенную обработку. Если вместо этого вы вызовете Foo :: repaint (), это вызовет немедленную рекурсию в Foo :: paintEvent (), что либо вызовет прерывание Qt, потому что вы создаете более 1 рисовальщика для одного и того же объекта, либо ваша программа прервется потому что в конце концов (вы знаете, за несколько сотен миллисекунд) стек уничтожил.

Если вы выполняете несколько потоков и просто хотите вызвать перерисовку, вы все равно можете сделать это из другого потока, поскольку он просто поместит событие paintEvent в очередь, чтобы его обработал соответствующий поток в нужное время. Если вы выполняете несколько потоков и хотите рисовать эти флаги с помощью одного и того же рисовальщика, не надо. Только не надо. В этом случае вы можете рассмотреть возможность рисования каждого флага на общем изображении и рисования этого изображения там, где вы сейчас используете QPainter.

Другие вопросы по теме