qt实现自定义控件可以实现鼠标拖动控件及拉拽

看到一个博客问答关于qt拖动及拖拽,好像写得不错,没有细看,是实现自定义控件可以实现鼠标拖动控件及拉拽的另一种方法,先摘抄下来,后面详细研究下,原文链接:https://bbs.csdn.net/topics/390848708

仅供学习,转载请联系原博主,如有侵权请及时联系删除

 

qtdesigner源码中有

拖动原理:
利用QDrag类实现。

在开始拖动的时:把需要拖动的控件图形设置给QDrag实例,控件图形通过QPixmap::grabWidget获取。
然后把控件隐藏,这个时候鼠标移动就会有控件跟着动的效果了。
在QDrag释放的时候得到释放的位置,然后把控件移动到这个位置并显示。

改变大小原理:
当控件被选中的时候,给工具外面套上一个特殊的widget,这个weidget其实就是绘制了8个小块。当鼠标移动和点击到不同的小块上进行相应的处理。在拖动的时候时刻计算偏移量,然后设置控件大小和位置。

基本原理就是这样的。

 

 

我只知道怎么拖动控件,
比如你托动标题,就能拖动窗体。
你可以重写标题控件的mouseMoveEvent事件
void YourTitleLabel::mouseMoveEvent(QMouseEvent *e)
{
    if(e->buttons() == Qt::LeftButton && m_bMoving)
    {
        QWidget* parentWidget = this->parentWidget();
        QPoint parentPoint = parentWidget->pos();
        parentPoint.setX(parentPoint.x() + e->x() - m_pressedPoint.x());
        parentPoint.setY(parentPoint.y() + e->y() - m_pressedPoint.y());

        QDesktopWidget *desktop = QApplication::desktop();
        QRect deskRect = desktop->availableGeometry();
        // 目标位置不能在任务栏下面,不能在左边移出一半
        if( (parentPoint.y() < (deskRect.bottom() - 20))
                && (parentPoint.x() > (deskRect.left() - parentWidget->width() / 2)))
            parentWidget->move(parentPoint);
    }
    QLabel::mouseMoveEvent(e);
}
注意标题栏的父是主窗体,这样拖动标题栏主窗体才会动。可以依次类推到你想要的其它控件

 

#ifndef QSELECTWIDGET_H
#define QSELECTWIDGET_H
 
#include 
#include 
 
class WidgetHandle: public QWidget
{
    Q_OBJECT
public:
    enum Type
    {
        LeftTop,
        Top,
        RightTop,
        Right,
        RightBottom,
        Bottom,
        LeftBottom,
        Left,
 
        TypeCount
    };
    WidgetHandle(QWidget* parent,Type t);
 
    void    setWidget(QWidget *w);
    void    setCurrent(bool b);
protected:
protected:
    void paintEvent(QPaintEvent *);
    void mousePressEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
    void mouseReleaseEvent(QMouseEvent *e);
 
protected:
    void    updateCursor();
    void    trySetGeometry(QWidget *w, int x, int y, int width, int height);
    void    tryResize(QWidget *w, int width, int height);
signals:
    void sizeChanged(int x,int y,int width,int height);
    void    mouse_button_release(const QRect& old,const QRect & now);
protected:
    Type        m_type;
    QWidget *   m_widget;
    bool        m_current;
    QPoint      m_origPressPos;
    QRect       m_geom, m_origGeom;
};
 
class WidgetSelection: public QObject
{
    Q_OBJECT
public:
    WidgetSelection(QWidget *parent);
 
    void setWidget(QWidget *w);
    QWidget *widget();
    bool isUsed() const;
 
    void hide();
    void show();
    void update();
    void updateGeometry();
 
    void setCurrent(bool b);
protected:
    bool eventFilter(QObject *object, QEvent *event);
 
protected slots:
    void    changedsize(int x,int y,int width,int height);
    void    mouse_button_release(const QRect& old,const QRect & now);
signals:
    void sizeChanged(QWidget* wid,const QRect& old,const QRect & now);
protected:
    WidgetHandle *m_handles[WidgetHandle::TypeCount];
    QWidget     *m_widget;
    QWidget     *m_formWindow;
};
 
