Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: aliks-os от Май 20, 2012, 16:08



Название: Виджет-контейнер: перемещаемый и изменяемый размер
Отправлено: aliks-os от Май 20, 2012, 16:08
Я хочу представить виджет который можно перемещать и у которого можно изменять размеры. Данный виджет может служить контейнером для других виджетов, таких как QLabel, QTableWidget и так далее. Данный виджет используется мною уже в нескольких проектах. Надеюсь он будем вам полезен



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"

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>

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();

private:


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

public slots:

};

#endif // TCONTAINER_H

tcontainer.cpp
Код:
@
/*
Programmer Aleksey Osipov
email: aliks-os@yandex.ru
*/

#include "tcontainer.h"

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 *e) {
    m_infocus = true;
    this->parentWidget()->installEventFilter(this);
    this->parentWidget()->repaint();
    emit inFocus(true);
}

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

bool TContainer::eventFilter( QObject *obj, QEvent *evt ) {
    //return QWidget::eventFilter(obj, evt);
    if (m_infocus) {
        QWidget *w = this->parentWidget();
        if (w == obj && evt->type()==QEvent::Paint) {
            //Рисуем выделение контейнара
            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;
    //QWidget::mouseMoveEvent(e);
    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();
    }
    //Двигаем контайнер при помощи клавиш
    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));
        }
    }
    // проверка положения курсора по горизонтали
    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;
        }
    }
    // проверка положения курсора по вертикали
    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());
    //QWidget::mouseMoveEvent(e);
}


Название: Re: Виджет-контейнер: перемещаемый и изменяемый размер
Отправлено: iroln от Май 20, 2012, 16:45
Лучше бы было если бы проект в архиве выложил. А ещё скриншот, а то я не понял, что с ним делать. :)


Название: Re: Виджет-контейнер: перемещаемый и изменяемый размер
Отправлено: aliks-os от Май 20, 2012, 16:49
Лучше бы было если бы проект в архиве выложил. А ещё скриншот, а то я не понял, что с ним делать. :)

Что с ним делать написано вверху


Название: Re: Виджет-контейнер: перемещаемый и изменяемый размер
Отправлено: Hrundel от Октябрь 19, 2012, 22:25
Я просто скопировал текст и раскидал в соответствующие файлы.
Запустил на компиляцию и получил 12 ошибок, все одно содержания:

undefined reference to `vtable for TContainer'

Будьте добры объясните почему.
Спасибо.