Qt界面中的子窗口实现鼠标拖动边缘改变大小以及移动(完整demo代码)

news/2024/7/8 1:50:45 标签: qt, 开发语言, 用户界面

目录

效果

拖拽

移动​编辑

实现

 DragResizeWgt类.h文件

DragResizeWgt类.cpp文件 

使用

 testwidget窗口.ui文件

testwidget窗口.h文件

testwidget窗口.cpp文件

参考


效果

想要的效果就是类似于QT IDE中的效果,可以拖动边缘改变大小,用户自身可以调整一些窗口的布局,方便使用,如下所示:

demo完成后,经测试达到的效果,如下所示:

拖拽

移动

如果你想要的是这样的效果,无需多言,上代码。

实现

这是一个自定义的窗口类,需要重写窗口的一些函数,如下所示:

    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);
    void resizeEvent(QResizeEvent *event);

 DragResizeWgt类.h文件

#ifndef DRAGRESIZEWGT_H
#define DRAGRESIZEWGT_H

#include <QWidget>
#include <QMouseEvent>
#include <QPoint>
#include <QScreen>
#include <QPainter>
#include <QResizeEvent>
#include <QEvent>
namespace Ui {
class DragResizeWgt;
}

class DragResizeWgt : public QWidget
{
    Q_OBJECT
    enum DIRECTION{
        nodir,
        top = 0x01,
        bottom = 0x02,
        left = 0x04,
        right = 0x08,
        topLeft = 0x01 | 0x04,
        topRight = 0x01 | 0x08,
        bottomLeft = 0x02 | 0x04,
        bottomRight = 0x02 | 0x08};
public:
    explicit DragResizeWgt(QWidget *parent = nullptr);
    ~DragResizeWgt();
signals:
    void sizeChange();
public:
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);
    void resizeEvent(QResizeEvent *event);
    bool eventFilter(QObject *watch, QEvent *event);
    void setEdgeBeReSized(const bool& resizeableTop, const bool& resizeableBottom, const bool& resizeableRight, const bool& resizeableLeft);
    void setIsRepositioning(const bool& reposition);
private:
    void checkEdge();
private:
    Ui::DragResizeWgt *ui;

    QPoint m_startCursor;

    int m_nLeftOff = 0;//鼠标开始拖拽时子窗口左边相对父窗口左边的距离
    int m_nRightOff = 0;//鼠标开始拖拽时子窗口右边相对父窗口左边的距离
    int m_nTopOff = 0;//鼠标开始拖拽时子窗口上边相对父窗口上边的距离
    int m_nBottomOff = 0;//鼠标开始拖拽时子窗口下边相对父窗口上边的距离

    QPoint dragPosition;   //鼠标拖动的位置
    int    edgeMargin = 4;     //鼠标检测的边缘距离
    DIRECTION resizeDir; //更改尺寸的方向

    bool m_resizing;
    bool m_repositioning;
    //帮助判断是否需要激活边框可变化大小
    bool m_resizeableTop;
    bool m_resizeableBottom;
    bool m_resizeableRight;
    bool m_resizeableLeft;
};

#endif // DRAGRESIZEWGT_H

DragResizeWgt类.cpp文件 

#include "DragResizeWgt.h"
#include "ui_DragResizeWgt.h"
#include <QDebug>
#include "Windows.h"
#include <QMouseEvent>
#include <QObject>
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#define min(a,b) ((a)<(b)? (a) :(b))
#define max(a,b) ((a)>(b)? (a) :(b))