class Selection :   public QObject
{
    Q_OBJECT
public:
    Selection(QWidget *formwindow);
    ~Selection();
 
    void clear();
 
    void  clearSelectionPool();
 
    void repaintSelection(QWidget *w);
    void repaintSelection();
 
    bool isWidgetSelected(QWidget *w) const;
    QWidgetList selectedWidgets() const;
 
    WidgetSelection *addWidget(QWidget *w);
    QWidget* removeWidget(QWidget *w);
    QWidget* current();
 
    void raiseList(const QWidgetList& l);
    void raiseWidget(QWidget *w);
 
    void updateGeometry(QWidget *w);
 
    void hide(QWidget *w);
    void show(QWidget *w);
 
 
    void setCurrent(QWidget *w);
signals:
    void sizeChanged(QWidget* wid,const QRect& old,const QRect & now);
 
private:
 
    typedef QList SelectionPool;
    SelectionPool m_selectionPool;
 
    typedef QHash SelectionHash;
    SelectionHash m_usedSelections;
    WidgetSelection *       m_current;
    QWidget*                m_formwindow;
};
 
#endif // QSELECTWIDGET_H

 

#include "qselectwidget.h"


#include 

#include 


WidgetHandle::WidgetHandle(QWidget *parent, Type t):
    QWidget(parent),
    m_type(t),
    m_current(false)
{
    setAttribute(Qt::WA_NoChildEventsForParent);
    setMouseTracking(false);
    setAutoFillBackground(true);

    setBackgroundRole(QPalette::Text);
    setFixedSize(6, 6);

    updateCursor();
}

void WidgetHandle::updateCursor()
{
    switch (m_type)
    {
    case LeftTop:
        setCursor(Qt::SizeFDiagCursor);
        break;
    case Top:
        setCursor(Qt::SizeVerCursor);
        break;
    case RightTop:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case Right:
        setCursor(Qt::SizeHorCursor);
        break;
    case RightBottom:
        setCursor(Qt::SizeFDiagCursor);
        break;
    case Bottom:
        setCursor(Qt::SizeVerCursor);
        break;
    case LeftBottom:
        setCursor(Qt::SizeBDiagCursor);
        break;
    case Left:
        setCursor(Qt::SizeHorCursor);
        break;
    default:
       setCursor(Qt::ArrowCursor);
       break;
    }
}

void WidgetHandle::setCurrent(bool b)
{
    m_current=b;
    this->update();
}

void WidgetHandle::setWidget(QWidget *w)
{
    m_widget = w;
}

void WidgetHandle::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.setPen(m_current? Qt::blue : Qt::black);
    p.setBrush(QBrush(QColor(m_current? Qt::darkBlue : Qt::black)));
    p.drawRect(0, 0, width() - 1, height() - 1);
}

void WidgetHandle::mousePressEvent(QMouseEvent *e)
{
    e->accept();

    if (!(m_widget && e->button() == Qt::LeftButton))
        return;

    QWidget *container = m_widget->parentWidget();

    m_origPressPos = container->mapFromGlobal(e->globalPos());
    m_geom = m_origGeom = m_widget->geometry();
}


