【Qt】交由用户自定义布局并记录

需求

1.可以自定义行数和列数。

2.可以自定义窗体占用的行数和列数。

3.可以保存用户自定义的布局。

思路

通过继承QWidget,在paintEvent事件中,根据行列数绘制 网格 单元格(cell)及区域(LOCATION)。

在mousePressEvent中获取鼠标起始点,通过计算获取起始点所在的单元格

在mouseMoveEvent中实时获取鼠标点,通过计算获取当前点所在的单元格(cell),根据起始点所在单元格的行列数当前点所在的单元格行列数,计算出所有跨越包含的单元格(cell)(就像是绘制矩形,有一个起始点和终点就可以得出矩形的位置和长宽。)并添加到列表中。如果其中包含的单元格在已经选定的区域(LOCATION:包含大于等于1个单元格)中,就清空当前的单元格列表。绘制效果。

在mouseRealeaseEvent中获取鼠标点,通过计算获取鼠标释放时鼠标点所在的单元格。如果此单元格在其他已经存在的区域中,则没有意义,不进行保存区域操作;如果单元格不在已经存在的区域中,且该区域内的所有单元格都不在其他已经存在的区域内,就保存当前的区域,将此区域加入区域列表中。绘制效果。

LOCATION中包含起始行起始列,以及跨越的行数跨域的列数

在类中有row和column用于记录当前的总行数和总列数。并可以通过函数修改这两个值,通过更新重新绘制网格。

效果

 代码