DragResizeWgt::DragResizeWgt(QWidget *parent) :
    QWidget(parent),ui(new Ui::DragResizeWgt),
    resizeDir(nodir), m_resizing(false),m_repositioning(false),
    m_resizeableTop(true), m_resizeableBottom(true),
    m_resizeableRight(true), m_resizeableLeft(true)
{
    ui->setupUi(this);
    this->setObjectName("DragResizeWgt");

    //注意:一定要设置一个最小的宽高奥,要不会被拖到看不见,默认最小(0,0)
    setMinimumSize(100, 100);

    //一定一定要有这句话奥,这是能捕捉到这个窗口鼠标事件的关键,还有一点需要特别注意,如果这个窗口上会叠加其他的widget或者控件,对应的子UI也需要调用setMouseTracking这个函数
    this->setMouseTracking(true);

    //鼠标事件过滤器,来处理父窗口与子窗口的事件关系,不能互相干扰,后续会十分用得到
    setAttribute(Qt::WA_NoMousePropagation);
    installEventFilter(this);
    // QVBoxLayout *layout = new QVBoxLayout(this);
    // QLabel *label = new QLabel("Resizable and Draggable Widget", this);
    // layout->addWidget(label);

    edgeMargin = 4;        //设置检测边缘为4
    resizeDir = nodir;   //初始化检测方向为无

    setEdgeBeReSized(false,true,true,false);
    // setEdgeBeReSized(true,true,true,true);
    setLayout(new QHBoxLayout);
}

DragResizeWgt::~DragResizeWgt() = default;

void DragResizeWgt::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)  //每当按下鼠标左键就记录一下位置
    {
        dragPosition = event->globalPos() - frameGeometry().topLeft();  //获得鼠标按键位置相对窗口左上面的位置
        m_startCursor = event->globalPos();

        m_nLeftOff = frameGeometry().left();
        m_nRightOff = frameGeometry().right() + 1;
        m_nTopOff = frameGeometry().top();
        m_nBottomOff = frameGeometry().bottom() + 1;
        qDebug() << "mousePressEvent" << dragPosition << m_startCursor << m_nLeftOff << m_nRightOff << m_nTopOff << m_nBottomOff;
    }
}

void DragResizeWgt::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton)//如果左键是按下的
    {
        if(resizeDir == nodir)//鼠标未放置在边缘处,进行窗口整体拖动处理
        {
            if(m_repositioning)
            {
                move(event->globalPos() - dragPosition);
            }
        }
        else//拖拽边缘,根据拖拽方向进行大小调整
        {

            int ptop,pbottom,pleft,pright;
            ptop = m_nTopOff;
            pbottom = m_nBottomOff;
            pleft = m_nLeftOff;
            pright = m_nRightOff;
            //这里获取父窗口的大小,如果没有则获取全局可用的屏幕大小
            QRect parentRect = parentWidget() ? parentWidget()->rect() : QApplication::primaryScreen()->availableGeometry();
            if(resizeDir & top)//拖拽顶部上下变化
            {
                //计算根据当前鼠标位置与拖拽偏移量计算当前top的位置
                ptop = m_nTopOff-(m_startCursor.ry()- event->globalY());
                qDebug() << "#########top position" << ptop << m_nTopOff << m_startCursor.ry() << event->globalY();
                if(ptop < 0)
                {
                    ptop = parentRect.height() - this->maximumHeight();
                }
                else{
                    if(this->height() <= minimumHeight())//进行极端高度最小的处理
                    {
                        ptop = min(m_nBottomOff-minimumHeight(),ptop);
                        qDebug() << "this->height() >= minimumHeight()" << ptop  << m_nBottomOff << minimumHeight();
                    }
                    else if(this->height() >= maximumHeight())//进行极端高度最大的处理
                    {
                        ptop = max(m_nBottomOff-maximumHeight(),ptop);
                        qDebug() << "this->height() >= maximumHeight()" << ptop << m_nBottomOff << maximumHeight();
                    }
                }
            }
            else if(resizeDir & bottom)//拖拽底部上下变化
            {
                //计算根据当前鼠标位置与拖拽偏移量计算当前bottom的位置
                pbottom = m_nBottomOff +(event->globalY()-m_startCursor.ry());
                if(pbottom > parentRect.bottom())
                {
                    pbottom = this->maximumHeight();
                }else{
                    if(this->height()<minimumHeight())//进行极端高度最小的处理
                    {
                        pbottom = m_nTopOff+minimumHeight();
                    }
                    else if(this->height()>maximumHeight())//进行极端高度最大的处理
                    {
                        pbottom = m_nTopOff+maximumHeight();
                    }
                }
            }

            if(resizeDir & left)//拖拽左侧左右变化
            {
                //计算根据当前鼠标位置与拖拽偏移量计算当前left的位置
                pleft = m_nLeftOff-(m_startCursor.rx() - event->globalX());
                if(pleft < 0)
                {
                    pleft = 0;
                }else{
                    if(this->width()<= minimumWidth())//进行极端宽度最小的处理
                    {
                        pleft = min(pleft,m_nRightOff- minimumWidth());
                    }
                    else if(this->width() >= maximumWidth())//进行极端宽度最大的处理
                    {
                        pleft = max(m_nRightOff- maximumWidth(),pleft);
                    }
                }
            }
            else if(resizeDir & right)//拖拽右侧左右变化
            {
                //计算根据当前鼠标位置与拖拽偏移量计算当前right的位置
                pright = m_nRightOff + (event->globalX()-m_startCursor.rx());
                if(pright > parentRect.right())
                {
                    pright = parentRect.right();
                }
                if(this->width()<minimumWidth())//进行极端宽度最小的处理
                {
                    pright = m_nLeftOff+minimumWidth();
                }
                else if(this->width()> this->maximumWidth())//进行极端宽度最大的处理
                {
                    pright = m_nLeftOff + this->maximumWidth();
                }
            }
            setGeometry(pleft,ptop,pright-pleft,pbottom-ptop);
            emit sizeChange();
        }

    }
    else checkEdge();
}