void WidgetHandle::mouseMoveEvent(QMouseEvent *e)
{
    if (!(m_widget && e->buttons() & Qt::LeftButton))
        return;

    e->accept();

    QWidget *container = m_widget->parentWidget();

    const QPoint rp = container->mapFromGlobal(e->globalPos());
    const QPoint d = rp - m_origPressPos;

    const QRect pr = container->rect();

    switch (m_type)
    {

    case LeftTop:
    {
        if (rp.x() > pr.width() - 2 * width() || rp.y() > pr.height() - 2 * height())
            return;

        int w = m_origGeom.width() - d.x();
        m_geom.setWidth(w);

        int h = m_origGeom.height() - d.y();
        m_geom.setHeight(h);

        const int dx = m_widget->width() - w;
        const int dy = m_widget->height() - h;

        trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y() + dy, w, h);
    }
    break;
    case Top:
    {
        if (rp.y() > pr.height() - 2 * height())
            return;

        int h = m_origGeom.height() - d.y();
        m_geom.setHeight(h);

        const int dy = m_widget->height() - h;
        trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, m_widget->width(), h);
    }
    break;
    case RightTop:
    {
        if (rp.x() < 2 * width() || rp.y() > pr.height() - 2 * height())
            return;

        int h = m_origGeom.height() - d.y();
        m_geom.setHeight(h);

        const int dy = m_widget->height() - h;

        int w = m_origGeom.width() + d.x();
        m_geom.setWidth(w);

        trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, w, h);
    }
    break;
    case Right:
    {
        if (rp.x() < 2 * width())
            return;

        int w = m_origGeom.width() + d.x();
        m_geom.setWidth(w);

        tryResize(m_widget, w, m_widget->height());
    }
    break;
    case RightBottom:
    {
        if (rp.x() < 2 * width() || rp.y() < 2 * height())
            return;

        int w = m_origGeom.width() + d.x();
        m_geom.setWidth(w);

        int h = m_origGeom.height() + d.y();
        m_geom.setHeight(h);

        tryResize(m_widget, w, h);
    }
    break;
    case Bottom:
    {
        if (rp.y() < 2 * height())
            return;

        int h = m_origGeom.height() + d.y();
        m_geom.setHeight(h);
        tryResize(m_widget, m_widget->width(), h);
    }
    break;
    case LeftBottom:
    {
        if (rp.x() > pr.width() - 2 * width() || rp.y() < 2 * height())
            return;

        int w = m_origGeom.width() - d.x();
        m_geom.setWidth(w);

        int h = m_origGeom.height() + d.y();
        m_geom.setHeight(h);

        int dx = m_widget->width() - w;

        trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, h);
    }
    break;
    case Left:
    {
        if (rp.x() > pr.width() - 2 * width())
            return;

        int w = m_origGeom.width() - d.x();
        m_geom.setWidth(w);

        const int dx = m_widget->width() - w;

        trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, m_widget->height());
    }
    break;
    default: break;
    }
}

void WidgetHandle::mouseReleaseEvent(QMouseEvent *e)
{
    if (e->button() != Qt::LeftButton)
        return;

    e->accept();
    emit mouse_button_release(m_origGeom,m_geom);
}

void WidgetHandle::trySetGeometry(QWidget *w, int x, int y, int width, int height)
{

    int minw = w->minimumSize().width();
    minw = qMax(minw, 20);

    int minh = w->minimumSize().height();
    minh = qMax(minh, 20);

    if (qMax(minw, width) > w->maximumWidth() ||
         qMax(minh, height) > w->maximumHeight())
        return;

    if (width < minw && x != w->x())
        x -= minw - width;

    if (height < minh && y != w->y())
        y -= minh - height;

    emit sizeChanged(x, y, qMax(minw, width), qMax(minh, height));
}

void WidgetHandle::tryResize(QWidget *w, int width, int height)
{
    int minw = w->minimumSize().width();
    minw = qMax(minw, 16);

    int minh = w->minimumSize().height();
    minh = qMax(minh, 16);

    emit sizeChanged(w->x(),w->y(),qMax(minw, width), qMax(minh, height));
}

WidgetSelection::WidgetSelection(QWidget *parent)   :
    m_widget(0),
    m_formWindow(parent)
{
    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        m_handles[i] = new WidgetHandle(m_formWindow, static_cast(i));
        connect(m_handles[i],SIGNAL(sizeChanged(int,int,int,int)),this,SLOT(changedsize(int,int,int,int)));
        connect(m_handles[i],SIGNAL(mouse_button_release(QRect,QRect)),this,SLOT(mouse_button_release(QRect,QRect)));
    }
    hide();
}

