qt 创建一个可以拖拽的矩形,简单实验 方案5

1.概要

创建一个可以拖拽的矩形,要求如下

鼠标接近左右边线,鼠标变成可以拖拽的形状,矩形的左右边线可以拖拽;

当鼠标点击矩形内的时候,鼠标变成手型,可以可以上下拖动;

点击+ctrl是选择矩形,选择后矩形的边线变成蓝色,再次点击取消选择;

选择的单个矩形可以对矩形进行拆分,选择多个矩形可以进行合并;

如果矩形已经被拆分成多少,当上下拖动的时候,全部矩形跟随;

2.代码

2.1 主函数

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow91 w; // 更改为 MainWindow91
    w.resize(500,400);
    w.show();
    return a.exec();
}

 2.2 窗口类

2.2.1 头文件

#ifndef MAINWINDOW91_H
#define MAINWINDOW91_H

#include <QWidget>
#include <QMenu>
#include <QAction>
#include <QMouseEvent>
#include <QGraphicsRectItem>
#include "CustomRectItem91.h"

class MainWindow91 : public QWidget
{
    Q_OBJECT

public:
    static MainWindow91* pMainWindow91;
    static MainWindow91* getMy();
    MainWindow91(QWidget *parent = nullptr);
    ~MainWindow91();
    void selectId(int di);
    void moveSelectId(int di);
    void setPostY(qreal y);//当别的控件上下拖动的时候,全部的控件保持一致
protected:
    void mousePressEvent(QMouseEvent *event) override;
private slots:
    void onMergeActionTriggered();
    void onSplitActionTriggered();

private:
    QGraphicsScene *scene;
    QMenu *contextMenu;
    QAction *mergeAction;
    QAction *splitAction;
    QList<int> indexIds;
    QList<int> selectIds;
    void clearSelect();//删除选择
    //void addSelect(int id);//添加选择
    //void removeSelect(int id);//移除选择
    QMap<int,CustomRectItem91 *> itemMaps;
    //QGraphicsRectItem *originalRect;
};

#endif // MAINWINDOW91_H

2.2.2 源文件 

#include "mainwindow91.h"
#include <QMouseEvent>
#include <QDebug>
#include <QGraphicsView>
#include <QGraphicsScene>
#include "CustomRectItem91.h"
#include "main9publics.h"

MainWindow91* MainWindow91::pMainWindow91 = NULL;

MainWindow91* MainWindow91::getMy(){
    return pMainWindow91;
}

MainWindow91::MainWindow91(QWidget *parent)
    : QWidget(parent)
{
    pMainWindow91 = this;

    // 创建一个QGraphicsScene和QGraphicsView
    scene = new QGraphicsScene();
    QGraphicsView *view = new QGraphicsView(scene, this);
    view->setGeometry(10, 10, 500, 400);
    // 创建原始矩形
    //CustomRectItem91 *originalRect = scene->addRect(0, 0, 200, 100, QPen(Qt::black), QBrush(Qt::blue));
    QRectF mergedRect(20, 20, 400, 100);
    CustomRectItem91 *originalRect = new CustomRectItem91(mergedRect);
    QPen pen(Qt::red); // 设置蓝色边框
    originalRect->setPen(pen);

    scene->addItem(originalRect);
    itemMaps.insert(originalRect->Id,originalRect);
    indexIds.append(originalRect->Id);
    // 创建右键菜单和动作
    contextMenu = new QMenu(this);
    mergeAction = contextMenu->addAction("合并");
    splitAction = contextMenu->addAction("拆分");

    // 连接信号和槽
    connect(mergeAction, &QAction::triggered, this, &MainWindow91::onMergeActionTriggered);
    connect(splitAction, &QAction::triggered, this, &MainWindow91::onSplitActionTriggered);
}

MainWindow91::~MainWindow91()
{
}

void MainWindow91::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton) {
        contextMenu->exec(event->globalPos());
    }
}