void DragResizeWgt::mouseReleaseEvent(QMouseEvent * event)
{
    // Q_UNUSED(event);
    if(resizeDir != nodir)//还原鼠标样式
    {
        checkEdge();
        emit sizeChange();
    }
}

void DragResizeWgt::paintEvent(QPaintEvent *event)
{
    // QPainter painter(this);
    // painter.fillRect(rect(), Qt::white);
    QWidget::paintEvent(event);
}

void DragResizeWgt::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);
    // emit sizeChange();
}

bool DragResizeWgt::eventFilter(QObject *watch, QEvent *event)
{
    //一定要加这一句,不然父窗口的event事件也会出发窗口大小的改变信号
    if(watch == parentWidget() && event->type() == QEvent::MouseButtonRelease)
    {
        event->ignore();
        return true;
    }
    // if(watch == parentWidget() && event->type() == QEvent::Resize)
    // {
    //     event->ignore();
    //     return true;
    // }
    return QWidget::eventFilter(watch, event);
}

void DragResizeWgt::setEdgeBeReSized(const bool &resizeableTop, const bool &resizeableBottom, const bool &resizeableRight, const bool &resizeableLeft)
{
    m_resizeableTop = resizeableTop;
    m_resizeableBottom =  resizeableBottom;
    m_resizeableRight = resizeableRight;
    m_resizeableLeft = resizeableLeft;
}

void DragResizeWgt::setIsRepositioning(const bool &reposition)
{
    m_repositioning = reposition;
}

void DragResizeWgt::checkEdge()
{
    QPoint pos = this->mapFromGlobal(QCursor::pos());//开始拖拽时点击控件的什么位置

    int diffLeft = pos.rx();
    int diffRight = this->width() - diffLeft;
    int diffTop = pos.ry();
    int diffBottom = this->height() - diffTop;
    QCursor tempCursor;                                    //获得当前鼠标样式,注意:只能获得当前鼠标样式然后再重新设置鼠标样式
    tempCursor = cursor();                                 //因为获得的不是鼠标指针,所以不能这样用:cursor().setXXXXX

    // qDebug() << "diffLeft" << diffLeft << "diffRight" << diffRight << "diffTop" << diffTop << "diffBottom" << diffBottom ;
    if(diffTop < edgeMargin && m_resizeableTop)
    {                              //根据 边缘距离 分类改变尺寸的方向
        if(diffLeft < edgeMargin  && m_resizeableTop && m_resizeableLeft)
        {
            resizeDir = topLeft;
            tempCursor.setShape(Qt::SizeFDiagCursor);
        }
        else if(diffRight < edgeMargin && m_resizeableTop && m_resizeableRight)
        {
            resizeDir = topRight;
            tempCursor.setShape(Qt::SizeBDiagCursor);
        }
        else
        {
            resizeDir = top;
            tempCursor.setShape(Qt::SizeVerCursor);
        }
    }
    else if(diffBottom < edgeMargin && m_resizeableBottom)
    {
        if(diffLeft < edgeMargin && m_resizeableBottom && m_resizeableLeft)
        {
            resizeDir = bottomLeft;
            tempCursor.setShape(Qt::SizeBDiagCursor);
        }
        else if(diffRight < edgeMargin && m_resizeableBottom && m_resizeableRight)
        {
            resizeDir = bottomRight;
            tempCursor.setShape(Qt::SizeFDiagCursor);
        }
        else
        {
            resizeDir = bottom;
            tempCursor.setShape(Qt::SizeVerCursor);
        }
    }
    else if(diffLeft < edgeMargin && m_resizeableLeft)
    {
        resizeDir = left;
        tempCursor.setShape(Qt::SizeHorCursor);
    }
    else if(diffRight < edgeMargin && m_resizeableRight)
    {
        resizeDir = right;
        tempCursor.setShape(Qt::SizeHorCursor);
    }
    else
    {
        resizeDir = nodir;
        tempCursor.setShape(Qt::ArrowCursor);
    }

    setCursor(tempCursor);
}