void WidgetSelection::setCurrent(bool b)
{
    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        m_handles[i]->setCurrent(b);
    }
}

void WidgetSelection::setWidget(QWidget *w)
{
    if (m_widget != 0)
    {
        QWidget* wid=m_widget;
        while(wid!=NULL)
        {
            wid->removeEventFilter(this);
            wid=wid->parentWidget();
            if(wid==m_formWindow)
            {
                break;
            }
        }
    }

    if (w == 0) {
        hide();
        m_widget = 0;
        return;
    }

    m_widget = w;

    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        m_handles[i]->setWidget(m_widget);
    }

    QWidget* wid=m_widget;
    while(wid!=NULL)
    {
        wid->installEventFilter(this);
        wid=wid->parentWidget();
        if(wid==m_formWindow)
        {
            break;
        }
    }

    updateGeometry();
    show();
}

bool WidgetSelection::isUsed() const
{
    return m_widget != 0;
}

QWidget *WidgetSelection::widget()
{
    return m_widget;
}

void WidgetSelection::updateGeometry()
{
    if (!m_widget || !m_widget->parentWidget())
        return;

    QPoint p = m_widget->mapToGlobal(QPoint(0,0));
    p = m_formWindow->mapFromGlobal(p);
    const QRect r(p, m_widget->size());

    const int w = 6;
    const int h = 6;

    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        WidgetHandle *hndl = m_handles[ i ];
        if (!hndl)
            continue;
        switch (i)
        {
        case WidgetHandle::LeftTop:
            hndl->move(r.x() - w / 2, r.y() - h / 2);
            break;
        case WidgetHandle::Top:
            hndl->move(r.x() + r.width() / 2 - w / 2, r.y() - h / 2);
            break;
        case WidgetHandle::RightTop:
            hndl->move(r.x() + r.width() - w / 2, r.y() - h / 2);
            break;
        case WidgetHandle::Right:
            hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() / 2 - h / 2);
            break;
        case WidgetHandle::RightBottom:
            hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() - h / 2);
            break;
        case WidgetHandle::Bottom:
            hndl->move(r.x() + r.width() / 2 - w / 2, r.y() + r.height() - h / 2);
            break;
        case WidgetHandle::LeftBottom:
            hndl->move(r.x() - w / 2, r.y() + r.height() - h / 2);
            break;
        case WidgetHandle::Left:
            hndl->move(r.x() - w / 2, r.y() + r.height() / 2 - h / 2);
            break;
        default:
            break;
        }
    }
}

 

 


void WidgetSelection::hide()
{
    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        WidgetHandle *h = m_handles[ i ];
        if (h)
            h->hide();
    }
}

void WidgetSelection::show()
{
    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        WidgetHandle *h = m_handles[ i ];
        if (h) {
            h->show();
            h->raise();
        }
    }
}

void WidgetSelection::update()
{
    for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
    {
        WidgetHandle *h = m_handles[ i ];
        if (h)
            h->update();
    }
}

bool WidgetSelection::eventFilter(QObject *object, QEvent *event)
{
    QObject *o=m_widget;
    while(1)
    {
        if(o==object)
        {
            break;
        }
        o=o->parent();
        if(o==NULL)
        {
            return false;
        }
    }

    switch (event->type()) {
        default: break;

        case QEvent::Move:
        case QEvent::Resize:
        case QEvent::ParentChange:
            updateGeometry();
            break;
        case QEvent::ZOrderChange:
            show();
            break;
    }

    return false;
}

void WidgetSelection::changedsize(int x, int y, int width, int height)
{
    m_widget->setProperty("geometry",QRect(x,y,width,height));
    updateGeometry();
}

void WidgetSelection::mouse_button_release(const QRect &old, const QRect &now)
{
    emit sizeChanged(m_widget,old,now);
}

Selection::Selection(QWidget *formwindow):
    m_current(NULL),
    m_formwindow(formwindow)
{
}

