QT 自定义可拖动缩放的无边框窗口,可用于mainmindow, widget

news2024/9/25 2:23:31

1. 用于拖动,缩放的工具类

“WindowControl.h”

#ifndef WINDOWCONTROL_H
#define WINDOWCONTROL_H

#include <QObject>
#include <QRubberBand>
#include <QStyleOptionFocusRect>
#include <QStylePainter>

class RubberBand;
class CursorPosCalculator;

/**
 * 窗口控制类
 * 存储界面对应的数据集合,及是否可移动、可缩放属性
 * 进行缩放等相关操作
 */
class WindowControl : public QObject {
    Q_OBJECT

  public:
    explicit WindowControl(QObject *parent = nullptr);
    ~WindowControl();
    void activeWindow(QWidget *window);         // 激活窗体
    void removeWindow(QWidget *window);         // 移除窗口
    void setWindowMove(bool moveAble);          // 窗体移动
    void setWindowResize(bool resizeAble);      // 窗体缩放
    void setRubberBandOnMove(bool movable);     // 设置橡皮筋移动
    void setRubberBandOnResize(bool resizable); // 设置橡皮筋缩放

    void handleWidgetEvent(QEvent *event); // 处理鼠标划过、按下、按下、释放、移动事件
    void updateRubberBandStatus();         // 更新橡皮筋状态

  protected:
    virtual bool eventFilter(QObject *obj,
                             QEvent *event); // 事件过滤, 移动,缩放

  private:
    /** 状态 **/
    // QHash<QWidget*, WindowData*> windowDataHash;    // 缓存要控制的窗口
    bool windowMoveAble;           // 可以移动
    bool windowResizeAble;         // 可以缩放
    bool windowRubberBandOnResize; // 可以橡皮筋移动
    bool windowRubberBandOnMove;   // 可以橡皮筋缩放

    /** 窗口及其操作 **/
    RubberBand *m_pRubberBand; // 橡皮筋选择框
    QWidget *m_pWidget;        // 被控制的窗口
    QPoint m_ptDragPos;        // 拖动时坐标
    CursorPosCalculator *m_pressedMousePos;
    CursorPosCalculator *m_moveMousePos;
    bool m_bLeftButtonPressed;      // 鼠标左键是否按下
    bool m_bCursorShapeChanged;     // 鼠标形状是否改变
    bool m_bLeftButtonTitlePressed; // 标题区域是否按下鼠标
    Qt::WindowFlags m_windowFlags;

    void updateCursorShape(const QPoint &gMousePos);  // 更新鼠标样式
    void resizeWidget(const QPoint &gMousePos);       // 重置窗体大小
    void moveWidget(const QPoint &gMousePos);         // 移动窗体
    void handleMousePressEvent(QMouseEvent *event);   // 处理鼠标按下
    void handleMouseReleaseEvent(QMouseEvent *event); // 处理鼠标释放
    void handleMouseMoveEvent(QMouseEvent *event);    // 处理鼠标移动
    void handleLeaveEvent(QEvent *event);             // 处理鼠标离开
    void handleHoverMoveEvent(QHoverEvent *event);    // 处理鼠标进入
};

// ================================================================
/**
 * 窗口控制,
 */
class WindowData {};

// ==================================================================
/**
 * 自定义的橡皮筋选择框
 * @brief The RubberBand class
 */
class RubberBand : public QRubberBand {
  public:
    RubberBand(Shape s, QWidget *p = nullptr) : QRubberBand(s, p) {
        QPalette palette;
        palette.setBrush(QPalette::WindowText, QBrush(Qt::lightGray));
        setPalette(palette); // 调色板应用到当前的橡皮筋对象上
        repaint();
    }

  protected:
    virtual void paintEvent(QPaintEvent *) {
        QStylePainter painter(this);
        QStyleOptionFocusRect option;
        option.initFrom(this);

        QPen pen;
        pen.setStyle(Qt::DashLine);
        pen.setWidth(1);
        pen.setColor(QColor(Qt::red));
        painter.setPen(pen);
        painter.drawControl(QStyle::CE_FocusFrame, option);
    }
};

// ==================================================================
/**
 * 计算鼠标是否位于左、上、右、下、左上角、左下角、右上角、右下角
 */

class CursorPosCalculator {
  public:
    explicit CursorPosCalculator();
    void reset();
    void recalculate(const QPoint &globalMousePos, const QRect &frameRect);

