Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Перемещение QFrame
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt GUI
AD
У меня имеется QFrame (визир) c формой QFrame::VLine. Я переопределяю QFrame, т.е. создал потомка от QFrame. Этот QFrame находится на виджете. У виджета определены функции нажатия, движения и отпускания мыши. У QFrame тоже определены. Как заставить QFrame передвинуться и встать на нужное новое место? При этом хотелось бы, чтобы функции передвижения мыши не вызывались. Я правильно понимаю, что в переопределенном виджете надо как-то перехватывать фокус при наведении на визир и ставить флаг игнорирования, а в функциях переопределения мыши виджета проверять флаг игнора? Какую виртуальную функцию виджета надо перехватить при наведении фокуса на визир?
Вот функции мыша визира:
class VFFrame: public QFrame
{
//.....................
bool _is_left_pressed;        ///< флаг указания нажатия на левую кнопку мыши
//.....................
        virtual void mousePressEvent(QMouseEvent* events);
    virtual void mouseMoveEvent(QMouseEvent* events);
    virtual void mouseReleaseEvent(QMouseEvent* events);
};
/// Переопределение нажатия на лекую кнопку мыши
void VFFrame::mousePressEvent(QMouseEvent* events)
{
    QFrame::mousePressEvent(events);

    switch(events -> button())
    {
    case Qt::LeftButton:                ///< если нажата левая кнопка мыши
        _is_left_pressed = true;
    break;
    }
}

/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
    QFrame::mouseMoveEvent(events);

    if(!_is_left_pressed) return;
    move(events -> pos());
}

/// Отпускание кнопки мыши
void VFFrame::mouseReleaseEvent(QMouseEvent* events)
{
    QFrame::mouseReleaseEvent(events);

    if(!_is_left_pressed) return;
    _is_left_pressed = false;
    setGeometry(events -> pos().x(), y(), width(), height());
}

Вот функция создания визира в виджете:
/// Создание и отображение вертикального визира
void GraphicDisplay::verticalViewfinder()
{
    if(v_viewfinderAction -> isChecked())
    {
        VFFrame* finder(new VFFrame(paramsDisplay, QFrame::VLine));
        gridLayout -> addWidget(finder, 0, 0, 1, 1);
    }
}
kwisp
Цитата(AD @ 16.7.2009, 13:41) *
Какую виртуальную функцию виджета надо перехватить при наведении фокуса на визир?

если ты под фокусом понимаешь курсор мыши то.
это
enterEvent()
leaveEvent()
AD
Еще вопрос: если я внес визир в компоновщик:
gridLayout -> addWidget(finder, 0, 0, 1, 1);

Я могу с помощью move() меня его положение? (Необходимо двигать по горизонтали)

/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
// ........................................
move(events -> pos());
}

Если нет, то как заставить его появиться на форме?
kwisp
Цитата(AD @ 16.7.2009, 14:03) *
Я могу с помощью move() меня его положение? (Необходимо двигать по горизонтали)

я так понял что это вопрос.
ну не знаю предполагаю что нет.
напиши небольшой тестик и посмотри.:)
Цитата(AD @ 16.7.2009, 14:03) *
void VFFrame::mouseMoveEvent(QMouseEvent* events) { // ........................................ move(events -> pos()); }

опять же предполагаю что это не совсем красиво. будет.
координаты мыши и левого верхнего угла визира не совпадают же.
AD
Цитата(kwisp @ 16.7.2009, 14:13) *
опять же предполагаю что это не совсем красиво. будет.
координаты мыши и левого верхнего угла визира не совпадают же.

Так уже сделал. Ничего не двигается. А как добиться, чтобы в скомпонованном окне стал это визир, нескомпонованный (т.е. не добавлен в компоновщик с помощью addWidget), виден?

Вот такой код:
/// Создание и отображение вертикального визира
void GraphicDisplay::verticalViewfinder()
{
    if(v_viewfinderAction -> isChecked())
    {
        VFFrame* finder(new VFFrame(paramsDisplay, QFrame::VLine));
        finder -> setGeometry(140, 140, 16, 400);
        //gridLayout -> addWidget(finder, 0, 0, 1, 1);
    }
}
kwisp
Цитата(AD @ 16.7.2009, 14:59) *
Так уже сделал. Ничего не двигается. А как добиться, чтобы в скомпонованном окне стал это визир, нескомпонованный (т.е. не добавлен в компоновщик с помощью addWidget), виден?

жуть какаято.
а просто отдельным окном его никак нельзя сделать.
двигай куда хочешь.
AD
Цитата(kwisp @ 16.7.2009, 15:38) *
жуть какаято.
а просто отдельным окном его никак нельзя сделать.
двигай куда хочешь.

В смысле? Это как? Мне необходимо, чтобы при делании что-то с визиром, были определенные результаты у виджета? Ну т.е. взаимосвязь была... Понимаешь?
kwisp
AD,
что мешает сделать его членом класса виджета но не давать ему parenta он как окно будет самостоятельным:) и взаимосвязь будет на уровне членов класса.
в конце концов можно где нить выше по иеррархии отдать указатель на визор виджету.
ну как бы тут вариантов куча.
AD
Ну с этим вроде разобрался. Я не понимаю двух вещей. Как заставить принимать размеры визира во вертикали те же, что и окна? И как указать мыши, что мы в данной точке сфокусированы на визире, а не на виджете (у QEvent нет функции pos())?
kwisp
AD,
какие-то концептуальные непонимания.
resizeEvent() виджета переопредели в нем напиши визиру принять высоту виджета и всё.
Цитата(AD @ 16.7.2009, 16:33) *
И как указать мыши, что мы в данной точке сфокусированы на визире, а не на виджете (у QEvent нет функции pos())?