使用

新建一个主界面窗口testwidget,用于创建主界面包含QWidget和DragResizeWgt共同存在的情况

其中widget_6为底部窗口,widget_5为顶部窗口

注意,我这里右边的窗口类中,我将widget_6和widget提升为了DragResizeWgt窗口类。

 testwidget窗口.ui文件

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>testwidget</class>
 <widget class="QWidget" name="testwidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>662</width>
    <height>549</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout_2">
   <property name="spacing">
    <number>0</number>
   </property>
   <property name="leftMargin">
    <number>0</number>
   </property>
   <property name="topMargin">
    <number>0</number>
   </property>
   <property name="rightMargin">
    <number>0</number>
   </property>
   <property name="bottomMargin">
    <number>0</number>
   </property>
   <item>
    <widget class="QWidget" name="widget_8" native="true">
     <layout class="QVBoxLayout" name="verticalLayout">
      <property name="spacing">
       <number>0</number>
      </property>
      <property name="leftMargin">
       <number>0</number>
      </property>
      <property name="topMargin">
       <number>0</number>
      </property>
      <property name="rightMargin">
       <number>0</number>
      </property>
      <property name="bottomMargin">
       <number>0</number>
      </property>
      <item>
       <widget class="QWidget" name="widget_5" native="true">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>50</height>
         </size>
        </property>
        <property name="maximumSize">
         <size>
          <width>16777215</width>
          <height>50</height>
         </size>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QWidget" name="widget_7" native="true">
        <property name="styleSheet">
         <string notr="true">background-color: rgb(170, 85, 255);</string>
        </property>
        <layout class="QHBoxLayout" name="horizontalLayout_2">
         <property name="spacing">
          <number>0</number>
         </property>
         <property name="leftMargin">
          <number>0</number>
         </property>
         <property name="topMargin">
          <number>0</number>
         </property>
         <property name="rightMargin">
          <number>0</number>
         </property>
         <property name="bottomMargin">
          <number>0</number>
         </property>
         <item>
          <widget class="DragResizeWgt" name="widget" native="true">
           <property name="styleSheet">
            <string notr="true"/>
           </property>
          </widget>
         </item>
         <item>
          <widget class="QWidget" name="widget_4" native="true">
           <property name="styleSheet">
            <string notr="true">background-color: rgb(0, 0, 127);</string>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
     </layout>
    </widget>
   </item>
   <item>
    <widget class="DragResizeWgt" name="widget_6" native="true">
     <property name="styleSheet">
      <string notr="true">background-color: rgb(255, 85, 127);</string>
     </property>
     <layout class="QHBoxLayout" name="horizontalLayout">
      <property name="spacing">
       <number>0</number>
      </property>
     </layout>
    </widget>
   </item>
  </layout>
 </widget>
 <customwidgets>
  <customwidget>
   <class>DragResizeWgt</class>
   <extends>QWidget</extends>
   <header>dragresizewgt.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