  public:
    bool m_bOnEdges;
    bool m_bOnLeftEdge;
    bool m_bOnRightEdge;
    bool m_bOnTopEdge;
    bool m_bOnBottomEdge;
    bool m_bOnTopLeftEdge;
    bool m_bOnBottomLeftEdge;
    bool m_bOnTopRightEdge;
    bool m_bOnBottomRightEdge;

    static int m_nBorderWidth;
    static int m_nTitleHeight;
};

#endif // WINDOWCONTROL_H

WindowControl.cpp

#include "utils/WindowControl.h"
#include "qcoreevent.h"

#include <QMouseEvent>

/**
 * @brief WindowControl::WindowControl
 */
WindowControl::WindowControl(QObject *parent) : QObject(parent) {
    // 初始化状态
    windowMoveAble = true;
    windowResizeAble = true;
    windowRubberBandOnMove = false;
    windowRubberBandOnResize = false;

    m_pressedMousePos = new CursorPosCalculator;
    m_moveMousePos = new CursorPosCalculator;
}

WindowControl::~WindowControl() {
    m_pWidget->setMouseTracking(false);           // 禁用鼠标跟踪
    m_pWidget->setWindowFlags(m_windowFlags);     // 还原窗口标志
    m_pWidget->setAttribute(Qt::WA_Hover, false); // 禁用鼠标指针悬停事件

    delete m_pRubberBand;
    m_pRubberBand = NULL;
    delete m_pressedMousePos;
    m_pressedMousePos = NULL;
    delete m_moveMousePos;
    m_moveMousePos = NULL;
}

bool WindowControl::eventFilter(QObject *obj, QEvent *event) {
    switch (event->type()) {
    case QEvent::MouseMove:
    case QEvent::HoverMove:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::Leave: {
        if (obj == m_pWidget) {
            handleWidgetEvent(event);
            return true;
        }
    }
    default:
        return QObject::eventFilter(obj, event);
    }
}

void WindowControl::activeWindow(QWidget *window) {
    m_pWidget = window;
    window->installEventFilter(this); // 安装事件过滤器

    m_bLeftButtonPressed = false;
    m_bCursorShapeChanged = false;
    m_bLeftButtonTitlePressed = false;
    m_pRubberBand = NULL;

    m_windowFlags = m_pWidget->windowFlags();
    m_pWidget->setMouseTracking(true);           // 鼠标追踪
    m_pWidget->setAttribute(Qt::WA_Hover, true); // 启用鼠标指针悬停事件

    updateRubberBandStatus();
}

void WindowControl::removeWindow(QWidget *window) {
    if (m_pWidget) {
        delete this;
    }
}

void WindowControl::setWindowMove(bool moveAble) { windowMoveAble = moveAble; }

void WindowControl::setWindowResize(bool resizeAble) { windowResizeAble = resizeAble; }

void WindowControl::setRubberBandOnMove(bool movable) {
    windowRubberBandOnMove = movable;
    updateRubberBandStatus();
}

void WindowControl::setRubberBandOnResize(bool resizable) {
    windowRubberBandOnResize = resizable;
    updateRubberBandStatus();
}

void WindowControl::updateRubberBandStatus() {
    if (windowRubberBandOnResize || windowRubberBandOnMove) {
        if (NULL == m_pRubberBand) {
            m_pRubberBand = new RubberBand(QRubberBand::Rectangle);
        }
    } else {
        delete m_pRubberBand;
        m_pRubberBand = NULL;
    }
}

void WindowControl::handleWidgetEvent(QEvent *event) {
    switch (event->type()) {
    default:
        break;
    case QEvent::MouseButtonPress:
        handleMousePressEvent(static_cast<QMouseEvent *>(event));
        break;
    case QEvent::MouseButtonRelease:
        handleMouseReleaseEvent(static_cast<QMouseEvent *>(event));
        break;
    case QEvent::MouseMove:
        handleMouseMoveEvent(static_cast<QMouseEvent *>(event));
        break;
    case QEvent::Leave:
        handleLeaveEvent(event);
        break;
    case QEvent::HoverMove:
        handleHoverMoveEvent(static_cast<QHoverEvent *>(event));
        break;
    }
}