void MainWindow91::onMergeActionTriggered()
{
    qDebug() << "合并操作被触发";
    // 在这里实现合并的逻辑
    if(selectIds.length()<=1){
        qDebug()<<"selectIds.length():"<<selectIds.length();
    }
    int statId = selectIds.first();
    int endId = selectIds.last();

    CustomRectItem91* istart = itemMaps[statId];
    CustomRectItem91* iend = itemMaps[endId];

    int startIndex = indexIds.indexOf(statId);//获取选择的控件在列表中的下标
    //取消选择
    for (int value : selectIds){
        CustomRectItem91* sItem = itemMaps[value];
        sItem->moveSelect();//取消选择属性,为合并控件打好基础
        scene->removeItem(sItem);//移除控件
        itemMaps.remove(value);//移除对象类别
        indexIds.removeOne(value);//移除对象排序列表
    }

    //合并
    CustomRectItem91* inew  = mergeRects(istart,iend);
    scene->addItem(inew);//添加合并后的控件
    itemMaps.insert(inew->Id,inew);//添加对象map
    indexIds.insert(startIndex,inew->Id);//添加控制顺序列表

    //清除创建的对象
    for (int value : selectIds){
        CustomRectItem91* sItem = itemMaps[value];
        delete sItem;
    }

    selectIds.clear();//清除选择列表
}

void MainWindow91::onSplitActionTriggered()
{
    qDebug() << "拆分操作被触发";
    if(selectIds.length()<=0){
        qDebug()<<"selectIds.length():"<<selectIds.length();
    }
    // 拆分矩形
    int id = selectIds.first();
    int startIndex = indexIds.indexOf(id);//获取选择的控件在列表中的下标
    CustomRectItem91* originalRect = itemMaps[id];
    originalRect->moveSelect();
    auto [leftRect, rightRect] = splitRect(originalRect);
    scene->removeItem(originalRect);
    scene->addItem(leftRect);
    scene->addItem(rightRect);
    selectIds.clear();

    itemMaps.remove(originalRect->Id);
    itemMaps.insert(leftRect->Id,leftRect);
    itemMaps.insert(rightRect->Id,rightRect);

    indexIds.removeOne(originalRect->Id);
    indexIds.insert(startIndex,leftRect->Id);
    indexIds.insert(startIndex+1,rightRect->Id);
    //indexIds.append(leftRect->Id);
    //indexIds.append(rightRect->Id);

    //delete originalRect;
    // 在这里实现拆分的逻辑
}

void MainWindow91::selectId(int id){
    int myIndex = indexIds.indexOf(id);//我的下标序号
    if(selectIds.length()>0){
        int indexStart  = indexIds.indexOf(selectIds.first());//已经选择的序号列表的头
        if(myIndex<indexStart){
            if(myIndex!=indexStart-1){
                //重新选择
                clearSelect();
            }else{
                //链接
            }
            selectIds.insert(0,id);
        }else{
            int indexEnd  = indexIds.indexOf(selectIds.last());
            if(myIndex!=indexEnd+1){
                //重新选择
                clearSelect();
            }else{
                //链接
            }
            selectIds.append(id);
        }
    }else{
        this->selectIds.append(id);
    }
}

void MainWindow91::moveSelectId(int id){
    this->selectIds.removeOne(id);
}

//删除选择,同时要更新ui的状态,ui也去掉选择
void MainWindow91::clearSelect(){
    for (int value : selectIds){
        itemMaps[value]->moveSelect();
    }
    selectIds.clear();
}
//当别的控件上下拖动的时候,全部的控件保持一致
void MainWindow91::setPostY(qreal y){
    for (int value : indexIds){
        itemMaps[value]->setPostY(y);
    }
}

2.3 矩形类

2.3.1 头文件 

#ifndef CUSTOMRECTITEM91_H
#define CUSTOMRECTITEM91_H

#include <QGraphicsRectItem>
#include <QColor>
#include <QRectF>