class LayoutBox:public QWidget{
    Q_OBJECT
public:
    struct LOCATION{
        LOCATION(int _row,int _column,int _rowSpan,int _columnSpan){
            row=_row;column=_column;rowSpan=_rowSpan;columnSpan=_columnSpan;
        }
        int row=-1;
        int column=-1;
        int rowSpan=-1;
        int columnSpan=-1;
        int appID=-1;
    };
    enum MODE{
        THREE_ONE_THREE,    //3+1+3
        THREE_ONE_THREE_ONE,    //3+1+3+1
        TWO_ONE_TWO,    //2+1+2
        TWO_ONE_TWO_ONE,    //2+1+2+1
        THREE_ONE,          //3+1
    };
public:
    explicit LayoutBox(QWidget* parent=nullptr);
    ~LayoutBox();
    void clear();
    void setRow(int row);
    void setColumn(int column);
    void setDefault();
    void setMode(MODE mode);
protected:
    void resizeEvent(QResizeEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event)override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseDoubleClickEvent(QMouseEvent *event) override;
private:
    bool isInLoationList(LOCATION &cell);
    LOCATION getCell(QPoint pos);
    QList<QRectF> getCellRects(int startRow,int startColumn,int endRow,int endColumn);
    QRectF getCellRect(LOCATION &cell);
    QRectF getLocationRect(LOCATION &location);
    int getLocation(LOCATION &cell);
    void setLocationAppID(int index,int appID);
signals:
    void locationClickedSignal(int);
private:
    int _row=6;     //行数
    int _column=8;      //列数
    double _cellWidth=0;       //单元格宽度
    double _cellHeight=0;      //单元格高度
    int _midLine=1;         //分界线宽度
    QList<LOCATION> _locationList;      //位置列表
    LOCATION _startCell=LOCATION(-1,-1,1,1);
    bool _isStart=false;        //是否开始
    QList<QRectF> _currentRects; //当前选中的布局
};
LayoutBox::LayoutBox(QWidget* parent):QWidget(parent){}
LayoutBox::~LayoutBox(){}
void LayoutBox::clear(){
    _locationList.clear();
    _currentRects.clear();
    _isStart=false;
    update();
}
void LayoutBox::setRow(int row){
    if(row<=0){
        _row=1;
    }else if(row>50){
        _row=50;
    }else{
        _row=row;
    }
    _cellWidth=(width()-_midLine*(_column+1))/(double)_column;
    _cellHeight=(height()-_midLine*(_row+1))/(double)_row;
    clear();
}
void LayoutBox::setColumn(int column){
    if(column<=0){
        _column=1;
    }else if(column>50){
        _column=50;
    }else{
        _column=column;
    }
    _cellWidth=(width()-_midLine*(_column+1))/(double)_column;
    _cellHeight=(height()-_midLine*(_row+1))/(double)_row;
    clear();
}
void LayoutBox::setDefault(){
    _column=8;
    _row=6;
    _cellWidth=(width()-_midLine*(_column+1))/(double)_column;
    _cellHeight=(height()-_midLine*(_row+1))/(double)_row;
    clear();
}
void LayoutBox::setMode(MODE mode){
    setDefault();
    if(mode==THREE_ONE_THREE){
        _locationList<<LOCATION(0,0,2,2)<<LOCATION(2,0,2,2)<<LOCATION(4,0,2,2)<<LOCATION(0,2,6,4)<<LOCATION(0,6,2,2)<<LOCATION(2,6,2,2)<<LOCATION(4,6,2,2);
    }else if(mode==THREE_ONE_THREE_ONE){
        _locationList<<LOCATION(0,0,2,2)<<LOCATION(2,0,2,2)<<LOCATION(4,0,2,2)<<LOCATION(0,2,5,4)<<LOCATION(5,2,1,4)<<LOCATION(0,6,2,2)<<LOCATION(2,6,2,2)<<LOCATION(4,6,2,2);
    }else if(mode==TWO_ONE_TWO){
        _locationList<<LOCATION(0,0,3,2)<<LOCATION(3,0,3,2)<<LOCATION(0,2,6,4)<<LOCATION(0,6,3,2)<<LOCATION(3,6,3,2);
    }else if(mode==TWO_ONE_TWO_ONE){
        _locationList<<LOCATION(0,0,3,2)<<LOCATION(3,0,3,2)<<LOCATION(0,2,4,4)<<LOCATION(4,2,2,4)<<LOCATION(0,6,3,2)<<LOCATION(3,6,3,2);
    }else if(mode==THREE_ONE){
        _locationList<<LOCATION(0,0,2,2)<<LOCATION(2,0,2,2)<<LOCATION(4,0,2,2)<<LOCATION(0,2,6,6);
    }
    update();
}
void LayoutBox::resizeEvent(QResizeEvent *event){
    Q_UNUSED(event)
    _cellWidth=(width()-_midLine*(_column+1))/(double)_column;
    _cellHeight=(height()-_midLine*(_row+1))/(double)_row;
}
void LayoutBox::paintEvent(QPaintEvent *event){
    Q_UNUSED(event)
    QPainter painter(this);
    painter.save();
    painter.setRenderHints(QPainter::Antialiasing,true);
    painter.setPen(Qt::NoPen);
    painter.setBrush(PAINT::yellow);
    for(int i=0;i<_column+1;i++){
        QRectF rect(i*(_midLine+_cellWidth),0,_midLine,height());
        painter.drawRect(rect);
    }
    for(int i=0;i<_row+1;i++){
        QRectF rect(0,i*(_midLine+_cellHeight),width(),_midLine);
        painter.drawRect(rect);
    }
    painter.setBrush(PAINT::blue20);
    for(int i=0;i<_currentRects.length();i++){
        QRectF rect=_currentRects.at(i);
        painter.drawRect(rect);
    }
    painter.setBrush(PAINT::deepblue);
    for(int i=0;i<_locationList.size();i++){
        LOCATION location=_locationList.at(i);
        QRectF rect=getLocationRect(location);
        painter.drawRect(rect);
        if(location.appID>=0){
            painter.setPen(Qt::white);
            painter.drawText(rect,Qt::AlignCenter,QString("AppID:%1").arg(location.appID));
            painter.setPen(Qt::NoPen);
        }
    }
    painter.restore();
}
void LayoutBox::mouseDoubleClickEvent(QMouseEvent *event){
    LOCATION cell=getCell(event->pos());
    if(cell.row>=0&&cell.column>=0&&isInLoationList(cell)){
        int locationIndex=getLocation(cell);
        emit locationClickedSignal(locationIndex);
    }
}
void LayoutBox::mousePressEvent(QMouseEvent *event){
    LOCATION cell=getCell(event->pos());
    if(cell.row>=0&&cell.column>=0){
        if(!isInLoationList(cell)){
            _startCell=cell;
            _isStart=true;
        }
    }else{
        _isStart=false;
    }
}
void LayoutBox::mouseMoveEvent(QMouseEvent *event){
    if(_isStart){
        LOCATION cell=getCell(event->pos());
        if(cell.row>=0&&cell.column>=0&&!isInLoationList(cell)){
            _currentRects=getCellRects(_startCell.row,_startCell.column,cell.row,cell.column);
            update();
        }else{
            _currentRects.clear();
            update();
        }
    }else{
        _currentRects.clear();
    }
}
void LayoutBox::mouseReleaseEvent(QMouseEvent *event){
    if(_isStart){
        LOCATION cell=getCell(event->pos());
        if(cell.row>=0&&cell.column>=0&&_currentRects.length()!=0){
            int sRow=qMin(_startCell.row,cell.row);
            int eRow=qMax(_startCell.row,cell.row);
            int sColumn=qMin(_startCell.column,cell.column);
            int eColumn=qMax(_startCell.column,cell.column);
            LOCATION location(sRow,sColumn,eRow-sRow+1,eColumn-sColumn+1);
            _locationList.append(location);
            update();
        }
    }
    _isStart=false;
}
bool LayoutBox::isInLoationList(LayoutBox::LOCATION &cell){
    for(int i=0;i<_locationList.length();i++){
        LOCATION location=_locationList.at(i);
        if(location.row<=cell.row&&cell.row<=location.row+location.rowSpan-1&&location.column<=cell.column&&cell.column<=location.column+location.columnSpan-1){
            return true;
        }
    }
    return false;
}
LayoutBox::LOCATION LayoutBox::getCell(QPoint pos){
    if(pos.x()>0&&pos.x()<width()&&pos.y()>0&&pos.y()<height()){
        int column=qFloor(pos.x()/(_cellWidth+_midLine));
        int row=qFloor(pos.y()/(_cellHeight+_midLine));
        return LOCATION(row,column,1,1);
    }else{
        return LOCATION(-1,-1,1,1);
    }
}
QList<QRectF> LayoutBox::getCellRects(int startRow,int startColumn,int endRow,int endColumn){
    QList<QRectF> rects;
    int sRow=qMin(startRow,endRow);
    int eRow=qMax(startRow,endRow);
    int sColumn=qMin(startColumn,endColumn);
    int eColumn=qMax(startColumn,endColumn);
    for(int row=sRow;row<eRow+1;row++){
        for(int column=sColumn;column<eColumn+1;column++){
            LOCATION cell(row,column,1,1);
            if(isInLoationList(cell)){
                rects.clear();
                return rects;
            }else{
                QRectF rect=getCellRect(cell);
                rects.append(rect);
            }
        }
    }
    return rects;
}
QRectF LayoutBox::getCellRect(LayoutBox::LOCATION &cell){
    return QRectF(_midLine+cell.column*(_cellWidth+_midLine),_midLine+cell.row*(_cellHeight+_midLine),_cellWidth,_cellHeight);
}
QRectF LayoutBox::getLocationRect(LayoutBox::LOCATION &location){
    double sx=_midLine+location.column*(_midLine+_cellWidth);
    double sy=_midLine+location.row*(_midLine+_cellHeight);
    double w=(_midLine+_cellWidth)*location.columnSpan-_midLine;
    double h=(_midLine+_cellHeight)*location.rowSpan-_midLine;
    return QRectF(sx,sy,w,h);
}
int LayoutBox::getLocation(LOCATION &cell){
    for(int i=0;i<_locationList.length();i++){
        LOCATION location=_locationList.at(i);
        if(location.row<=cell.row&&cell.row<=location.row+location.rowSpan-1&&location.column<=cell.column&&cell.column<=location.column+location.columnSpan-1){
            return i;
        }
    }
    return -1;
}
void LayoutBox::setLocationAppID(int index, int appID){
    _locationList[index].appID=appID;
}

后语

本示例代码没有实现保存和读取,可以自行定义配置文件保存这些布局数据,在需要时加载配置数据得到效果。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值