void WindowControl::updateCursorShape(const QPoint &gMousePos) {
    // 检查全屏或最大化状态
    if (m_pWidget->isFullScreen() || m_pWidget->isMaximized()) {
        if (m_bCursorShapeChanged) {
            m_pWidget->unsetCursor(); // 光标设置为默认
        }
        return;
    }

    m_moveMousePos->recalculate(gMousePos, m_pWidget->frameGeometry());

    if (m_moveMousePos->m_bOnTopLeftEdge || m_moveMousePos->m_bOnBottomRightEdge) {
        m_pWidget->setCursor(Qt::SizeFDiagCursor); // 对角线大小调整光标
        m_bCursorShapeChanged = true;
    } else if (m_moveMousePos->m_bOnTopRightEdge || m_moveMousePos->m_bOnBottomLeftEdge) {
        m_pWidget->setCursor(Qt::SizeBDiagCursor); // 反对角线大小调整光标
        m_bCursorShapeChanged = true;
    } else if (m_moveMousePos->m_bOnLeftEdge || m_moveMousePos->m_bOnRightEdge) {
        m_pWidget->setCursor(Qt::SizeHorCursor); // 水平调整大小光标
        m_bCursorShapeChanged = true;
    } else if (m_moveMousePos->m_bOnTopEdge || m_moveMousePos->m_bOnBottomEdge) {
        m_pWidget->setCursor(Qt::SizeVerCursor); // 垂直调整大小光标
        m_bCursorShapeChanged = true;
    } else {
        if (m_bCursorShapeChanged) {
            m_pWidget->unsetCursor(); // 恢复默认
            m_bCursorShapeChanged = false;
        }
    }
}

void WindowControl::resizeWidget(const QPoint &gMousePos) {
    QRect origRect;

    if (windowRubberBandOnResize)
        origRect = m_pRubberBand->frameGeometry();
    else
        origRect = m_pWidget->frameGeometry();

    int left = origRect.left();
    int top = origRect.top();
    int right = origRect.right();
    int bottom = origRect.bottom();
    origRect.getCoords(&left, &top, &right, &bottom);

    // int minWidth = m_pWidget->minimumWidth();
    // int minHeight = m_pWidget->minimumHeight();
    int minWidth = 40;
    int minHeight = 40;

    if (m_pressedMousePos->m_bOnTopLeftEdge) {
        left = gMousePos.x();
        top = gMousePos.y();
    } else if (m_pressedMousePos->m_bOnBottomLeftEdge) {
        left = gMousePos.x();
        bottom = gMousePos.y();
    } else if (m_pressedMousePos->m_bOnTopRightEdge) {
        right = gMousePos.x();
        top = gMousePos.y();
    } else if (m_pressedMousePos->m_bOnBottomRightEdge) {
        right = gMousePos.x();
        bottom = gMousePos.y();
    } else if (m_pressedMousePos->m_bOnLeftEdge) {
        left = gMousePos.x();
    } else if (m_pressedMousePos->m_bOnRightEdge) {
        right = gMousePos.x();
    } else if (m_pressedMousePos->m_bOnTopEdge) {
        top = gMousePos.y();
    } else if (m_pressedMousePos->m_bOnBottomEdge) {
        bottom = gMousePos.y();
    }

    QRect newRect(QPoint(left, top), QPoint(right, bottom));

    if (newRect.isValid()) {
        if (minWidth > newRect.width()) {
            if (left != origRect.left())
                newRect.setLeft(origRect.left());
            else
                newRect.setRight(origRect.right());
        }
        if (minHeight > newRect.height()) {
            if (top != origRect.top())
                newRect.setTop(origRect.top());
            else
                newRect.setBottom(origRect.bottom());
        }

        if (windowRubberBandOnResize) {
            m_pRubberBand->setGeometry(newRect);
        } else {
            m_pWidget->setGeometry(newRect);
        }
    }
}

void WindowControl::moveWidget(const QPoint &gMousePos) {
    if (windowRubberBandOnMove) {
        m_pRubberBand->move(gMousePos - m_ptDragPos);
    } else {
        m_pWidget->move(gMousePos - m_ptDragPos);
    }
}

void WindowControl::handleMousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        m_bLeftButtonPressed = true;

        m_bLeftButtonTitlePressed = event->pos().y() < 30;

        QRect frameRect = m_pWidget->frameGeometry();
        QRect moveRect(frameRect.x(), frameRect.y(), frameRect.width(), 30);
        m_pressedMousePos->recalculate(event->globalPos(), frameRect);

        m_ptDragPos = event->globalPos() - frameRect.topLeft();

        if (m_pressedMousePos->m_bOnEdges) {
            if (windowRubberBandOnResize) {
                m_pRubberBand->setGeometry(frameRect);
                m_pRubberBand->show();
            }
        } else if (windowRubberBandOnMove) {
            if (moveRect.contains(event->globalPos())) {
                m_pRubberBand->setGeometry(frameRect);
                m_pRubberBand->show();
            }
        }
    }
}