Selection::~Selection()
{
    clearSelectionPool();
}

void Selection::clear()
{
    if (!m_usedSelections.empty())
    {
        const SelectionHash::iterator mend = m_usedSelections.end();
        for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it)
        {
            it.value()->setWidget(0);
        }
        m_usedSelections.clear();
    }
}

void  Selection::clearSelectionPool()
{
    clear();
    qDeleteAll(m_selectionPool);
    m_selectionPool.clear();
}

WidgetSelection *Selection::addWidget(QWidget *w)
{
    WidgetSelection *rc= m_usedSelections.value(w);
    if (rc != 0)
    {
        rc->show();
        return rc;
    }
    const SelectionPool::iterator pend = m_selectionPool.end();
    for (SelectionPool::iterator it = m_selectionPool.begin(); it != pend; ++it)
    {
        if (! (*it)->isUsed()) {
            rc = *it;
            break;
        }
    }

    if (rc == 0) {
        rc = new WidgetSelection(m_formwindow);
        connect(rc,SIGNAL(sizeChanged(QWidget*,QRect,QRect)),this,SIGNAL(sizeChanged(QWidget*,QRect,QRect)));
        m_selectionPool.push_back(rc);

    }
    m_usedSelections.insert(w, rc);
    rc->setWidget(w);
    return rc;
}

QWidget* Selection::removeWidget(QWidget *w)
{
    WidgetSelection *s = m_usedSelections.value(w);
    if (!s)
        return w;

    if(m_current==s)
    {
        m_current->setCurrent(false);
        m_current=NULL;
    }
    s->setWidget(0);
    m_usedSelections.remove(w);
    if (m_usedSelections.isEmpty())
        return 0;

    return (*m_usedSelections.begin())->widget();
}

void Selection::repaintSelection(QWidget *w)
{
    if (WidgetSelection *s = m_usedSelections.value(w))
        s->update();
}

void Selection::repaintSelection()
{
    const SelectionHash::iterator mend = m_usedSelections.end();
    for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) {
        it.value()->update();
    }
}

bool Selection::isWidgetSelected(QWidget *w) const{
    return  m_usedSelections.contains(w);
}

QWidgetList Selection::selectedWidgets() const
{
    return m_usedSelections.keys();
}

void Selection::raiseList(const QWidgetList& l)
{
    const SelectionHash::iterator mend = m_usedSelections.end();
    for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) {
        WidgetSelection *w = it.value();
        if (l.contains(w->widget()))
            w->show();
    }
}

void Selection::raiseWidget(QWidget *w)
{
    if (WidgetSelection *s = m_usedSelections.value(w))
        s->show();
}

void Selection::updateGeometry(QWidget *w)
{
    if (WidgetSelection *s = m_usedSelections.value(w))
    {
        s->updateGeometry();
    }
}

void Selection::hide(QWidget *w)
{
    if (WidgetSelection *s = m_usedSelections.value(w))
        s->hide();
}

void Selection::show(QWidget *w)
{
    if (WidgetSelection *s = m_usedSelections.value(w))
        s->show();
}

void Selection::setCurrent(QWidget *w)
{
    WidgetSelection *s = m_usedSelections.value(w);
    if(m_current==s)
    {
        return;
    }
    if(m_current!=NULL)
    {
        m_current->setCurrent(false);
    }
    m_current=s;
    if(m_current!=NULL)
    {
        m_current->setCurrent(true);
    }
}

QWidget* Selection::current()
{
    return m_current==NULL?NULL:m_current->widget();
}

 

这个就是我(回答问题的人)做的一个控件拖拽大小的源码。

把需要改变大小的widget指针添加到Selection实例中就可以了。

 

把需要改变大小的widget指针添加到Selection实例中就可以了。


这儿好像说法不对 先实例一个 Selection出来  然后再调用 AddWidget(QWidget *w)  的方法 刚你要缩放的控件的指针传进去就可以了  可用

你可能感兴趣的:(Qt)