Widget-moveable-and-resizeable: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
(add pyqt)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
I want to present a widget which can be moved and at which it is possible to change the sizes. This widget can serve as the container for other widgets, such as to QLabel, QTableWidget and so on. This widget is used by me already in several projects. I hope it we will to you it is useful
We want to present a widget which can be moved and at which it is possible to change the sizes. This widget can serve as the container for other widgets, such as to QLabel, QTableWidget and so on. This widget is used by autors already in several projects. We hope it we will to you it is useful


mainwindow.h
There are two version of the widget: original,  written in C++ and  translated to Python with PyQt.
<code>
 
Python (PyQt) version is accessible  by  https://github.com/korabelnikov/moveable-and-resize-qt-widget-on-python feel free to use and improve it.
 
C++ code listed bellow
 
mainwindow.h<code>
/*
/*
Programmer Aleksey Osipov
* Programmer Aleksey Osipov
email: aliks-os@yandex.ru
* email: aliks-os@yandex.ru
*/
*/


#ifndef MAINWINDOW_H
#ifndef MAINWINDOW_H
Line 20: Line 25:
class MainWindow : public QMainWindow
class MainWindow : public QMainWindow
{
{
   Q_OBJECT
    Q_OBJECT
   
 
public:
public:
   explicit MainWindow(QWidget *parent = 0);
    explicit MainWindow(QWidget *parent = 0);
   ~MainWindow();
    ~MainWindow();
   
 
private:
private:
   Ui::MainWindow '''ui;
    Ui::MainWindow *ui;
};
};


#endif // MAINWINDOW_H
#endif // MAINWINDOW_H
</code>


</code>
mainwindow.cpp
mainwindow.cpp
<code>
/*
* Programmer Aleksey Osipov
* email: aliks-os@yandex.ru
*/


<code>
/'''
Programmer Aleksey Osipov
email: aliks-os@yandex.ru
*/
#include "mainwindow.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>


MainWindow::MainWindow(QWidget *parent) :  QMainWindow(parent),  ui(new Ui::MainWindow) {
MainWindow::MainWindow(QWidget *parent) :
   ui->setupUi(this);
    QMainWindow(parent),
   this->showMaximized();
    ui(new Ui::MainWindow)
   QLabel *lab1 = new QLabel("Label1");
{
   QLabel *lab2 = new QLabel("Label2");
    ui->setupUi(this);
   TContainer *con1 = new TContainer(this,QPoint(10,10),lab1);
    this->showMaximized();
   TContainer '''con2 = new TContainer(this,QPoint(20,50),lab2);
    QLabel *lab1 = new QLabel("Label1");
    QLabel *lab2 = new QLabel("Label2");
    TContainer *con1 = new TContainer(this, QPoint(10, 10), lab1);
    TContainer *con2 = new TContainer(this, QPoint(20, 50),lab2);
}
}


Line 56: Line 65:
}
}
</code>
</code>


tcontainer.h
tcontainer.h
<code>
<code>
/'''
/*
Programmer Aleksey Osipov
* Programmer Aleksey Osipov
email: aliks-os@yandex.ru
* email: aliks-os@yandex.ru
*/
*/
 
#ifndef TCONTAINER_H
#ifndef TCONTAINER_H
#define TCONTAINER_H
#define TCONTAINER_H
Line 71: Line 79:
#include <QMouseEvent>
#include <QMouseEvent>
#include <QtGui>
#include <QtGui>
#include <QVBoxLayout>
#include <QMenu>


enum modes{
enum modes{
   NONE = 0,
    NONE = 0,
   MOVE = 1,
    MOVE = 1,
   RESIZETL = 2,
    RESIZETL = 2,
   RESIZET = 3,
    RESIZET = 3,
   RESIZETR = 4,
    RESIZETR = 4,
   RESIZER = 5,
    RESIZER = 5,
   RESIZEBR = 6,
    RESIZEBR = 6,
   RESIZEB = 7,
    RESIZEB = 7,
   RESIZEBL = 8,
    RESIZEBL = 8,
   RESIZEL = 9
    RESIZEL = 9
};
};


class TContainer : public QWidget {
class TContainer : public QWidget {
   Q_OBJECT
    Q_OBJECT
 
public:
public:
   TContainer(QWidget *parent, QPoint p, QWidget *cWidget = 0);
    TContainer(QWidget *parent, QPoint p, QWidget *cWidget = 0);
   ~TContainer();
    ~TContainer();
   QWidget *childWidget;
    QWidget *childWidget;
   QMenu *menu;
    QMenu *menu;
   void setChildWidget(QWidget '''cWidget);
    void setChildWidget(QWidget *cWidget);


protected:
protected:
   int mode;
    int mode;
   QPoint position;
    QPoint position;
   QVBoxLayout''' vLayout;
    QVBoxLayout* vLayout;
   void setCursorShape(const QPoint &amp;e_pos);
    void setCursorShape(const QPoint &e_pos);
   bool eventFilter( QObject *obj, QEvent '''evt );
    bool eventFilter(QObject *obj, QEvent *evt);
   void keyPressEvent(QKeyEvent''');
    void keyPressEvent(QKeyEvent*);
   void focusInEvent(QFocusEvent ''');
    void focusInEvent(QFocusEvent*);
   void focusOutEvent(QFocusEvent''');
    void focusOutEvent(QFocusEvent*);
   void mousePressEvent(QMouseEvent ''');
    void mousePressEvent(QMouseEvent*);
   void mouseReleaseEvent(QMouseEvent''');
    void mouseReleaseEvent(QMouseEvent*);
   void mouseMoveEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
   bool m_infocus;
    bool m_infocus;
   bool m_showMenu;
    bool m_showMenu;
   bool m_isEditing;
    bool m_isEditing;
   void popupShow(const QPoint &amp;pt);
    void popupShow(const QPoint &pt);
   QWidget '''clone();
    QWidget *clone();
 
private:
 


signals:
signals:
   void inFocus(bool mode);
    void inFocus(bool mode);
   void outFocus(bool mode);
    void outFocus(bool mode);
   void newGeometry(QRect rect);
    void newGeometry(QRect rect);
 
public slots:
 
};
};


#endif // TCONTAINER_H
#endif // TCONTAINER_H
</code>
</code>


tcontainer.cpp
tcontainer.cpp
<code>
<code>
/'''
Programmer Aleksey Osipov
email: aliks-os@yandex.ru
*/
#include "tcontainer.h"
#include "tcontainer.h"
#include <QApplication>


TContainer::TContainer(QWidget *parent, QPoint p, QWidget *cWidget) : QWidget(parent) {
TContainer::TContainer(QWidget *parent, QPoint p, QWidget *cWidget) : QWidget(parent) {
   mode = NONE;
    mode = NONE;
   childWidget = cWidget;
    childWidget = cWidget;
   setAttribute(Qt::WA_DeleteOnClose);
    setAttribute(Qt::WA_DeleteOnClose);
   this->setVisible(true);
    this->setVisible(true);
   this->setAutoFillBackground(false);
    this->setAutoFillBackground(false);
   this->setMouseTracking(true);
    this->setMouseTracking(true);
   this->setFocusPolicy(Qt::ClickFocus);
    this->setFocusPolicy(Qt::ClickFocus);
   this->setFocus();
    this->setFocus();
   this->move(p);
    this->move(p);


   vLayout = new QVBoxLayout(this);
    vLayout = new QVBoxLayout(this);
   if (cWidget != 0) {
    if (cWidget != 0) {
       cWidget->setParent(this);
        cWidget->setParent(this);
       cWidget->releaseMouse();
        cWidget->releaseMouse();
       cWidget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
        cWidget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
       vLayout->addWidget(cWidget);
        vLayout->addWidget(cWidget);
       vLayout->setContentsMargins(0,0,0,0);
        vLayout->setContentsMargins(0, 0, 0, 0);
   }
    }
   this->setLayout(vLayout);
    this->setLayout(vLayout);


   m_infocus = true;
    m_infocus = true;
   m_showMenu = false;
    m_showMenu = false;
   m_isEditing = true;
    m_isEditing = true;
   this->installEventFilter(parent);
    this->installEventFilter(parent);
}
}


TContainer::~TContainer() {
TContainer::~TContainer() {
   delete vLayout;
    delete vLayout;
}
}


void TContainer::setChildWidget(QWidget *cWidget) {
void TContainer::setChildWidget(QWidget *cWidget) {
   if (cWidget != 0) {
    if (cWidget != 0) {
       childWidget = cWidget;
        childWidget = cWidget;
       childWidget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
        childWidget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
       childWidget->setParent(this);
        childWidget->setParent(this);
       vLayout->addWidget(cWidget);
        vLayout->addWidget(cWidget);
       vLayout->setContentsMargins(0,0,0,0);
        vLayout->setContentsMargins(0, 0, 0, 0);
   }
    }
}
}


void TContainer::popupShow(const QPoint &amp;pt) {
void TContainer::popupShow(const QPoint &pt) {
   if (menu->isEmpty()) return;
    if (menu->isEmpty()) return;
   QPoint global = this->mapToGlobal(pt);
    QPoint global = this->mapToGlobal(pt);
   m_showMenu = true;
    m_showMenu = true;
   menu->exec(global);
    menu->exec(global);
   m_showMenu = false;
    m_showMenu = false;
}
}


void TContainer::focusInEvent(QFocusEvent *e) {
void TContainer::focusInEvent(QFocusEvent *) {
   m_infocus = true;
    m_infocus = true;
   this->parentWidget()->installEventFilter(this);
    this->parentWidget()->installEventFilter(this);
   this->parentWidget()->repaint();
    this->parentWidget()->repaint();
   emit inFocus(true);
    emit inFocus(true);
}
}


void TContainer::focusOutEvent(QFocusEvent *e) {
void TContainer::focusOutEvent(QFocusEvent *) {
   if (!m_isEditing) return;
    if (!m_isEditing) return;
   if (m_showMenu) return;
    if (m_showMenu) return;
   mode = NONE;
    mode = NONE;
   emit outFocus(false);
    emit outFocus(false);
   m_infocus = false;
    m_infocus = false;
}
}


bool TContainer::eventFilter( QObject *obj, QEvent *evt ) {
bool TContainer::eventFilter(QObject *obj, QEvent *evt) {
   //return QWidget::eventFilter(obj, evt);
    if (m_infocus) {
   if (m_infocus) {
        QWidget *w = this->parentWidget();
       QWidget *w = this->parentWidget();
        if (w == obj && evt->type() == QEvent::Paint) {
       if (w obj &amp;amp;&amp;amp; evt->type()QEvent::Paint) {
            // Draw container selection
           //Рисуем выделение контейнара
            QPainter painter(w);
           QPainter painter(w);
            QPoint p = this->mapTo(w, QPoint(-3, -3));
           QPoint p = this->mapTo(w,QPoint(–3,-3));
            QPoint LT = w->mapFrom(w, p);
           QPoint LT = w->mapFrom(w,p);
            QPoint LB = w->mapFrom(w, QPoint(p.x(), p.y() + this->height()));
           QPoint LB = w->mapFrom(w,QPoint(p.x(),p.y()+this->height()));
            QPoint RB = w->mapFrom(w, QPoint(p.x() + this->width(), p.y() + this->height()));
           QPoint RB = w->mapFrom(w,QPoint(p.x()+this->width(),p.y()+this->height()));
            QPoint RT = w->mapFrom(w, QPoint(p.x() + this->width(), p.y()));
           QPoint RT = w->mapFrom(w,QPoint(p.x()+this->width(),p.y()));


           painter.fillRect(LT.x(),LT.y(),6,6,QColor("black"));
            painter.fillRect(LT.x(), LT.y(), 6, 6, QColor("black"));
           painter.fillRect(LB.x(),LB.y(),6,6,QColor("black"));
            painter.fillRect(LB.x(), LB.y(), 6, 6, QColor("black"));
           painter.fillRect(RB.x(),RB.y(),6,6,QColor("black"));
            painter.fillRect(RB.x(), RB.y(), 6, 6, QColor("black"));
           painter.fillRect(RT.x(),RT.y(),6,6,QColor("black"));
            painter.fillRect(RT.x(), RT.y(), 6, 6, QColor("black"));
           return QWidget::eventFilter(obj,evt);
            return QWidget::eventFilter(obj, evt);
       }
        }
   }
    }
   return QWidget::eventFilter(obj, evt);}
    return QWidget::eventFilter(obj, evt);
}


void TContainer::mousePressEvent(QMouseEvent *e) {
void TContainer::mousePressEvent(QMouseEvent *e) {
   position = QPoint(e->globalX()-geometry().x(), e->globalY()-geometry().y());
    position = QPoint(e->globalX()-geometry().x(), e->globalY()-geometry().y());
   if (!m_isEditing) return;
    if (!m_isEditing) return;
   if (!m_infocus) return;
    if (!m_infocus) return;
   //QWidget::mouseMoveEvent(e);
    if (!e->buttons() && Qt::LeftButton) {
   if (!e->buttons() &amp; Qt::LeftButton) {
        setCursorShape(e->pos());
       setCursorShape(e->pos());
        return;
       return;
    }
   }
    if(e->button() == Qt::RightButton) {
   if(e->button()==Qt::RightButton) {
        popupShow(e->pos());
       popupShow(e->pos());
        e->accept();
       e->accept();
    }
   }
}
}


void TContainer::keyPressEvent(QKeyEvent *e) {
void TContainer::keyPressEvent(QKeyEvent *e) {
   if (!m_isEditing) return;
    if (!m_isEditing) return;
   if (e->key() Qt::Key_Delete) {
    if (e->key() == Qt::Key_Delete) {
       this->deleteLater();
        this->deleteLater();
   }
    }
   //Двигаем контайнер при помощи клавиш
    // Moving container with arrows
   if (QApplication::keyboardModifiers() Qt::ControlModifier) {
    if (QApplication::keyboardModifiers() == Qt::ControlModifier) {
       QPoint newPos(this->x(),this->y());
        QPoint newPos(this->x(),this->y());
       if (e->key() Qt::Key_Up) newPos.setY(newPos.y()-1);
        if (e->key() == Qt::Key_Up) newPos.setY(newPos.y() - 1);
       if (e->key() Qt::Key_Down) newPos.setY(newPos.y()+1);
        if (e->key() == Qt::Key_Down) newPos.setY(newPos.y() + 1);
       if (e->key() Qt::Key_Left) newPos.setX(newPos.x()-1);
        if (e->key() == Qt::Key_Left) newPos.setX(newPos.x() - 1);
       if (e->key() Qt::Key_Right) newPos.setX(newPos.x()+1);
        if (e->key() == Qt::Key_Right) newPos.setX(newPos.x() + 1);
       move(newPos);
        move(newPos);
   }
    }
   if (QApplication::keyboardModifiers() Qt::ShiftModifier) {
    if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
       if (e->key() Qt::Key_Up) resize(width(),height()-1);
        if (e->key() == Qt::Key_Up) resize(width(), height() - 1);
       if (e->key() Qt::Key_Down) resize(width(),height()+1);
        if (e->key() == Qt::Key_Down) resize(width(), height() + 1);
       if (e->key() Qt::Key_Left) resize(width()-1,height());
        if (e->key() == Qt::Key_Left) resize(width() - 1, height());
       if (e->key() == Qt::Key_Right) resize(width()''1,height());
        if (e->key() == Qt::Key_Right) resize(width() + 1, height());
   }
    }
   emit newGeometry(this->geometry());
    emit newGeometry(this->geometry());
}
}


void TContainer::setCursorShape(const QPoint &amp;e_pos) {
void TContainer::setCursorShape(const QPoint &e_pos) {
   const int diff = 3;
    const int diff = 3;
   if (
    if (
           //Left-Bottom
            //Left-Bottom
           ((e_pos.y() > y()'' height() - diff) &amp;&amp;          //Bottom
            ((e_pos.y() > y() + height() - diff) &&     //Bottom
            (e_pos.x() < x()''diff)) ||                      //Left
            (e_pos.x() < x() + diff)) ||               //Left
           //Right-Bottom
            //Right-Bottom
           ((e_pos.y() > y()'' height() - diff) &amp;&amp;          //Bottom
            ((e_pos.y() > y() + height() - diff) &&     //Bottom
            (e_pos.x() > x() + width() - diff)) ||          //Right
            (e_pos.x() > x() + width() - diff)) ||     //Right
           //Left-Top
            //Left-Top
           ((e_pos.y() < y() + diff) &amp;&amp;                     //Top
            ((e_pos.y() < y() + diff) &&               //Top
            (e_pos.x() < x() + diff)) ||                    //Left
            (e_pos.x() < x() + diff)) ||               //Left
           //Right-Top
            //Right-Top
           ((e_pos.y() < y() + diff) &amp;&amp;                     //Top
            ((e_pos.y() < y() + diff) &&               //Top
            (e_pos.x() > x() + width() - diff))             //Right
            (e_pos.x() > x() + width() - diff))       //Right
      )
            )
   {
    {
       //Left-Bottom
        //Left-Bottom
       if ((e_pos.y() > y() + height() - diff) &amp;&amp;           //Bottom
        if ((e_pos.y() > y() + height() - diff) &&     //Bottom
           (e_pos.x() < x() + diff)) {                      //Left
                (e_pos.x() < x() + diff))               //Left
           mode = RESIZEBL;
        {
           setCursor(QCursor(Qt::SizeBDiagCursor));
            mode = RESIZEBL;
       }
            setCursor(QCursor(Qt::SizeBDiagCursor));
       //Right-Bottom
        }
       if ((e_pos.y() > y() + height() - diff) &amp;&amp;           //Bottom
        //Right-Bottom
           (e_pos.x() > x() + width() - diff)) {            //Right
        if ((e_pos.y() > y() + height() - diff) &&     //Bottom
           mode = RESIZEBR;
                (e_pos.x() > x() + width() - diff))     //Right
           setCursor(QCursor(Qt::SizeFDiagCursor));
        {
       }
            mode = RESIZEBR;
       //Left-Top
            setCursor(QCursor(Qt::SizeFDiagCursor));
       if ((e_pos.y() < y() + diff) &amp;&amp;                      //Top
        }
           (e_pos.x() < x() + diff)) {                      //Left
        //Left-Top
           mode = RESIZETL;
        if ((e_pos.y() < y() + diff) &&                 //Top
           setCursor(QCursor(Qt::SizeFDiagCursor));
                (e_pos.x() < x() + diff))               //Left
       }
        {
       //Right-Top
            mode = RESIZETL;
       if ((e_pos.y() < y() + diff) &amp;&amp;                      //Top
            setCursor(QCursor(Qt::SizeFDiagCursor));
           (e_pos.x() > x() + width() - diff)) {            //Right
        }
           mode = RESIZETR;
        //Right-Top
           setCursor(QCursor(Qt::SizeBDiagCursor));
        if ((e_pos.y() < y() + diff) &&                 //Top
       }
                (e_pos.x() > x() + width() - diff))     //Right
   }
        {
   // проверка положения курсора по горизонтали
            mode = RESIZETR;
   else if ((e_pos.x() < x() + diff) ||             //Left
            setCursor(QCursor(Qt::SizeBDiagCursor));
           ((e_pos.x() > x() + width() - diff))) {  //Right
        }
       if (e_pos.x() < x() + diff) {                //Left
    }
           setCursor(QCursor(Qt::SizeHorCursor));
    // check cursor horizontal position
           mode = RESIZEL;
    else if ((e_pos.x() < x() + diff) ||               //Left
       } else {                                     //Right
            ((e_pos.x() > x() + width() - diff)))     //Right
           setCursor(QCursor(Qt::SizeHorCursor));
    {
           mode = RESIZER;
        if (e_pos.x() < x() + diff) {                   //Left
       }
            setCursor(QCursor(Qt::SizeHorCursor));
   }
            mode = RESIZEL;
   // проверка положения курсора по вертикали
        } else {                                       //Right
   else if (((e_pos.y() > y() + height() - diff)) || //Bottom
            setCursor(QCursor(Qt::SizeHorCursor));
             (e_pos.y() < y() + diff)) {             //Top
            mode = RESIZER;
       if (e_pos.y() < y() + diff) {                 //Top
        }
           setCursor(QCursor(Qt::SizeVerCursor));
    }
           mode = RESIZET;
    // check cursor vertical position
       } else {                                      //Bottom
    else if (((e_pos.y() > y() + height() - diff)) ||   //Bottom
           setCursor(QCursor(Qt::SizeVerCursor));
            (e_pos.y() < y() + diff))                 //Top
           mode = RESIZEB;
    {
       }
        if (e_pos.y() < y() + diff) {                   //Top
   } else {
            setCursor(QCursor(Qt::SizeVerCursor));
       setCursor(QCursor(Qt::ArrowCursor));
            mode = RESIZET;
       mode = MOVE;
        } else {                                       //Bottom
   }
            setCursor(QCursor(Qt::SizeVerCursor));
            mode = RESIZEB;
        }
    } else {
        setCursor(QCursor(Qt::ArrowCursor));
        mode = MOVE;
    }
}
}


void TContainer::mouseReleaseEvent(QMouseEvent *e) {
void TContainer::mouseReleaseEvent(QMouseEvent *e) {
   QWidget::mouseReleaseEvent(e);
    QWidget::mouseReleaseEvent(e);
}
}


void TContainer::mouseMoveEvent(QMouseEvent *e) {
void TContainer::mouseMoveEvent(QMouseEvent *e) {
   QWidget::mouseMoveEvent(e);
    QWidget::mouseMoveEvent(e);
   if (!m_isEditing) return;
    if (!m_isEditing) return;
   if (!m_infocus) return;
    if (!m_infocus) return;
   if (!e->buttons() &amp; Qt::LeftButton) {
    if (!e->buttons() && Qt::LeftButton) {
       QPoint p = QPoint(e->x()+geometry().x(), e->y()+geometry().y());
        QPoint p = QPoint(e->x() + geometry().x(), e->y() + geometry().y());
       setCursorShape(p);
        setCursorShape(p);
       return;
        return;
   }
    }


   if ((mode MOVE || mode NONE) &amp;&amp; e->buttons() &amp;&amp; Qt::LeftButton) {
    if ((mode == MOVE || mode == NONE) && e->buttons() && Qt::LeftButton) {
       QPoint toMove = e->globalPos() - position;
        QPoint toMove = e->globalPos() - position;
       if (toMove.x() < 0) return;
        if (toMove.x() < 0) return;
       if (toMove.y() < 0) return;
        if (toMove.y() < 0) return;
       if (toMove.x() > this->parentWidget()->width()-this->width()) return;
        if (toMove.x() > this->parentWidget()->width() - this->width()) return;
       move(toMove);
        move(toMove);
       emit newGeometry(this->geometry());
        emit newGeometry(this->geometry());
       this->parentWidget()->repaint();
        this->parentWidget()->repaint();
       return;
        return;
   }
    }
   if ((mode != MOVE) &amp;&amp; e->buttons() &amp;&amp; Qt::LeftButton) {
    if ((mode != MOVE) && e->buttons() && Qt::LeftButton) {
       switch (mode){
        switch (mode){
           case RESIZETL: {  //Left-Top
        case RESIZETL: {   //Left-Top
               int newwidth = e->globalX() - position.x() - geometry().x();
            int newwidth = e->globalX() - position.x() - geometry().x();
               int newheight = e->globalY() - position.y() - geometry().y();
            int newheight = e->globalY() - position.y() - geometry().y();
               QPoint toMove = e->globalPos() - position;
            QPoint toMove = e->globalPos() - position;
               resize(this->geometry().width()-newwidth,this->geometry().height()-newheight);
            resize(this->geometry().width() - newwidth, this->geometry().height() - newheight);
               move(toMove.x(),toMove.y());
            move(toMove.x(), toMove.y());
               break;
            break;
           }
        }
           case RESIZETR: {  //Right-Top
        case RESIZETR: {   //Right-Top
               int newheight = e->globalY() - position.y() - geometry().y();
            int newheight = e->globalY() - position.y() - geometry().y();
               QPoint toMove = e->globalPos() - position;
            QPoint toMove = e->globalPos() - position;
               resize(e->x(),this->geometry().height()-newheight);
            resize(e->x(), this->geometry().height() - newheight);
               move(this->x(),toMove.y());
            move(this->x(), toMove.y());
               break;
            break;
           }
        }
           case RESIZEBL: {  //Left-Bottom
        case RESIZEBL: {   //Left-Bottom
               int newwidth = e->globalX() - position.x() - geometry().x();
            int newwidth = e->globalX() - position.x() - geometry().x();
               QPoint toMove = e->globalPos() - position;
            QPoint toMove = e->globalPos() - position;
               resize(this->geometry().width()-newwidth,e->y());
            resize(this->geometry().width() - newwidth, e->y());
               move(toMove.x(),this->y());
            move(toMove.x(), this->y());
               break;
            break;
           }
        }
           case RESIZEB: {   //Bottom
        case RESIZEB: {     //Bottom
               resize(width(),e->y()); break;}
            resize(width(), e->y());
           case RESIZEL:  {  //Left
            break;
               int newwidth = e->globalX() - position.x() - geometry().x();
        }
               QPoint toMove = e->globalPos() - position;
        case RESIZEL: {     //Left
               resize(this->geometry().width()-newwidth,height());
            int newwidth = e->globalX() - position.x() - geometry().x();
               move(toMove.x(),this->y());
            QPoint toMove = e->globalPos() - position;
               break;
            resize(this->geometry().width() - newwidth, height());
           }
            move(toMove.x(), this->y());
           case RESIZET:  {  //Top
            break;
               int newheight = e->globalY() - position.y() - geometry().y();
        }
               QPoint toMove = e->globalPos() - position;
        case RESIZET: {     //Top
               resize(width(),this->geometry().height()-newheight);
            int newheight = e->globalY() - position.y() - geometry().y();
               move(this->x(),toMove.y());
            QPoint toMove = e->globalPos() - position;
               break;
            resize(width(), this->geometry().height() - newheight);
           }
            move(this->x(), toMove.y());
           case RESIZER:  {  //Right
            break;
               resize(e->x(),height()); break;}
        }
           case RESIZEBR: {  //Right-Bottom
        case RESIZER: {     //Right
               resize(e->x(),e->y()); break;}
            resize(e->x(), height());
       }
            break;
       this->parentWidget()->repaint();
        }
   }
        case RESIZEBR: {   //Right-Bottom
   emit newGeometry(this->geometry());
            resize(e->x(), e->y());
   //QWidget::mouseMoveEvent(e);
            break;
        }
        }
        this->parentWidget()->repaint();
    }
    emit newGeometry(this->geometry());
}
}
</code>
</code>

Latest revision as of 12:03, 4 February 2018

We want to present a widget which can be moved and at which it is possible to change the sizes. This widget can serve as the container for other widgets, such as to QLabel, QTableWidget and so on. This widget is used by autors already in several projects. We hope it we will to you it is useful

There are two version of the widget: original, written in C++ and translated to Python with PyQt.

Python (PyQt) version is accessible by https://github.com/korabelnikov/moveable-and-resize-qt-widget-on-python feel free to use and improve it.

C++ code listed bellow

mainwindow.h

/*
 * Programmer Aleksey Osipov
 * email: aliks-os@yandex.ru
 */

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "tcontainer.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

/*
 * Programmer Aleksey Osipov
 * email: aliks-os@yandex.ru
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLabel>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->showMaximized();
    QLabel *lab1 = new QLabel("Label1");
    QLabel *lab2 = new QLabel("Label2");
    TContainer *con1 = new TContainer(this, QPoint(10, 10), lab1);
    TContainer *con2 = new TContainer(this, QPoint(20, 50),lab2);
}

MainWindow::~MainWindow() {
    delete ui;
}

tcontainer.h

/*
 * Programmer Aleksey Osipov
 * email: aliks-os@yandex.ru
 */

#ifndef TCONTAINER_H
#define TCONTAINER_H

#include <QWidget>
#include <QMouseEvent>
#include <QtGui>
#include <QVBoxLayout>
#include <QMenu>

enum modes{
    NONE = 0,
    MOVE = 1,
    RESIZETL = 2,
    RESIZET = 3,
    RESIZETR = 4,
    RESIZER = 5,
    RESIZEBR = 6,
    RESIZEB = 7,
    RESIZEBL = 8,
    RESIZEL = 9
};

class TContainer : public QWidget {
    Q_OBJECT

public:
    TContainer(QWidget *parent, QPoint p, QWidget *cWidget = 0);
    ~TContainer();
    QWidget *childWidget;
    QMenu *menu;
    void setChildWidget(QWidget *cWidget);

protected:
    int mode;
    QPoint position;
    QVBoxLayout* vLayout;
    void setCursorShape(const QPoint &e_pos);
    bool eventFilter(QObject *obj, QEvent *evt);
    void keyPressEvent(QKeyEvent*);
    void focusInEvent(QFocusEvent*);
    void focusOutEvent(QFocusEvent*);
    void mousePressEvent(QMouseEvent*);
    void mouseReleaseEvent(QMouseEvent*);
    void mouseMoveEvent(QMouseEvent *);
    bool m_infocus;
    bool m_showMenu;
    bool m_isEditing;
    void popupShow(const QPoint &pt);
    QWidget *clone();

signals:
    void inFocus(bool mode);
    void outFocus(bool mode);
    void newGeometry(QRect rect);
};

#endif // TCONTAINER_H

tcontainer.cpp

#include "tcontainer.h"
#include <QApplication>

TContainer::TContainer(QWidget *parent, QPoint p, QWidget *cWidget) : QWidget(parent) {
    mode = NONE;
    childWidget = cWidget;
    setAttribute(Qt::WA_DeleteOnClose);
    this->setVisible(true);
    this->setAutoFillBackground(false);
    this->setMouseTracking(true);
    this->setFocusPolicy(Qt::ClickFocus);
    this->setFocus();
    this->move(p);

    vLayout = new QVBoxLayout(this);
    if (cWidget != 0) {
        cWidget->setParent(this);
        cWidget->releaseMouse();
        cWidget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
        vLayout->addWidget(cWidget);
        vLayout->setContentsMargins(0, 0, 0, 0);
    }
    this->setLayout(vLayout);

    m_infocus = true;
    m_showMenu = false;
    m_isEditing = true;
    this->installEventFilter(parent);
}

TContainer::~TContainer() {
    delete vLayout;
}

void TContainer::setChildWidget(QWidget *cWidget) {
    if (cWidget != 0) {
        childWidget = cWidget;
        childWidget->setAttribute(Qt::WA_TransparentForMouseEvents, true);
        childWidget->setParent(this);
        vLayout->addWidget(cWidget);
        vLayout->setContentsMargins(0, 0, 0, 0);
    }
}

void TContainer::popupShow(const QPoint &pt) {
    if (menu->isEmpty()) return;
    QPoint global = this->mapToGlobal(pt);
    m_showMenu = true;
    menu->exec(global);
    m_showMenu = false;
}

void TContainer::focusInEvent(QFocusEvent *) {
    m_infocus = true;
    this->parentWidget()->installEventFilter(this);
    this->parentWidget()->repaint();
    emit inFocus(true);
}

void TContainer::focusOutEvent(QFocusEvent *) {
    if (!m_isEditing) return;
    if (m_showMenu) return;
    mode = NONE;
    emit outFocus(false);
    m_infocus = false;
}

bool TContainer::eventFilter(QObject *obj, QEvent *evt) {
    if (m_infocus) {
        QWidget *w = this->parentWidget();
        if (w == obj && evt->type() == QEvent::Paint) {
            // Draw container selection
            QPainter painter(w);
            QPoint p = this->mapTo(w, QPoint(-3, -3));
            QPoint LT = w->mapFrom(w, p);
            QPoint LB = w->mapFrom(w, QPoint(p.x(), p.y() + this->height()));
            QPoint RB = w->mapFrom(w, QPoint(p.x() + this->width(), p.y() + this->height()));
            QPoint RT = w->mapFrom(w, QPoint(p.x() + this->width(), p.y()));

            painter.fillRect(LT.x(), LT.y(), 6, 6, QColor("black"));
            painter.fillRect(LB.x(), LB.y(), 6, 6, QColor("black"));
            painter.fillRect(RB.x(), RB.y(), 6, 6, QColor("black"));
            painter.fillRect(RT.x(), RT.y(), 6, 6, QColor("black"));
            return QWidget::eventFilter(obj, evt);
        }
    }
    return QWidget::eventFilter(obj, evt);
}

void TContainer::mousePressEvent(QMouseEvent *e) {
    position = QPoint(e->globalX()-geometry().x(), e->globalY()-geometry().y());
    if (!m_isEditing) return;
    if (!m_infocus) return;
    if (!e->buttons() && Qt::LeftButton) {
        setCursorShape(e->pos());
        return;
    }
    if(e->button() == Qt::RightButton) {
        popupShow(e->pos());
        e->accept();
    }
}

void TContainer::keyPressEvent(QKeyEvent *e) {
    if (!m_isEditing) return;
    if (e->key() == Qt::Key_Delete) {
        this->deleteLater();
    }
    // Moving container with arrows
    if (QApplication::keyboardModifiers() == Qt::ControlModifier) {
        QPoint newPos(this->x(),this->y());
        if (e->key() == Qt::Key_Up) newPos.setY(newPos.y() - 1);
        if (e->key() == Qt::Key_Down) newPos.setY(newPos.y() + 1);
        if (e->key() == Qt::Key_Left) newPos.setX(newPos.x() - 1);
        if (e->key() == Qt::Key_Right) newPos.setX(newPos.x() + 1);
        move(newPos);
    }
    if (QApplication::keyboardModifiers() == Qt::ShiftModifier) {
        if (e->key() == Qt::Key_Up) resize(width(), height() - 1);
        if (e->key() == Qt::Key_Down) resize(width(), height() + 1);
        if (e->key() == Qt::Key_Left) resize(width() - 1, height());
        if (e->key() == Qt::Key_Right) resize(width() + 1, height());
    }
    emit newGeometry(this->geometry());
}

void TContainer::setCursorShape(const QPoint &e_pos) {
    const int diff = 3;
    if (
            //Left-Bottom
            ((e_pos.y() > y() + height() - diff) &&     //Bottom
             (e_pos.x() < x() + diff)) ||               //Left
            //Right-Bottom
            ((e_pos.y() > y() + height() - diff) &&     //Bottom
             (e_pos.x() > x() + width() - diff)) ||     //Right
            //Left-Top
            ((e_pos.y() < y() + diff) &&                //Top
             (e_pos.x() < x() + diff)) ||               //Left
            //Right-Top
            ((e_pos.y() < y() + diff) &&                //Top
             (e_pos.x() > x() + width() - diff))        //Right
            )
    {
        //Left-Bottom
        if ((e_pos.y() > y() + height() - diff) &&      //Bottom
                (e_pos.x() < x() + diff))               //Left
        {
            mode = RESIZEBL;
            setCursor(QCursor(Qt::SizeBDiagCursor));
        }
        //Right-Bottom
        if ((e_pos.y() > y() + height() - diff) &&      //Bottom
                (e_pos.x() > x() + width() - diff))     //Right
        {
            mode = RESIZEBR;
            setCursor(QCursor(Qt::SizeFDiagCursor));
        }
        //Left-Top
        if ((e_pos.y() < y() + diff) &&                 //Top
                (e_pos.x() < x() + diff))               //Left
        {
            mode = RESIZETL;
            setCursor(QCursor(Qt::SizeFDiagCursor));
        }
        //Right-Top
        if ((e_pos.y() < y() + diff) &&                 //Top
                (e_pos.x() > x() + width() - diff))     //Right
        {
            mode = RESIZETR;
            setCursor(QCursor(Qt::SizeBDiagCursor));
        }
    }
    // check cursor horizontal position
    else if ((e_pos.x() < x() + diff) ||                //Left
             ((e_pos.x() > x() + width() - diff)))      //Right
    {
        if (e_pos.x() < x() + diff) {                   //Left
            setCursor(QCursor(Qt::SizeHorCursor));
            mode = RESIZEL;
        } else {                                        //Right
            setCursor(QCursor(Qt::SizeHorCursor));
            mode = RESIZER;
        }
    }
    // check cursor vertical position
    else if (((e_pos.y() > y() + height() - diff)) ||   //Bottom
             (e_pos.y() < y() + diff))                  //Top
    {
        if (e_pos.y() < y() + diff) {                   //Top
            setCursor(QCursor(Qt::SizeVerCursor));
            mode = RESIZET;
        } else {                                        //Bottom
            setCursor(QCursor(Qt::SizeVerCursor));
            mode = RESIZEB;
        }
    } else {
        setCursor(QCursor(Qt::ArrowCursor));
        mode = MOVE;
    }
}

void TContainer::mouseReleaseEvent(QMouseEvent *e) {
    QWidget::mouseReleaseEvent(e);
}

void TContainer::mouseMoveEvent(QMouseEvent *e) {
    QWidget::mouseMoveEvent(e);
    if (!m_isEditing) return;
    if (!m_infocus) return;
    if (!e->buttons() && Qt::LeftButton) {
        QPoint p = QPoint(e->x() + geometry().x(), e->y() + geometry().y());
        setCursorShape(p);
        return;
    }

    if ((mode == MOVE || mode == NONE) && e->buttons() && Qt::LeftButton) {
        QPoint toMove = e->globalPos() - position;
        if (toMove.x() < 0) return;
        if (toMove.y() < 0) return;
        if (toMove.x() > this->parentWidget()->width() - this->width()) return;
        move(toMove);
        emit newGeometry(this->geometry());
        this->parentWidget()->repaint();
        return;
    }
    if ((mode != MOVE) && e->buttons() && Qt::LeftButton) {
        switch (mode){
        case RESIZETL: {    //Left-Top
            int newwidth = e->globalX() - position.x() - geometry().x();
            int newheight = e->globalY() - position.y() - geometry().y();
            QPoint toMove = e->globalPos() - position;
            resize(this->geometry().width() - newwidth, this->geometry().height() - newheight);
            move(toMove.x(), toMove.y());
            break;
        }
        case RESIZETR: {    //Right-Top
            int newheight = e->globalY() - position.y() - geometry().y();
            QPoint toMove = e->globalPos() - position;
            resize(e->x(), this->geometry().height() - newheight);
            move(this->x(), toMove.y());
            break;
        }
        case RESIZEBL: {    //Left-Bottom
            int newwidth = e->globalX() - position.x() - geometry().x();
            QPoint toMove = e->globalPos() - position;
            resize(this->geometry().width() - newwidth, e->y());
            move(toMove.x(), this->y());
            break;
        }
        case RESIZEB: {     //Bottom
            resize(width(), e->y());
            break;
        }
        case RESIZEL: {     //Left
            int newwidth = e->globalX() - position.x() - geometry().x();
            QPoint toMove = e->globalPos() - position;
            resize(this->geometry().width() - newwidth, height());
            move(toMove.x(), this->y());
            break;
        }
        case RESIZET: {     //Top
            int newheight = e->globalY() - position.y() - geometry().y();
            QPoint toMove = e->globalPos() - position;
            resize(width(), this->geometry().height() - newheight);
            move(this->x(), toMove.y());
            break;
        }
        case RESIZER: {     //Right
            resize(e->x(), height());
            break;
        }
        case RESIZEBR: {    //Right-Bottom
            resize(e->x(), e->y());
            break;
        }
        }
        this->parentWidget()->repaint();
    }
    emit newGeometry(this->geometry());
}