void WindowControl::handleMouseReleaseEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        m_bLeftButtonPressed = false;
        m_bLeftButtonTitlePressed = false;
        m_pressedMousePos->reset();
        if (m_pRubberBand && m_pRubberBand->isVisible()) {
            m_pRubberBand->hide();
            m_pWidget->setGeometry(m_pRubberBand->geometry());
        }
    }
}

void WindowControl::handleMouseMoveEvent(QMouseEvent *event) {
    if (m_bLeftButtonPressed) {
        if (windowResizeAble && m_pressedMousePos->m_bOnEdges) {
            resizeWidget(event->globalPos());
        } else if (windowMoveAble && m_bLeftButtonTitlePressed) {
            moveWidget(event->globalPos());
        }
    } else if (windowResizeAble) {
        updateCursorShape(event->globalPos());
    }
}

void WindowControl::handleLeaveEvent(QEvent *event) {
    Q_UNUSED(event)
    if (!m_bLeftButtonPressed) {
        m_pWidget->unsetCursor();
    }
}

void WindowControl::handleHoverMoveEvent(QHoverEvent *event) {
    if (windowResizeAble) {
        updateCursorShape(m_pWidget->mapToGlobal(event->pos())); // 局部坐标转全局屏幕坐标
    }
}

// CursorPosCalculator==========================================

int CursorPosCalculator::m_nBorderWidth = 5;
int CursorPosCalculator::m_nTitleHeight = 30;

CursorPosCalculator::CursorPosCalculator() { reset(); }

void CursorPosCalculator::reset() {
    m_bOnEdges = false;
    m_bOnLeftEdge = false;
    m_bOnRightEdge = false;
    m_bOnTopEdge = false;
    m_bOnBottomEdge = false;
    m_bOnTopLeftEdge = false;
    m_bOnBottomLeftEdge = false;
    m_bOnTopRightEdge = false;
    m_bOnBottomRightEdge = false;
}

void CursorPosCalculator::recalculate(const QPoint &gMousePos, const QRect &frameRect) {
    int globalMouseX = gMousePos.x();
    int globalMouseY = gMousePos.y();

    int frameX = frameRect.x();
    int frameY = frameRect.y();

    int frameWidth = frameRect.width();
    int frameHeight = frameRect.height();

    m_bOnLeftEdge = (globalMouseX >= frameX && globalMouseX <= frameX + m_nBorderWidth);

    m_bOnRightEdge = (globalMouseX >= frameX + frameWidth - m_nBorderWidth && globalMouseX <= frameX + frameWidth);

    m_bOnTopEdge = (globalMouseY >= frameY && globalMouseY <= frameY + m_nBorderWidth);

    m_bOnBottomEdge = (globalMouseY >= frameY + frameHeight - m_nBorderWidth && globalMouseY <= frameY + frameHeight);

    m_bOnTopLeftEdge = m_bOnTopEdge && m_bOnLeftEdge;
    m_bOnBottomLeftEdge = m_bOnBottomEdge && m_bOnLeftEdge;
    m_bOnTopRightEdge = m_bOnTopEdge && m_bOnRightEdge;
    m_bOnBottomRightEdge = m_bOnBottomEdge && m_bOnRightEdge;

    m_bOnEdges = m_bOnLeftEdge || m_bOnRightEdge || m_bOnTopEdge || m_bOnBottomEdge;
}

2. 使用示例

定义基类:

#ifndef WINDOW_H
#define WINDOW_H

#include <QMainWindow>

/**
 * 自定义无边框mainwindow
 */
class Window : public QMainWindow {
    Q_OBJECT

  public:
    Window(QWidget *parent = nullptr);
    ~Window();

  private:
    void framelesshelperInit();
};

#endif // WINDOW_H

#include "component/window.h"
#include "utils/WindowControl.h"

Window::Window(QWidget *parent) : QMainWindow(parent) {
    resize(1200, 740);
    setWindowFlags(Qt::FramelessWindowHint);

    framelesshelperInit();
}

Window::~Window() {}

