Проблемы с QGraphicsPixmapItem, обрабатывающим события мыши в QGraphicsScene

Я создал объект:

class Button : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT
public:
    Button();
    virtual QRectF boundingRect() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;

    // QGraphicsItem interface
protected:
    virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
    virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
signals:
    void clicked();
private:
    bool m_pressed;
    QPixmap m_buttonPixmap, m_pressedButtonPixmap;
};

затем я реализовал несколько функций:

Button::Button()
    : m_pressed(false)
{
    m_buttonPixmap = PixmapManager::Instance()->getPixmap(PixmapManager::Button);
    m_pressedButtonPixmap = PixmapManager::Instance()->getPixmap(PixmapManager::PressedButton);
    setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable);
}

QRectF Button::boundingRect() const
{
    return QRectF(-m_buttonPixmap.width() / 2.0f,
                  -m_buttonPixmap.height() / 2.0f,
                  m_buttonPixmap.width(),
                  m_buttonPixmap.height());

}

void Button::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    if (m_pressed) {
        //painter->drawPixmap(0,0, m_pressedButtonPixmap);

    }
    else {
        painter->setBrush(Qt::red);
        painter->drawRect(boundingRect());
        //painter->drawPixmap(0,0, m_buttonPixmap);
    }
}

void Button::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "pressed ";
    m_pressed = true;
    update();
    QGraphicsPixmapItem::mousePressEvent(event);
}

void Button::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "released ";
    m_pressed = false;
    update();
    QGraphicsPixmapItem::mouseReleaseEvent(event);
}

Я также создал QGraphicsScene с элементом Button:

MenuScene::MenuScene(QObject *parent)
    : QGraphicsScene(parent)
{
    setSceneRect(0,0, SCREEN::PHYSICAL_SIZE.width(), SCREEN::PHYSICAL_SIZE.height());
    addItem(&m_startButton);
}

void MenuScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Scene pressed";
    QGraphicsScene::mousePressEvent(event);
}

void MenuScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    qDebug() << "Scene released";
    QGraphicsScene::mouseReleaseEvent(event);
}

Если я нажму на кнопку, я получу только информацию из MenuScene, например «Сцена нажата» / «Сцена выпущена».

В main.cpp я использовал:

    MenuScene* ms = new MenuScene();
    QGraphicsView gv;
    gc.show();

Я пробовал использовать: m_startButton.setAcceptedMouseButtons(Qt::AllButtons); m_startButton.setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); но без результата.

Да, я сделал. Я использовал класс Button: public QObject, public QGraphicsPixmapItem и переопределения для событий мыши: // Интерфейс QGraphicsItem protected: virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) override; виртуальная пустота mouseReleaseEvent (QGraphicsSceneMouseEvent *event) переопределение;

Bondrusiek 26.07.2024 18:43

Хорошо, я сделал минимальный воспроизводимый пример.

Bondrusiek 29.07.2024 17:46
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обнаружение столкновений мыши всегда использует функцию items() представления с флагом Qt::IntersectsItemShape, чтобы проверить, на какие элементы может повлиять событие мыши, а это означает, что результат всегда основан на shape() элемента.

Хотя поведение QGraphicsItem по умолчанию заключается в возврате QPainterPath на основе boundingRect(), это не относится ко всем подклассам, включая QGraphicsPixmapItem, который создает путь на основе своего растрового изображения (и, возможно, с учетом его маски).

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

Таким образом, самое простое решение — вызвать setPixmap(m_buttonPixmap) в конструкторе, а затем снова вызвать setPixmap() с любыми растровыми изображениями в соответствующем обработчике событий мыши.

В качестве альтернативы вы можете переопределить shape(), создать QPainterPath, использовать addRect(boundingRect()) и вернуть его (вам также следует рассмотреть возможность кэширования как ограничивающего прямоугольника, так и пути, чтобы избежать ненужных накладных расходов).

Однако обратите внимание, что вы практически не пользуетесь преимуществами каких-либо функций QGraphicsPixmapItem: вы не только не используете его возможности смещения, режима преобразования или маскировки, но также в конечном итоге рисуете растровые изображения самостоятельно.
Учитывая это, на самом деле нет смысла создавать из него подкласс с самого начала, и вы, вероятно, могли бы просто наследовать от QGraphicsObject, который уже наследуется как от QObject, так и от QGraphicsItem.

Оно работает. Большое спасибо! Решением является метод shape(). Я использовал: QPainterPath Button::shape() const {QPainterPath path; path.addRect(boundingRect()); Обратный путь; } Я также заменил QGraphicsPixmapItem на QGraphicsObject.

Bondrusiek 30.07.2024 17:48

@Bondrusiek Хорошо, пожалуйста. Обратите внимание: если вы просто создаете подкласс QGraphicsObject, вам больше не нужно переопределять shape(), поскольку оно следует поведению QGraphicsItem по умолчанию, которое уже возвращает QPainterPath на основе boundingRect(), как объяснено в ответе.

musicamante 30.07.2024 20:38

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