class CustomRectItem91 : public QGraphicsRectItem {
public:
    static int idNum;
    CustomRectItem91(QGraphicsItem *parent = nullptr);
    CustomRectItem91(const QRectF &rect, QGraphicsItem *parent = nullptr);
    int Id;
    void moveSelect();
    void setPostY(qreal y);//当别的控件上下拖动的时候,全部的控件保持一致
protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;

private:
    QColor originalColor;
    enum Edge { NoEdge, LeftEdge, RightEdge };
    Edge draggingEdge = NoEdge;
    bool draggingItem = false;
    QPointF lastMousePos;
    bool isNearEdge(const QPointF &pos, Edge edge) const;
};

#endif // CUSTOMRECTITEM91_H

2.3.2 资源文件 

#include "CustomRectItem91.h"
#include <QMouseEvent>
#include <QBrush>
#include <QPen>
#include <QGraphicsSceneMouseEvent>
#include "mainwindow91.h"

int CustomRectItem91::idNum = 0;

CustomRectItem91::CustomRectItem91(QGraphicsItem *parent)
    : QGraphicsRectItem(parent) {
    //setFlag(QGraphicsItem::ItemIsMovable, false);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
    // 设置初始颜色并保存为原始颜色
    //originalColor = Qt::black; // 或者您想要的任何初始颜色
    originalColor = Qt::red; // 或者您想要的任何初始颜色
    //setBrush(QBrush(originalColor));
    Id = idNum++;
    //MainWindow91* mw = MainWindow91::getMy();
}

CustomRectItem91::CustomRectItem91(const QRectF &rect, QGraphicsItem *parent): QGraphicsRectItem(rect,parent){
    // 设置初始颜色并保存为原始颜色
    originalColor = Qt::red; // 或者您想要的任何初始颜色
    //setBrush(QBrush(originalColor));
    Id = idNum++;
}

void CustomRectItem91::mousePressEvent(QGraphicsSceneMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        if(event->modifiers() & Qt::ControlModifier){
            if (contains(event->pos())) {
                QColor currentColor = pen().color();
                if (currentColor == originalColor) {
                    // 变成红色
                    setPen(QPen(Qt::blue));
                    //setBrush(QBrush(Qt::red));
                    MainWindow91::getMy()->selectId(Id);
                } else {
                    // 恢复原来的颜色
                    //setBrush(QBrush(originalColor));
                    setPen(QPen(originalColor));
                    MainWindow91::getMy()->moveSelectId(Id);
                }
                update(); // 更新图形项以反映颜色变化
            }

        }else{
            if (isNearEdge(event->pos(), LeftEdge)) {
                draggingEdge = LeftEdge;
                qDebug()<<"draggingEdge left ";
                setCursor(Qt::SplitHCursor);
            } else if (isNearEdge(event->pos(), RightEdge)) {
                draggingEdge = RightEdge;
                setCursor(Qt::SplitHCursor);
                qDebug()<<"draggingEdge right";
            } else {
                draggingItem = true;
                lastMousePos = event->pos();
                setCursor(Qt::OpenHandCursor);
                qDebug()<<"draggingItem";
            }
            update();
        }
    }else{
        QGraphicsRectItem::mousePressEvent(event); // 调用基类的mousePressEvent以处理其他可能的交互
    }
    //
}

void CustomRectItem91::moveSelect()
{
    // 恢复原来的颜色
    //setBrush(QBrush(originalColor));
    setPen(QPen(originalColor));
    update(); // 更新图形项以反映颜色变化
}