не пойму вопроса.
AD
Цитата(kwisp @ 16.7.2009, 16:45) *
Цитата(AD @ 16.7.2009, 16:33) *
И как указать мыши, что мы в данной точке сфокусированы на визире, а не на виджете (у QEvent нет функции pos())?

не пойму вопроса.

Двигаемся мышью по виджету. Вдруг наткнулись на визир. Как определить, что мы на визире? :)
kwisp
Цитата(AD @ 16.7.2009, 16:57) *
Двигаемся мышью по виджету. Вдруг наткнулись на визир. Как определить, что мы на визире? :)

тфу.
ну к примеру, см. сообщение№2
AD
Блин, ну не очень понял, как эти функции применить.... Ладно.... разберусь.

А как заставить визир двигаться только по горизонтали, например?
AD
Движение визира сделал так, но нет пока, что четкого следования за указателем мыши. Кто подскажет, в чем ошибка?
/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
    QFrame::mouseMoveEvent(events);

    if(!_is_left_pressed) return;
    if(_vf_shape == QFrame::VLine)
        move(_move_point.x(), y());
    else if(_vf_shape == QFrame::HLine)
        move(x(), _move_point.y());
}

/// Отпускание кнопки мыши
void VFFrame::mouseReleaseEvent(QMouseEvent* events)
{
    QFrame::mouseReleaseEvent(events);

    if(!_is_left_pressed) return;
    _is_left_pressed = false;
    if(_vf_shape == QFrame::VLine)
        setGeometry(_move_point.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        setGeometry(x(), _move_point.y(), width(), height());
    _is_viewfinder = false;
}

/// Изменение размеров окна
void VFFrame::resizeEvent(QResizeEvent* events)
{
    if(_vf_shape == QFrame::VLine)
        setGeometry(x(), 0, 16, parentWidget() -> height());
    else if(_vf_shape == QFrame::HLine)
        setGeometry(0, y(), parentWidget() -> width(), 16);
}

/// Проверка на попадание фокуса на визир
bool GraphicDisplay::isViewfinder(const QPoint& pos) const
{
    foreach(VFFrame* pf, viewfinderList)
        if(pf -> isViewfinder())
        {
            pf -> setMovePoint(pos);
            return true;
        }
    return false;
}

/// Нажатие на кнопку - рисование "резиновой ленты"
void GraphicDisplay::mousePressEvent(QMouseEvent* events)
{
    QWidget::mousePressEvent(events);

    if(isViewfinder(events -> pos())) return;
    // .....................................................
}

/// Переопределение функции передвижения мыши
void GraphicDisplay::mouseMoveEvent(QMouseEvent* events)
{
    if(isViewfinder(events -> pos())) return;

    // ........................................
    update();
}

/// Возвращение прежнего вида курсору и изменение масштаба
void GraphicDisplay::mouseReleaseEvent(QMouseEvent* events)
{
    if(isViewfinder(events -> pos())) return;

    // ............................
}
Движение визира происходит дерганиями, что не соответствует тому, чего хочется получить.
/// Класс для переопределения виджета каждого визира
class VFFrame: public QFrame
{
         QPoint _move_point;            ///< точка целеуказания, куда необходимо двигать

public:
         void setMovePoint(const QPoint& pnt) { _move_point = pnt; }
};
AD
Судя по всему, это происходит потому, что вначале попадаем в функцию
void VFFrame::mousePressEvent(QMouseEvent* events), а потом уже в void GraphicDisplay::mousePressEvent(QMouseEvent* events) (для остальных аналогично). А как сделать наоборот? Т.е. чтобы вначале попадали в GraphicDisplay::mousePressEvent, а потом уже в VFFrame::mousePressEvent?

Кто-нибудь может хоть подсказать в какую сторону смотреть?
AD
Попробовал решить указанную выше проблему слотов-сигналов. Не очень удалось. Не могу понять, как мне выйти на нужную координату:
viewfinder
/// Класс для переопределения виджета каждого визира
class VFFrame: public QFrame
{
    Q_OBJECT

private:
    QPoint _move_point;            ///< точка целеуказания, куда необходимо двигать

signals:
    void moveVF();

public:
    void setMovePoint(const QPoint& pnt) { _move_point = pnt; }
};

/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
    QFrame::mouseMoveEvent(events);

    emit moveVF();

    if(!_is_left_pressed) return;
    if(_vf_shape == QFrame::VLine)
        setGeometry(_move_point.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        setGeometry(x(), _move_point.y(), width(), height());
}

/// Отпускание кнопки мыши
void VFFrame::mouseReleaseEvent(QMouseEvent* events)
{
    QFrame::mouseReleaseEvent(events);

    emit moveVF();

    if(!_is_left_pressed) return;
    _is_left_pressed = false;
    if(_vf_shape == QFrame::VLine)
        setGeometry(_move_point.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        setGeometry(x(), _move_point.y(), width(), height());
    _is_viewfinder = false;
}

/// Изменение размеров окна
void VFFrame::resizeEvent(QResizeEvent* events)
{
    if(_vf_shape == QFrame::VLine)
        setGeometry(x(), 0, 16, parentWidget() -> height());
    else if(_vf_shape == QFrame::HLine)
        setGeometry(0, y(), parentWidget() -> width(), 16);
}

/// Класс для отображения параметров по времени или по расстоянию
class GraphicDisplay : public QDialog, public Ui::GraphicDisplayClass
{
    Q_OBJECT

private:
        QList<VFFrame*> viewfinderList;    ///< список всех визиров
    QPoint _move_pointVF;        ///< точка, куда следует перемещаться визир
        void connectViewfinder();
    void disconnectViewfinder();

private slots:
    void setMovePoint();
};

/// Проверка на попадание фокуса на визир
bool GraphicDisplay::isViewfinder(const QPoint& pos)
{
    foreach(VFFrame* pf, viewfinderList)
        if(pf -> isViewfinder())
        {
            _move_pointVF = pos;
            return true;
        }
    return false;
}

/// Подсоединение сигнала
void GraphicDisplay::connectViewfinder()
{
    foreach(VFFrame* pf, viewfinderList)
        if(pf -> isViewfinder())
        {
            connect(pf, SIGNAL(moveVF()), this, SLOT(setMovePoint()));
            break;
        }
}

/// Разъединение сигнала
void GraphicDisplay::disconnectViewfinder()
{
    foreach(VFFrame* pf, viewfinderList)
        if(pf -> isViewfinder())
        {
            disconnect(pf, SIGNAL(moveVF()), this, SLOT(setMovePoint()));
            break;
        }
}

/// Нажатие на кнопку - рисование "резиновой ленты"
void GraphicDisplay::mousePressEvent(QMouseEvent* events)
{
    QWidget::mousePressEvent(events);

    if(isViewfinder(events -> pos())) { connectViewfinder(); return; }
// ....................................
}

/// Переопределение функции передвижения мыши
void GraphicDisplay::mouseMoveEvent(QMouseEvent* events)
{
    if(isViewfinder(events -> pos())) return;

        // .............................................
}

/// Возвращение прежнего вида курсору и изменение масштаба
void GraphicDisplay::mouseReleaseEvent(QMouseEvent* events)
{
    if(isViewfinder(events -> pos()))
    { disconnectViewfinder(); return; }

// ....................................................................
}


Смысл в том, что во время движения в координату _move_point записывается предыдущее значение, т.к. движение мыша функций GraphicDisplay попадает позже, чем в движение мыша функций VFFrame. Как все-таки добиться эффекта, чтобы в функцию setMovePoint класса VFFrame передавалось значение events -> pos() класса GraphicDisplay?
AD
Буду рад за любой совет. Уже полторы недели с этим мучаюсь!
AD
вот рисунок визира:
Нажмите для просмотра прикрепленного файла
ufna
не, просто хочется глянуть в динамике что происходит. В какой момент и что. Я словами плохо объясню что хочу увидеть )



кстати, на прог орге совет дали сводящийся вот к чему - в визире ты узнаешь глобальные координаты, затем - переводишь их в систему координат график дисплея. Хотя мне кажется тут ненмого в другом дело.

я бы советовал перевести управление движением с визира на дисплей, воспользовавшись переменной-стейтом нажат/не нажат в визире.

я сии визиры делаю вообще не отдельными виджетами, а объектами дисплея через QRect и ручную отрисовку. Там тогда все становится очень простым, точным и удобным.



P.S. - я оба форума не особо разделяю, тему видел в обоих, ответил просто в том, в который зашел когда было время посмотреть подробнее :)
AD
Подсказанное решение практически полностью подходит. Ни слоты не нужны, ничего.
/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
    QFrame::mouseMoveEvent(events);

    QPoint gpos(events -> globalPos());
    QPoint pos(_graph -> mapFromGlobal(gpos));

    if(!_is_left_pressed) return;
    if(_vf_shape == QFrame::VLine)
        setGeometry(/*_move_point.x()*/pos.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        setGeometry(x(), /*_move_point.y()*/pos.y(), width(), height());
}


