Синхронизировать рисование прямоугольника, используя распространение событий мыши - PullRequest
0 голосов
/ 11 июня 2018

У меня есть базовый класс MainWidget, который наследует QOpenGLWidget.MainWidget имеет 2 дочерних класса ColorWidget и BWWidget.Я хочу синхронизировать рисование прямоугольника между обоими дочерними виджетами, т.е. когда я начинаю рисовать фигуру на ColorWidget, она должна появиться на BWWidget.Я переписал mouseMoveEvent для базового класса, чтобы рисовать прямоугольники.

void MainWidget::mouseMoveEvent(QMouseEvent* event)
{
    if(m_mousePressed && event->type() == QEvent::MouseMove)
    {
        // check some conditions
        if (/*conditions*/)
        {
            m_activeItem.reset(new Rectangle(this));

            m_activeItem->show();
        }
    }
}

Я могу рисовать прямоугольники на дочерних классах индивидуально.Но я хочу, чтобы их рисовали одновременно.Я попытался переписать mouseMoveEvent для обоих дочерних классов, но кажется, что вызов MainWidget::mouseMoveEvent() из дочерних классов приведет к бесконечному циклу и падению.

В моем случае родительский класс для ColorWidget и BWWidget является QDockWidget, а мой Rectangle класс наследует QLabel.

Не уверен, как я могу это реализовать.

1 Ответ

0 голосов
/ 11 июня 2018

Я не уверен, что на 100% понимаю, о чем вы спрашиваете здесь (в основном, потому что вы не предоставили минимальный скомпилируемый пример), вот что я понял:

  • У вас есть два виджета,
    • один из типов class ColorWidget : public MainWidget
    • один из class BWWidget : public MainWidget
    • с class MainWidget : public QOpenGLWidget
  • Эти два виджетавидимый бок о бок.
  • Когда один из двух ваших виджетов получает mouseMoveEvent(), оба должны что-то отображать.

Если это то, что у вас есть, это ваши варианты:

  1. Прежде всего, вы должны переместить функциональность, чтобы создать прямоугольник из вашего обработчика событий перемещения мыши (например, в функцию MainWidget::DrawMouseMoveRectangle(QPoint pos).
    • . Это уже делает случайную рекурсивностьвызовы менее вероятны.
  2. (возможно :) Сделайте оба виджета известными друг другу (например, через QPointer<MainWidget> pOther).
    • Переопределите mouseMoveEvent() и позвоните DrawMouseMoveRectangle(QPoint pos)для this и pOther.
  3. (лучше :) Поскольку вы уже используете Qt, создайте сигнал MainWidget::SignalMouseMove(QPoint p) и слот MainWidget::MouseMovedSlot(QPoint p).
    • При инициализации общего родительского виджета вы подключаете слоты обоих виджетов к сигналу каждого виджета (см. Ниже).
    • В MainWidget mouseMoveEvent() do emit SignalMouseMove(evt->pos)*
      • (*) Возможно, вам нужно передать некоторый контекст для правильной интерпретации геометрии.
    • Теперь обе функции вызываются независимо от виджета, который получил событие.

Как выполнить подключение:

bool ok = true;
ok = ok && connect(w1, &MainWidget::SignalMouseMove, w1, &MainWidget::MouseMovedSlot);
ok = ok && connect(w1, &MainWidget::SignalMouseMove, w2, &MainWidget::MouseMovedSlot);
ok = ok && connect(w2, &MainWidget::SignalMouseMove, w1, &MainWidget::MouseMovedSlot);
ok = ok && connect(w2, &MainWidget::SignalMouseMove, w2, &MainWidget::MouseMovedSlot);
Q_ASSERT(ok);

РЕДАКТИРОВАТЬ

Ответ на ваш комментарий:

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

Отображение одного и того же экземпляра виджета в двух разных родительских виджетах может возможно, но определенно выглядит как кладж, а не как Qt.

Вы должны взглянуть на Qt's модель-представление-программирование , потому что это, по сути, то, чего вы хотите достичь:

  • Отображение одной модели в двух видах.
  • Обновление обоих видов при любом изменении модели.

Поскольку реализация QAbstractItemModel немного избыточна для этого, вот несколько альтернатив:

  • Использование Graphics View Framework Qt :Отобразите то же самое QGraphicsScene за две QGraphicsView с и поместите в сцену немного QGraphicsRectItem.
  • Используйте поддержку параметров Qt для полуавтоматического связывания данных.
  • Сверните свое, этоне так уж сложно:
    • По сути, вы должны отделить логику view от логики model , например, RectangleView и RectangleModel.
    • Затем сделайте два соединяемых, например, через сигналы в модели и слоты в представлениях.
    • Создайте представление в обоих ваших виджетах.
    • Дайте каждому виджету общий указательк модели.
    • Соедините модель с обоими видами.
    • Результат: Всякий раз, когда вы меняете модель (из которойвиджет не имеет значения), оба представления будут обновлены.

РЕДАКТИРОВАТЬ 2: очень простой пример с использованием общего QGraphicsRectItem

// this is a minimal compilable example of two views sharing the same model, with automatic update on mouse events
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QMouseEvent>
#include <QHBoxLayout>

class TestWidget : public QWidget
{
    //Q_OBJECT // Not neccessary here because we don't use and don't need moc for this example. -> Don't try this at home!
public:
    TestWidget() : QWidget(Q_NULLPTR),
        lt(new QHBoxLayout(this)),
        v1(new QGraphicsView(this)),
        v2(new QGraphicsView(this)),
        s(new QGraphicsScene(this)),
        r(Q_NULLPTR)
    {
        // initialization
        r = s->addRect(0, 0, 10, 10, QPen(Qt::red), Qt::yellow);

        lt->addWidget(v1);
        lt->addWidget(v2);

        // sharing the same model:
        v1->setScene(s);
        v2->setScene(s);
        // in reality, you need to share QGraphicsRectItem *r, too.
        // (it would actually be sufficient to share *r only)

        // very simple mouse interaction:
        v1->viewport()->installEventFilter(this);
        v1->viewport()->setMouseTracking(true);
        v2->viewport()->installEventFilter(this);
        v2->viewport()->setMouseTracking(true);
    }

    bool eventFilter(QObject *o, QEvent *evt) Q_DECL_OVERRIDE
    {
        QGraphicsView *gv = Q_NULLPTR;
        if(o == v1->viewport())
        {
            gv = v1;
        }
        else if(o == v2->viewport())
        {
            gv = v2;
        }

        if(gv != Q_NULLPTR)
        {
            QPointF p;
            switch(evt->type())
            {
            case QEvent::MouseMove:
                p = static_cast<QMouseEvent*>(evt)->pos();
                evt->accept();
                break;
            default:
                break;
            }
            if(p != QPoint())
            {
                // do something different depending on interacting view - just for demonstration
                if(gv == v1)
                {
                    r->setRect(QRectF(p, r->rect().bottomRight()));
                }
                else
                {
                    r->setRect(QRectF(r->rect().topLeft(), p));
                }
            }
        }
        return QWidget::eventFilter(o, evt);
    }

private:
    QHBoxLayout *lt;
    QGraphicsView *v1;
    QGraphicsView *v2;
    QGraphicsScene *s;
    QGraphicsRectItem *r;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    TestWidget w;
    w.show();
    return a.exec();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...