void Window::framelesshelperInit() {
    // this指的是要处理的窗体
    WindowControl *control = new WindowControl(this);
    control->activeWindow(this);          //激活当前窗体
    control->setWindowMove(true);         //设置窗体可移动
    control->setWindowResize(true);       //设置窗体可缩放
    control->setRubberBandOnMove(true);   //设置橡皮筋效果-可移动
    control->setRubberBandOnResize(true); //设置橡皮筋效果-可缩放
}

继承可拖动缩放的窗口:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "component/window.h"

#include <QMainWindow>

class MainWindow : public Window {
    Q_OBJECT

  public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
};
#endif // MAINWINDOW_H

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

MainWindow::MainWindow(QWidget *parent) : Window(parent) {
    resize(1200, 740);
    setWindowFlags(Qt::FramelessWindowHint);

    // 创建自定义标题栏
    QLabel *customTitleBar = new QLabel("自定义标题栏", this);
    customTitleBar->setStyleSheet("background-color: blue; color: white;");

    // 设置自定义标题栏
    setMenuWidget(customTitleBar);

  
}

MainWindow::~MainWindow() {}

使用:

#include "mainwindow.h"

#include "component/window.h"

#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

控制类引用自: https://blog.csdn.net/u012959478/article/details/140658545

上述测试工程代码: https://download.csdn.net/download/qq_51355375/89783077

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2162138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Elasticsearch、ik分词器、elasticsearch-head、Kibana的认识与安装

文章目录 elasticsearch安装elasticsearchIK中文分词器elasticsearch-headkibana elasticsearch Elasticsearch是一个基于Lucene的搜索服务器&#xff0c;也是属于NoSQL阵营的数据库。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口提供给我们操…

2025年SEO策略:如何优化您的知识库?

如今很多人在遇到问题时都会求助于谷歌。谷歌已经成为提供解决方案不可或缺的工具。作为全球搜索引擎的巨头&#xff0c;拥有大量用户流量。这就是为什么确保您的产品和服务在谷歌搜索结果中排名靠前是至关重要的&#xff0c;如果您想获得更多的客户&#xff0c;SEO是一个非常关…

打造你的专属主题-VitePress保姆级教程

本篇为vitepress系列教程&#xff0c;在开始前&#xff0c;若还不了解vitepress的小伙伴可以看一下以往文章&#xff1a; 不敲一行代码&#xff01;助你快速搭建属于自己的官网博客&#xff01;-VitePress保姆级教程 文章目录 VitePress主题配置准备自定义主题配置标题配置图标…

如何用AI实现自动更新文章?(全自动更新网站)

AI的诞生确实给我们的生活和工作都带来了很大的改变&#xff0c;从我自身来讲&#xff0c;也渐渐习惯了遇到事情先问问AI&#xff0c;不管是翻译、专业性问题、PPT制作、总结写作这些&#xff0c;确实帮我迅速理清了思路&#xff0c;也可以有很多内容的借鉴。 作为一个业余爱好…

滑动窗口算法第一弹(长度最小的子数组,无重复字符的最长子串 最大连续1的个数III)

目录 前言 1. 长度最小的子数组 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;暴力解法 &#xff08;3&#xff09;优化 2. 无重复字符的最长子串 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;暴力解法 &#xff08;3&#xff…

深度学习:卷积神经网络CNN

目录 一、什么是卷积&#xff1f; 二、卷积神经网络的组成 1. 卷积层 2. 池化层 3. 激活函数 4. 全连接层 三、卷积神经网络的构造 四、代码实现 1.数据预处理 2.创建卷积神经网络 3.创建训练集和测试集函数 4.创建损失函数和优化器并进行训练 一、什么是卷积&…

Kivy,一个上天入地的 Python 库

大家好&#xff01;我是炒青椒不放辣&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…

USB 电缆中的信号线 DP、DM 的缩写由来

经常在一些芯片的规格书中看到 USB 的信号对是以 DP 和 DM 命名&#xff1a; 我在想&#xff0c;这些规格书是不是写错了&#xff0c;把 N 写成 M 了&#xff1f;DM 中的 M 到底是什么的缩写&#xff1f; 于是我找了一些资料&#xff0c;终于在《Universal Serial Bus Cables …

string 的介绍及使用

一.string类介绍 C语言中&#xff0c;字符串是以’\0’结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需要用户自己管理&a…

BUUCTF [SCTF2019]电单车详解两种方法(python实现绝对原创)