testwidget窗口.h文件

#ifndef TESTWIDGET_H
#define TESTWIDGET_H

#include <QWidget>
#include <QMouseEvent>
namespace Ui {
class testwidget;
}

class testwidget : public QWidget
{
    Q_OBJECT

public:
    explicit testwidget(QWidget *parent = nullptr);
    ~testwidget();

public:
    void resizeEvent(QResizeEvent *event);
private:
    Ui::testwidget *ui;
};

#endif // TESTWIDGET_H

testwidget窗口.cpp文件

#include "testwidget.h"
#include "qdebug.h"
#include "ui_testwidget.h"
#include "dragresizewgt.h"
#include <QPushButton>
testwidget::testwidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::testwidget)
{
    ui->setupUi(this);
    // DragResizeWgt *w = new DragResizeWgt(this);
    // w->resize(400,400);
    // w->setStyleSheet("background-color: rgb(255, 255, 0);");
    // w->show();
    // this->setMaximumSize(1920,1080);
    this->setMouseTracking(true);
    this->setMinimumSize(480,270);

    ui->widget->setEdgeBeReSized(false,false,true,false);
    // ui->widget->setWgtMaxmumSize(300,800);
    ui->widget->setMinimumSize(100,0);
    // ui->widget_4->setEdgeBeReSized(false,false,false,true);
    ui->widget_6->setEdgeBeReSized(true,false,false,false);
    ui->widget_6->setMinimumSize(0,100);
    // ui->widget_6->setWgtMaxmumSize(1000,800);
    // ui->widget->setStyleSheet("background-color: rgb(20, 20, 255);");
    QWidget *childWidget3 = new QWidget;
    childWidget3->setMouseTracking(true);
    childWidget3->setStyleSheet("background-color: rgb(255, 12, 128);");
    childWidget3->setMouseTracking(true);
    ui->widget->layout()->addWidget(childWidget3);
    ui->widget->layout()->setContentsMargins(0,0,0,0);
    ui->widget->layout()->setSpacing(0);
    connect(ui->widget, &DragResizeWgt::sizeChange, [=](){
        qDebug() << "this->width()" << this->width() << "ui->widget->width()"<< ui->widget->width();
        int remainingWidth = this->width() -  ui->widget->width();
        ui->widget_4->setFixedWidth(remainingWidth);
    });
    connect(ui->widget_6, &DragResizeWgt::sizeChange, [=](){
        qDebug() << "this->width()" << this->height() << "ui->widget->height()"<< ui->widget_6->height();
        int remainingHeight= this->height() -  ui->widget_6->height();
        ui->widget_8->setFixedHeight(remainingHeight);
        ui->widget_4->setFixedHeight(remainingHeight);
    });
    QWidget *childWidget1 = new QWidget;
    QVBoxLayout *layout = new QVBoxLayout(this);
    QPushButton *label = new QPushButton("Resizable and Draggable Widget", childWidget1);
    layout->addWidget(label);
    childWidget1->setLayout(layout);
    connect(label,  &QPushButton::clicked, [](){
        qDebug() << "pushbutton clicked";
    });
    childWidget1->setMouseTracking(true);
    childWidget1->setStyleSheet("background-color: rgb(85, 85, 255);");
    QWidget *childWidget2 = new QWidget;
    childWidget2->setMouseTracking(true);
    childWidget2->setStyleSheet("background-color: rgb(85, 20, 255);");
    ui->widget_6->layout()->addWidget(childWidget1);
    ui->widget_6->layout()->addWidget(childWidget2);
    ui->widget_6->layout()->setContentsMargins(0,0,0,0);
    ui->widget_6->layout()->setSpacing(0);


    ui->widget->setIsRepositioning(true);
}

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

// void testwidget::mousePressEvent(QMouseEvent *event)
// {

// }

// void testwidget::mouseReleaseEvent(QMouseEvent *event)
// {

// }