Единственное, все-таки курсор идет слегка левее визира. Но основная проблема, по сути, решена. Есть ли возможность попасть ровно под курсор?
ufna
а если добавить к X просто некоторую константу?
AD
Цитата(ufna @ 24.7.2009, 18:56) *
а если добавить к X просто некоторую константу?

Надо еще в функцию и нажатия внести. Этого еще не сделал. Сейчас все отрихтую, может быть, вообще больше ничего не понадобится.
AD
Сделал вариант, который "почти" правильный! :)

/// Переопределение нажатия на лекую кнопку мыши
void VFFrame::mousePressEvent(QMouseEvent* events)
{
    QFrame::mousePressEvent(events);

    switch(events -> button())
    {
    case Qt::LeftButton:                ///< если нажата левая кнопка мыши
        _is_left_pressed = true;
    break;
    }

    if(!_is_left_pressed) return;

    QPoint gpos(events -> globalPos());
    QPoint pos((_graph) ? _graph -> mapFromGlobal(gpos) : ((_mgraph) ? _mgraph -> mapFromGlobal(gpos) : gpos));
    if(_vf_shape == QFrame::VLine)
        pos.setX(pos.x() - _DELTA_COORD),
        setGeometry(pos.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        pos.setY(pos.y() - _DELTA_COORD),
        setGeometry(x(), pos.y(), width(), height());
}

/// Передвижение визира вслед за мышью
void VFFrame::mouseMoveEvent(QMouseEvent* events)
{
    QFrame::mouseMoveEvent(events);
    if(!_is_left_pressed) return;

    QPoint gpos(events -> globalPos());
    QPoint pos((_graph) ? _graph -> mapFromGlobal(gpos) : ((_mgraph) ? _mgraph -> mapFromGlobal(gpos) : gpos));
    if(_vf_shape == QFrame::VLine)
        pos.setX(pos.x() - _DELTA_COORD),
        setGeometry(pos.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        pos.setY(pos.y() - _DELTA_COORD),
        setGeometry(x(), pos.y(), width(), height());
}

/// Отпускание кнопки мыши
void VFFrame::mouseReleaseEvent(QMouseEvent* events)
{
    QFrame::mouseReleaseEvent(events);
    if(!_is_left_pressed) return;

    _is_left_pressed = false;
    QPoint gpos(events -> globalPos());
    QPoint pos((_graph) ? _graph -> mapFromGlobal(gpos) : ((_mgraph) ? _mgraph -> mapFromGlobal(gpos) : gpos));
    if(_vf_shape == QFrame::VLine)
        pos.setX(pos.x() - _DELTA_COORD),
        setGeometry(pos.x(), y(), width(), height());
    else if(_vf_shape == QFrame::HLine)
        pos.setY(pos.y() - _DELTA_COORD),
        setGeometry(x(), pos.y(), width(), height());
    _is_viewfinder = false;
}


Это "почти" состоит в том, что я из координаты вычитаю константу. У меня она равна 20. А есть возможность сделать без таких хаков? Заранее благодарен.
BRE
Цитата(AD @ 27.7.2009, 11:14) *
Это "почти" состоит в том, что я из координаты вычитаю константу. У меня она равна 20. А есть возможность сделать без таких хаков? Заранее благодарен.

Попробуй вычитать для:
* VLine - width() / 2
* HLine - height() / 2
AD
Цитата(BRE @ 27.7.2009, 11:17) *
Попробуй вычитать для:
* VLine - width() / 2
* HLine - height() / 2

Спасибо. В следующем варианте помогло полностью:
* VLine - width()
* HLine - height()
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.