使用audacity打开&#xff0c;发现是一段PT2242 信号 PT2242信号 有长有短&#xff0c;短的为0&#xff0c;长的为1化出来 这应该是截获电动车钥匙发射出的锁车信号 0 01110100101010100110 0010 0前四位为同步码0 。。。中间这20位为01110100101010100110为地址码0010为功…

ssm病人跟踪治疗信息管理系统

专业团队&#xff0c;咨询就送开题报告&#xff0c;欢迎大家咨询留言 摘 要 病人跟踪治疗信息管理系统采用B/S模式&#xff0c;促进了病人跟踪治疗信息管理系统的安全、快捷、高效的发展。传统的管理模式还处于手工处理阶段&#xff0c;管理效率极低&#xff0c;随着病人的不断…

《SG-Former: Self-guided Transformer with Evolving Token Reallocation》ICCV2023

摘要 SG-Former&#xff08;Self-guided Transformer&#xff09;是一种新型的视觉Transformer模型&#xff0c;旨在解决传统Transformer在处理大型特征图时面临的计算成本高的问题。该模型通过一种自适应细粒度的全局自注意力机制&#xff0c;实现了有效的计算成本降低。它利…

VmWare安装虚拟机教程(centos7)

VMWare下载&#xff1a; 下载 VMware Workstation Pro - VMware Customer Connect 安装包&#xff1a;&#xff08;16的版本&#xff09;免费&#xff01;&#xff08;一个赞就行&#xff09; 一直点下一步即可&#xff0c;注意修改一下安装位置就好 二、安装虚拟机 安装虚…

鸭脖变“刺客”,啃不起了

撰文&#xff5c;ANGELICA 编辑&#xff5c;ANGELICA 审核&#xff5c;烨 Lydia 声明&#xff5c;图片来源网络。日晞研究所原创文章&#xff0c;如需转载请留言申请开白。 你有多久没吃卤味了&#xff1f; 2020年之后&#xff0c;人们对于几大卤味巨头的关注度正在下降。 …

视频字幕生成:分享6款专业易操作的工具,让创作更简单!

​视频字幕如何添加&#xff1f;日常剪辑Vlog视频时&#xff0c;就需要给视频添加上字幕了。字幕是一个比较重要的元素&#xff0c;它不仅可以帮助听力受损或语言障碍的人士理解内容&#xff0c;还可以让你的视频更加易于理解和吸引观众。 那么如何实现视频字幕生成&#xff0c…

【LLaMa2入门】从零开始训练LLaMa2

目录 1 背景2 搭建环境2.1 硬件配置2.2 搭建虚拟环境2.2.1 创建虚拟环境2.2.2 安装所需的库 3 准备工作3.1 下载GitHub代码3.2 下载模型3.3 数据处理3.3.1 下载数据3.3.2 数据集tokenize预处理 4 训练4.1 修改配置4.2 开始训练4.3 多机多卡训练 5 模型推理5.1 编译5.1.1 安装gc…

ResNet18模型扑克牌图片预测

加入会员社群&#xff0c;免费获取本项目数据集和代码&#xff1a;点击进入>> 1. 项目简介 该项目旨在通过深度学习技术&#xff0c;使用ResNet18模型对扑克牌图像进行预测与分类。扑克牌图片分类任务属于图像识别中的一个应用场景&#xff0c;要求模型能够准确识别扑克…

【python篇】python pickle模块一篇就能明白,快速理解

持久性就是指保持对象&#xff0c;甚至在多次执行同一程序之间也保持对象。通过本文&#xff0c;您会对 Python对象的各种持久性机制&#xff08;从关系数据库到 Python 的 pickle以及其它机制&#xff09;有一个总体认识。另外&#xff0c;还会让您更深一步地了解Python 的对象…

音视频入门基础:FLV专题(5)——FFmpeg源码中,判断某文件是否为FLV文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.flv 可以判断出某个文件是否为FLV文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为FLV文件呢&#xff1f;它内部其实是通过flv_probe函数来判断的。从《FFmpeg源码&#xff1a;av_probe_input_format3函数和AVI…

Serilog文档翻译系列(五) - 编写日志事件

日志事件通过 Log 静态类或 ILogger 接口上的方法写入接收器。下面的示例将使用 Log 以便语法简洁&#xff0c;但下面显示的方法同样可用于接口。 Log.Warning("Disk quota {Quota} MB exceeded by {User}", quota, user); 通过此日志方法创建的警告事件将具有两个相…