void testwidget::resizeEvent(QResizeEvent *event)
{
    qDebug() << "resizeEvent";
    ui->widget_6->setMaximumSize(this->width(),this->height()*0.7);
    ui->widget_8->setMinimumWidth(0);
    ui->widget_8->setMaximumWidth(this->width());
    ui->widget_8->setMinimumHeight(0);
    ui->widget_8->setMaximumHeight(this->height() - ui->widget_6->height());
    ui->widget_4->setMaximumWidth(this->width()*0.9);
    ui->widget->setMaximumSize(this->width()*0.9,this->height() - ui->widget_5->height());
}

最后在main函数中show()

    testwidget w;
    w.show();

参考

源于对这篇文章的参考,调试与修改

https://blog.csdn.net/weixin_40425059/article/details/116495403

如有什么别的问题可以留言,谢谢。


http://www.niftyadmin.cn/n/5536030.html

相关文章

UE4_材质_水体的反射与折射制作_Ben教程

在这个教程中&#xff0c;将制作水的反射和折射&#xff0c;上个教程&#xff0c;我们主要讲了制作水涟漪&#xff08;水面波纹&#xff09;和水滴法线混合&#xff0c;水深计算&#xff0c;我们首先要谈的是反射和产生折射的问题。我们将所有从干扰从场景中分离出去&#xff0…

11 - matlab m_map地学绘图工具基础函数 - 绘制航迹、椭圆、风向玫瑰图和特定的圆形区域的有关函数及其用法

11 - matlab m_map地学绘图工具基础函数 - 绘制航迹、椭圆、风向玫瑰图和特定的圆形区域的有关函数及其用法 0. 引言1. 关于m_track2. 关于m_range_ring3. 关于m_ellipse4. 关于m_windrose5. 结语 0. 引言 本篇介绍下m_map中绘制航迹图函数&#xff08;m_track&#xff09;、绘…

【HDFS】关于Hadoop的IPC.Client类的一些整理

org.apache.hadoop.ipc.Client 类是IPC服务的一个客户端。 IPC请求把一个Writable对象当做参数,返回一个Writable对象当做结果value。 一个IPC服务运行在某个端口上,并且由参数class和value class定义。 Router里的IPC.Client对象就两个 有这样一个类:ClientCache 看名字就…

GNU/Linux - wic文件的使用

Yocto/OpenEmbedded使用的磁盘镜像格式是 wic。为嵌入式系统提供 bootable images。 The disk image format used in the Yocto Project is wic. .wic 文件显然只是一个带有分区表和分区的磁盘镜像&#xff0c;就像下载 Linux 发行版时获得的所有 .img 文件一样。这就是为什么你…

使用Spring Boot实现博客管理系统

文章目录 引言第一章 Spring Boot概述1.1 什么是Spring Boot1.2 Spring Boot的主要特性 第二章 项目初始化第三章 用户管理模块3.1 创建用户实体类3.2 创建用户Repository接口3.3 实现用户Service类3.4 创建用户Controller类 第四章 博客文章管理模块4.1 创建博客文章实体类4.2…

航空数据管控系统-②项目分析与设计:任务1:需求分析-项目场景引入

任务描述 知识点&#xff1a;需求分析 重 点&#xff1a;原型设计工具&#xff0c;用例图&#xff0c;流程图绘制工具 难 点&#xff1a;功能点的梳理 内 容&#xff1a;完成本次实训项目的需求分析 先共同讨论处本项目的主要功能模块&#xff0c;并确定每个模块的负责…

7 动态规划

下面的例子不错&#xff1a; 对于动态规划&#xff0c;能学到不少东西&#xff1b; 你要清楚每一步都在做什么&#xff0c;划分细致就能够拆解清楚&#xff01; xk. - 力扣&#xff08;LeetCode&#xff09; labuladong的算法笔记-动态规划-CSDN博客 动态规划是一种强大的算法…

WRF学习——使用CMIP6数据驱动WRF/基于ncl与vdo的CMIP6数据处理

动力降尺度 国际耦合模式比较计划&#xff08;CMIP&#xff09;为研究不同情景下的气候变化提供了大量的模拟数据&#xff0c;而在实际研究中&#xff0c;全球气候模式输出的数据空间分辨率往往较低&#xff08;>100Km&#xff0c;缺乏区域气候特征&#xff0c;为了更好地研…