void CustomRectItem91::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
    if (draggingEdge == LeftEdge) {
        qreal newWidth = rect().width() - (event->pos().x() - rect().left());
        setRect(QRectF(event->pos().x(), rect().y(), newWidth, rect().height()));
    } else if (draggingEdge == RightEdge) {
        qreal newWidth = event->pos().x() - rect().left();
        setRect(QRectF(rect().left(), rect().y(), newWidth, rect().height()));
    } else if (draggingItem) {
        auto dy = event->pos().y() - lastMousePos.y();
        //auto newPos = pos() + QPointF(0, dy);
        //setPos(newPos);
        //lastMousePos = event->pos();
        MainWindow91* mw = MainWindow91::getMy();
        mw->setPostY(dy);
    }
}
//上下位置移动
//其他控件移动,我也跟着移动
void CustomRectItem91::setPostY(qreal movey){
    auto newPos = pos() + QPointF(0, movey);
    setPos(newPos);
}

void CustomRectItem91::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
    if (event->button() == Qt::LeftButton) {
        draggingEdge = NoEdge;
        draggingItem = false;
        setCursor(Qt::ArrowCursor);
        update();
        qDebug()<<"mouseReleaseEvent";
    }
}



bool CustomRectItem91::isNearEdge(const QPointF &pos, Edge edge)const{
    QRectF edgeRect;
    switch (edge) {
    case LeftEdge:
        edgeRect = QRectF(rect().x()-10, rect().y(), 20, rect().height());
        break;
    case RightEdge:
        edgeRect = QRectF(rect().x()+rect().width() - 10, rect().y(), 20, rect().height());
        break;
    default:
        break;
    }
    return edgeRect.contains(pos);
}

2.4.矩形的拆分和合并函数

2.4.1 头文件 

#ifndef MAIN9PUBLICS_H
#define MAIN9PUBLICS_H
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include "CustomRectItem91.h"

std::pair<CustomRectItem91*, CustomRectItem91*> splitRect(CustomRectItem91 *originalRect);

CustomRectItem91* mergeRects(CustomRectItem91 *rect1, CustomRectItem91 *rect2);

#endif // MAIN9PUBLICS_H

2.4.2 源文件 

#include "main9publics.h"

// 函数用于拆分矩形
std::pair<CustomRectItem91*, CustomRectItem91*> splitRect(CustomRectItem91 *originalRect) {
    QRectF originalRectF = originalRect->rect();
    QPointF originalPos = originalRect->pos();

    QRectF leftRect(0, 0, originalRectF.width() / 2-5, originalRectF.height());
    QRectF rightRect(0, 0, originalRectF.width() / 2-5, originalRectF.height());

    CustomRectItem91 *leftPart = new CustomRectItem91(leftRect);
    CustomRectItem91 *rightPart = new CustomRectItem91(rightRect);

    leftPart->setPos(originalPos);
    rightPart->setPos(QPointF(originalPos.x() + leftRect.width() + 10, originalPos.y()));
    //设置矩形的默认边框
    leftPart->setPen(originalRect->pen());
    rightPart->setPen(originalRect->pen());
    //leftPart->setBrush(originalRect->brush());
    //rightPart->setBrush(originalRect->brush());

    return {leftPart, rightPart};
}

// 函数用于合并矩形,根据两个矩形的位置和大小来计算合并后的矩形
CustomRectItem91* mergeRects(CustomRectItem91 *rect1, CustomRectItem91 *rect2) {
    QRectF rect1F = rect1->rect();
    QPointF rect1Pos = rect1->pos();
    QRectF rect2F = rect2->rect();
    QPointF rect2Pos = rect2->pos();

    // 计算合并后矩形的位置和大小
    qreal mergedWidth = rect1F.width() + (rect2Pos.x() - rect1Pos.x() - rect1F.width()) + rect2F.width();
    QRectF mergedRect(rect1Pos.x(), rect1Pos.y(), mergedWidth, rect1F.height());

    CustomRectItem91 *mergedRectItem = new CustomRectItem91(mergedRect);
    //mergedRectItem->setBrush(rect1->brush());
    //设置矩形的默认边框
    mergedRectItem->setPen(rect1->pen());

    // 清理旧的矩形
    //delete rect1;
    //delete rect2;

    return mergedRectItem;
}


3.运行结果

拖拽、缩放、鼠标形状3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值