QT c++和qml交互实例

文章目录

      • 一、demo效果图
      • 二、c++和qml交互的基本方式
        • 1、qml访问C++类对象
      • 三、关键代码
        • 1、工程结构图
        • 2、c++代码
          • MainWindow.cpp
          • MainQuickView.cpp
          • StudentInfoView.cpp
          • StudentInfoModel.cpp
        • 3、qml代码
          • main.qml
          • MainQuickTopRect.qml
          • MainQuickMiddleRect.qml
          • MainQuickMiddleTableRect.qml

一、demo效果图

该实例,主要是在已有的QWidget工程中,加入qml工程,方便qml项目的开发与维护,让qml开发者更好的上手qml。

(1)展示了c++和qml常见的交互方式。
(2)qwidget工程如何加载qml工程,如何加载自己实现的qml tool库。
(3)创建无边框qml界面,支持拖拽,窗口的缩小与展开,界面的分段实现。
(4)展示一个简单的堆栈窗口(SwipeView),相当于QStackedWidget,管理多个子窗口页面。
(5)实现一个简单的列表框(ListView),相当于QListWidget,定时请求网络数据,展示学生信息,将view和model进行分离,降低界面与数据的耦合。
(6)点击学号、年龄,实现了列表数据的排序。

在这里插入图片描述

二、c++和qml交互的基本方式

交互有很多种方式,有的比较繁杂,不易理解,此处只使用了最方便使用的方法,满足基本的交互。

1、qml访问C++类对象

需要先将C++类(MyWindow)注册到QQuickView中。和qml相关的C++类,最好都进行注册。

class MainQuickView : public QQuickView
{
    Q_OBJECT
public:
    MainQuickView(QQuickView *parent = nullptr);
    ~MainQuickView() override;
    void initialzeUI();
protected:
};

void MainQuickView ::initialzeUI()
{
    // 注册,为了qml中可以直接访问C++对象
    MyWindow *w = new MyWindow();
    this->rootContext()->setContextProperty("myWindow", w);
	...
}

这样C++的信号public槽函数Q_INVOKABLE 修饰的类成员函数

class MyWindow : public QWidget
{
      Q_OBJECT
  public:
      MyWindow();
      // Q_INVOKABLE可以将C++函数暴漏给qml引擎,注册到元对象系统
      Q_INVOKABLE void invokableMethod();
  signals:
      void dataChanged();
  public slots:
  	  void refresh();
};

就可以在qml中调用

// main.qml
Rectangle {
    id: root
    width: 1200
    height: 800
    onClicked: {
        myWindow.showNormal(); // showNormal是QWidget父类的槽函数
    }
}

三、关键代码

1、工程结构图

在这里插入图片描述

2、c++代码
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MainWindow)
    , m_pQuickVew(nullptr)
{
    ui->setupUi(this);
}

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

void MainWindow::on_pushButton_clicked()
{
    if (!m_pQuickVew)
    {
    	// 加载qml包含两种方式,一种是QQuickView,一种是QQmlApplicationEngine
    	// 当前使用第一种方式,MainQuickView继承自QQuickView
        m_pQuickVew = new MainQuickView();
        m_pQuickVew->setObjectName("quickView");
    }

    m_pQuickVew->show();
}
MainQuickView.cpp
static const char* s_mainPath = "qrc:/qml/main.qml";

MainQuickView::MainQuickView(QQuickView *parent)
    : QQuickView(parent)
    , m_bMin(false)
{
    this->setFlags(Qt::Window | Qt::FramelessWindowHint);
    this->setTitle(QString::fromLocal8Bit("图书馆"));
    initialize();
    setMoveable();
    setTitleData();
}

MainQuickView::~MainQuickView()
{
}

void MainQuickView::initialize()
{
    // 初始化view 和 model,降低耦合,提高可维护性
    if (!m_pStudentInfoView)
        m_pStudentInfoView = new StudentInfoView();

    if (!m_pStudentInfoModel)
        m_pStudentInfoModel = m_pStudentInfoView->getStudentInfoMode();

    // ...其他功能

    initialzeUI();
}

void MainQuickView::initialzeUI()
{
    // 注册,qml中可以直接访问C++对象
    this->rootContext()->setContextProperty("mainQuickView", this);
	// qml可以通过"studentInfoView",去使用其实现的函数
    this->rootContext()->setContextProperty("studentInfoView", m_pStudentInfoView);
    this->rootContext()->setContextProperty("studentInfoModel", m_pStudentInfoModel);

    // qml根对象大小随窗口大小改变而改变
    this->setResizeMode(QQuickView::SizeRootObjectToView);
    // 导入自定义模块工具
    this->engine()->addImportPath(":/qmlTools");
    // 设置准备加载得qml文件,相当于c++的main函数入口
    this->setSource(QUrl(s_mainPath));
}

void MainQuickView::minMaxQmlWindow()
{
    m_bMin = !m_bMin;
    emit minQmlWindow(m_bMin);
}

void MainQuickView::onSendTopRectPos(QVariant pX, QVariant pY)
{
    this->setX(this->x() + pX.toInt());
    this->setY(this->y() + pY.toInt());
}

void MainQuickView::onCloseQuickView()
{
    close();
}

void MainQuickView::onShowMinimized()
{
    showMinimized();
}

void MainQuickView::setMoveable()
{
	// 当移动qml窗口时,将移动坐标告诉C++
    // 找到对象名叫topRect的qml,C++绑定qml的信号
    QQuickItem* topRect = this->rootObject()->findChild<QQuickItem*>("topRect");
    if (topRect) {
        connect(topRect, SIGNAL(sendTopRectPos(QVariant, QVariant)),
                this, SLOT(onSendTopRectPos(QVariant, QVariant)));
    }
}

void MainQuickView::setTitleData()
{
    // 找到对象名叫topRect的qml,C++向qml发送消息,触发qml中实现的setTitleText函数
    QQuickItem* topRect = this->rootObject()->findChild<QQuickItem*>("topRect");
    QMetaObject::invokeMethod(topRect, "setTitleText", Q_ARG(QVariant, QString::fromLocal8Bit("Qml窗口标题")));
}
StudentInfoView.cpp
StudentInfoView::StudentInfoView(QObject *parent)
    : QObject(parent)
    , m_sortType(StudentInfoSort::sortNone)
{
    if (!m_pStudentInfoModel)
        m_pStudentInfoModel = new StudentInfoModel(this);
	
	// 如果数据来自网络,就需要定时请求接口,并更新界面
    m_timer = new QTimer(this);
    m_timer->setInterval(10 * 1000);
    QObject::connect(m_timer, &QTimer::timeout, this, &StudentInfoView::onUpdateInfoData);

    onUpdateInfoData();
    m_timer->start();
}

StudentInfoModel *StudentInfoView::getStudentInfoMode()
{
    return m_pStudentInfoModel;
}

// qSort()比较函数不能定义为类成员函数(参数包含隐藏的this指针),会导致参数不符
// 可以定义为static类成员函数、static函数、普通函数
bool StudentInfoView::idAscend(const StudentInfoItem &stu1, const StudentInfoItem &stu2)
{
    return stu1.stuId < stu2.stuId; //学号升序
}

// 普通函数
bool idDescend(const StudentInfoItem &stu1, const StudentInfoItem &stu2)
{
    return stu1.stuId > stu2.stuId; //学号降序
}

bool ageAscend(const StudentInfoItem &stu1, const StudentInfoItem &stu2)
{
    return stu1.age < stu2.age; //年龄升序
}

void StudentInfoView::setSort(StudentInfoSort sortType)
{
    m_sortType = sortType;
    if (m_sortType == StudentInfoSort::sortIdAscend)
    {
        qSort(m_allDatas.begin(), m_allDatas.end(), idAscend);
    }
    else if (m_sortType == StudentInfoSort::sortIdDescend)
    {
        qSort(m_allDatas.begin(), m_allDatas.end(), idDescend);
    }
    else if (m_sortType == StudentInfoSort::sortAgeAscend)
    {
    	// 比较函数也可以写为lambda表达式
        qSort(m_allDatas.begin(), m_allDatas.end(),
              [](const StudentInfoItem& stu1, const StudentInfoItem& stu2)
        {
            return stu1.age < stu2.age;
        });
    }
}

void StudentInfoView::updateSort(int sortType)
{
	// qml调用,执行哪一种排序方式,并刷新数据
    setSort((StudentInfoSort)sortType);

    if (m_pStudentInfoModel)
        m_pStudentInfoModel->clear();

    for (auto studentInfo : m_allDatas) {
        if (m_pStudentInfoModel) {
            m_pStudentInfoModel->AddModel(studentInfo);
        }
    }
}

void StudentInfoView::onUpdateInfoData()
{
    // 每隔十秒请求网络接口,根据返回的数据刷新model,该实例模拟网络数据
    m_allDatas.clear();
    if (m_pStudentInfoModel)
        m_pStudentInfoModel->clear();

    QVector<StudentInfoItem> studentInfos;

    StudentInfoItem item1;
    item1.stuId = 9704;
    item1.stuName = QString::fromLocal8Bit("百里");
    item1.sex = 1;
    item1.age = 14;

    StudentInfoItem item2;
    item2.stuId = 9207;
    item2.stuName = QString::fromLocal8Bit("黄忠");
    item2.sex = 1;
    item2.age = 26;

    StudentInfoItem item3;
    item3.stuId = 9206;
    item3.stuName = QString::fromLocal8Bit("鲁班");
    item3.sex = 1;
    item3.age = 17;

    StudentInfoItem item4;
    item4.stuId = 9787;
    item4.stuName = QString::fromLocal8Bit("女娲");
    item4.sex = 0;
    item4.age = 33;

    studentInfos << item1 << item2 << item3 << item4;

    m_allDatas = studentInfos;
    setSort(m_sortType); //每一次网络数据刷新后,执行保存的排序方式

    for (auto studentInfo : m_allDatas) {
        if (m_pStudentInfoModel) {
            m_pStudentInfoModel->AddModel(studentInfo);
        }
    }
}
StudentInfoModel.cpp
#include "StudentInfoModel.h"

StudentInfoModel::StudentInfoModel(QObject *parent)
    : QAbstractListModel(parent)
{
    roleNames();
}

StudentInfoModel::~StudentInfoModel()
{

}

void StudentInfoModel::clear()
{
    if (m_allDatas.size() <= 0)
        return;

    beginRemoveRows(QModelIndex(), 0, m_allDatas.size() - 1);
    m_allDatas.clear();
    endRemoveRows();
}

void StudentInfoModel::mremove(int index)
{
    beginRemoveRows(QModelIndex(), index, index);
    m_allDatas.erase(m_allDatas.begin() + index);
    endRemoveRows();
}

void StudentInfoModel::update(int index, const StudentInfoItem &infoModel)
{
    if (index < 0 || m_allDatas.size() < index)
        return;

    StudentInfoItem &srcModel = m_allDatas[index];
    srcModel = infoModel;
}

void StudentInfoModel::AddModel(const StudentInfoItem &md)
{
    beginInsertRows(QModelIndex(), rowCount(), rowCount());
    m_allDatas.push_back(md);
    endInsertRows();
}

QVariant StudentInfoModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() >= m_allDatas.size()) {
        return QVariant();
    }

    const StudentInfoItem &itemInfo = m_allDatas.at(index.row());

    StudentInfoRoles infoRole = static_cast<StudentInfoRoles>(role);

    switch (infoRole) {
    case StudentInfoRoles::stuIdRole :
        return itemInfo.stuId;
        break;

    case StudentInfoRoles::stuNameRole :
        return itemInfo.stuName;
        break;

    case StudentInfoRoles::stuSexRole :
        return itemInfo.sex;
        break;

    case StudentInfoRoles::stuAgeRole :
        return itemInfo.age;
        break;

    default:
        return QVariant();
        break;
    }
}

int StudentInfoModel::rowCount(const QModelIndex &parent) const
{
    return m_allDatas.size();
}

QHash<int, QByteArray> StudentInfoModel::roleNames() const
{
    // 映射C++端的枚举与QML端的字符串
    QHash<int, QByteArray> data;

    data[int(StudentInfoRoles::stuIdRole)]   = "stuId";
    data[int(StudentInfoRoles::stuNameRole)] = "stuName";
    data[int(StudentInfoRoles::stuSexRole)]  = "sex";
    data[int(StudentInfoRoles::stuAgeRole)]  = "age";
    return data;
}
3、qml代码
main.qml
import QtQuick 2.0
import QtQuick.Layouts 1.0

Item {
    id: root
    width: 1200
    height: 800

    Rectangle {
        anchors.fill: parent
        color: "red"
        ColumnLayout {
            spacing: 0
            MainQuickTopRect {
                id: topRect
                objectName: "topRect"
                width: root.width
                height: 50
            }

            MainQuickMiddleRect {
                id: middleRect
                objectName: "middleRect"
                width: root.width
                height: root.height - topRect.height
            }
        }
    }
}
MainQuickTopRect.qml
import QtQuick 2.12
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.12
import "../qmlTools/ButtonTools"

Rectangle {
    id: root
    color: "#181D33"

    signal sendTopRectPos(var x, var y)

    function setTitleText(text) {
        titleText.text = text
    }

    function onMinQmlWindow(bMin){
        if (bMin)
            narrowBtn.clicked() // narrowBtn是最小化按钮,当然也可以直接mainQuickView.onShowMinimized()
        else
            mainQuickView.showNormal()
    }

    Component.onCompleted: {
        mainQuickView.minQmlWindow.connect(onMinQmlWindow)
    }

    RowLayout {
        id: rowLayout
        anchors.fill: root
        anchors.leftMargin: 16
        anchors.rightMargin: 16
        Text {
            id: titleText
            anchors.fill: root
            anchors.left: rowLayout.left
            verticalAlignment: Text.AlignVCenter
            horizontalAlignment: Text.AlignHCenter
            color: "white"
            font.pixelSize: 18
            font.family: "Microsoft YaHei UI"
            font.bold: true
            text: ""

            // 设置文本框背景颜色
            Rectangle {
                id: titleTextBack
                anchors.fill: titleText
                color: "#000000"
                z: -1
            }
        }

        // 最小化
        ImageBtn {
            id: narrowBtn
            width: 24
            height: 24
            anchors.right: closeBtn.left

            normalUrl: "qrc:/resource/minNormal.png"
            hoveredUrl: "qrc:/resource/minHover.png"
            pressedUrl: "qrc:/resource/minHover.png"

            onClicked: {
                mainQuickView.onShowMinimized();
                console.log("min");
            }
        }

        // 关闭
        ImageBtn {
            id: closeBtn
            width: 24
            height: 24
            anchors.right: rowLayout.right

            normalUrl: "qrc:/resource/closeNormal.png"
            hoveredUrl: "qrc:/resource/closeHover.png"
            pressedUrl: "qrc:/resource/closeHover.png"

            onClicked: {
                mainQuickView.onCloseQuickView();
            }
        }
    }

    MouseArea {
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton
        propagateComposedEvents: true  //传递鼠标事件
        property point clickPos: "0, 0"

        onPressed: {
            clickPos = Qt.point(mouse.x, mouse.y)
            console.log("onPressed " + clickPos);
        }

        onPositionChanged: {
            var delta = Qt.point(mouse.x - clickPos.x, mouse.y - clickPos.y)
            sendTopRectPos(delta.x, delta.y)
        }
    }
}
MainQuickMiddleRect.qml
import QtQuick 2.0
import QtQuick 2.12
import QtQuick.Controls 1.2
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.2
import "../qmlTools/ButtonTools"

Rectangle {
    id: root
    color: "#2E3449"
    property int oneCount: 50
    property int twoCount: 50
    property int threeCount: 50
    readonly property int pageWidth  : 400

    Rectangle {
        id: titleSwitchBtn
        width: parent.width / 2
        anchors.top: parent.top
        anchors.topMargin: 30
        anchors.left: parent.left
        anchors.leftMargin: width - width / 2
        height: 46
        color: "#2C5CA5"

        RowLayout {
            spacing: 20
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 0
            anchors.left: parent.left
            anchors.leftMargin: 40

            DownLineBtn { // qmlTool中自定义实现的下划线按钮
                id: cover_one_btn
                btn_width: 100
                btn_string: qsTr("一班") + oneCount + qsTr("人")
                onMyClicked: {
                    coverBtnStat(cover_one_btn, true)
                    coverBtnStat(cover_two_btn, false)
                    coverBtnStat(cover_three_btn, false)
                    swipeView.currentIndex = 0
                }
            }

            DownLineBtn {
                id: cover_two_btn
                btn_width: 100
                btn_string: qsTr("二班") + twoCount + qsTr("人")
                onMyClicked: {
                    coverBtnStat(cover_one_btn, false)
                    coverBtnStat(cover_two_btn, true)
                    coverBtnStat(cover_three_btn, false)
                    swipeView.currentIndex = 1
                }
            }

            DownLineBtn {
                id: cover_three_btn
                btn_width: 100
                btn_string: qsTr("三班") + threeCount + qsTr("人")
                onMyClicked: {
                    coverBtnStat(cover_one_btn, false)
                    coverBtnStat(cover_two_btn, false)
                    coverBtnStat(cover_three_btn, true)
                    swipeView.currentIndex = 2
                }
            }
        }
    }

    Rectangle {
        id: view
        anchors.top: titleSwitchBtn.bottom
        anchors.topMargin: 4
        anchors.left: titleSwitchBtn.left
        width: titleSwitchBtn.width
        height: pageWidth
        color: "white"
        radius: 4

        SwipeView {
            id: swipeView
            objectName: "outSideSwipView"
            anchors.fill: parent
            currentIndex: 0
            clip: true  //隐藏未选中的界面
            interactive: false  //鼠标能否滑动

            Item {  //St: 0,第一页
                id: onePage
                Rectangle {
                    id: oneView
                    anchors.fill: parent
                    color: "#D7B9A1"
                }
            }

            Item {  //St: 1,第二页
                id: twoPage
                MainQuickMiddleTableRect {
                    id: tableView
                    color: "green"
                    width: titleSwitchBtn.width
                    height: pageWidth
                }
            }

            Item { //St: 2,第三页
                id: defaultPage

                Rectangle {
                    anchors.fill: parent
                    color: "#E6EC12"
                    radius: 4
                    Text {
                        text: qsTr("没有数据")
                        font.pixelSize:16
                        color: "red"
                        font.family: "Microsoft YaHei"
                        verticalAlignment: Text.AlignVCenter
                        horizontalAlignment: Text.AlignHCenter
                        anchors.verticalCenter: parent.verticalCenter
                        anchors.horizontalCenter: parent.horizontalCenter
                    }
                }
            }

        }
    }

    Component.onCompleted: {
    	// 初始化按钮状态
        coverBtnStat(cover_one_btn, true)
        coverBtnStat(cover_two_btn, false)
        coverBtnStat(cover_three_btn, false)
    }

    /*  btn: object
     *  st : modify state
    */
    function coverBtnStat(btn, st) {
        btn.bold_st = st
        btn.show_line = st
    }
}
MainQuickMiddleTableRect.qml
import QtQuick 2.0
import "../qmlTools/ButtonTools"
import QtQuick.Controls 1.4
import QtQuick.Controls 2.5

Rectangle {
    id: win
    anchors.fill: parent
    color: "green"

    property var current_numbers      : 0
    property var stu_id_sort_state    : 1
    property var stu_id_sort_open     : false

    // 绘制表头
    Rectangle {
        id: table_Head
        height: 48
        anchors.top: titleSwitchBtn.bottom

        Rectangle {
            id: table_Text
            height: 47  // 比整个表头高度小1,为了容纳下划线

            TextShow {
                id: name_text
                text: qsTr("姓名")
                anchors.left: table_Text.left
                anchors.leftMargin: 68
                anchors.verticalCenter: table_Text.verticalCenter
            }

            TextShow {
                id: id_text
                // 学号未点击时,显示"↕",表示不排序,点击后再判断时升序还是降序
                text: qsTr("学号") + (!stu_id_sort_open ?
                                     qsTr("↕") :
                                     (stu_id_sort_state ? qsTr("↓") : qsTr("↑")))
                anchors.left: table_Text.left
                anchors.leftMargin: 150
                anchors.verticalCenter: table_Text.verticalCenter

                MouseArea {
                    anchors.fill: parent
                    propagateComposedEvents: true
                    onPressed: {
                        console.log("student id clicked")
                        studentInfoView.updateSort(stu_id_sort_state ? 1 : 2) // 通知C++修改排序方式
                        stu_id_sort_state = !stu_id_sort_state
                        stu_id_sort_open = true
                    }
                }
            }

            TextShow {
                id: sex_text
                text: qsTr("性别")
                anchors.left: table_Text.left
                anchors.leftMargin: 220
                anchors.verticalCenter: table_Text.verticalCenter
            }

            TextShow {
                id: age_text
                text: qsTr("年龄")
                anchors.left: table_Text.left
                anchors.leftMargin: 290
                anchors.verticalCenter: table_Text.verticalCenter

                MouseArea {
                    anchors.fill: parent
                    propagateComposedEvents: true
                    onPressed: {
                        console.log("student age clicked")
                        studentInfoView.updateSort(3)
                        stu_id_sort_open = false
                    }
                }
            }

            LongLine {
                anchors.top: table_Text.bottom
            }
        }
    }

    //listView
    Rectangle {
        width: parent.width
        height: parent.height - table_Head.height
        color: "green"
        anchors.top: table_Head.bottom

        ListView {
            id: list_view
            anchors.rightMargin: 10
            anchors.bottomMargin: 50
            anchors.leftMargin: 0
            anchors.topMargin: 0
            anchors.fill: parent
            maximumFlickVelocity: 800
            clip: true
            delegate: studentInfoDelegate
            model: studentInfoModel
            boundsBehavior: Flickable.StopAtBounds
            highlightMoveDuration: 0

            ScrollBar.vertical: ScrollBar {
                id: scrollbar
                //visible: (current_numbers > 8)
                visible: true
                anchors.right: list_view.right
                width: 8
                active: true
                background: Item {
                    Rectangle {
                        anchors.right: parent.right
                        height: parent.height
                        color: "yellow"
                        radius: 4
                    }
                }
                contentItem: Rectangle {
                    radius: 4
                    color: "red"
                }
            }
        }

        //studentInfoDelegate 渲染每一个item
        Component {
            id: studentInfoDelegate
            Rectangle {
                id: list_item
                width: parent.width
                height: 46
                color: "green"

                Rectangle {
                    width: parent.width
                    height: parent.height
                    color: "green"
                    anchors.verticalCenter: parent.verticalCenter

                    Rectangle {
                        id: rect_item
                        color: "#333333"
                        height: 45

                        TextShow {
                            id: stu_name
                            text: model.stuName
                            anchors.verticalCenter: rect_item.verticalCenter
                            anchors.left: rect_item.left
                            anchors.leftMargin: 68
                        }

                        TextShow {
                            id: id_type
                            text: model.stuId
                            anchors.verticalCenter: rect_item.verticalCenter
                            anchors.left: rect_item.left
                            anchors.leftMargin: 150
                        }

                        TextShow {
                            id: sex_type
                            text: (model.sex == 1) ? qsTr("男") : qsTr("女")
                            anchors.verticalCenter: rect_item.verticalCenter
                            anchors.left: rect_item.left
                            anchors.leftMargin: 220
                        }

                        TextShow {
                            id: age_type
                            text: model.age + qsTr(" 岁")
                            anchors.verticalCenter: rect_item.verticalCenter
                            anchors.left: rect_item.left
                            anchors.leftMargin: 290
                        }
                    }

                    LongLine {
                        anchors.top: rect_item.bottom
                    }
                }
            }
        }
    }

    Component.onCompleted: {
    	// qml加载完成后,可以获取C++中数据的个数,用来标识是否需要展示滚动条
        current_numbers = 4
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

@Async正确使用姿势

Async注解可以使被修饰的方法成为异步方法&#xff0c;简单且方便&#xff0c;这篇文章将教你如何正确的使用它 先谈谈大多数人对Aysnc的认识&#xff1a; 如果直接使用Async&#xff0c;未指定线程池 并且 容器内也没有beanName为taskExecutor的bean&#xff0c;则会使…

im6ull学习总结(三-3)freetype

1、Freetype简介 FreeType是一个开源的字体渲染引擎&#xff0c;主要用于将字体文件转换为位图或矢量图形&#xff0c;并在屏幕上渲染出高质量的字体。它提供了一组API&#xff0c;使开发者能够在自己的应用程序中使用和呈现字体。 FreeType最初是作为一个独立项目开发的&…

欢乐钓鱼^^

欢迎来到程序小院 欢乐钓鱼 玩法&#xff1a;点击鼠标左键左右晃动的鱼钩&#xff0c;下方左右移动的鱼对准鱼的方向即可进行钓鱼&#xff0c; 不同的鱼不同的分数&#xff0c;快去钓鱼吧^^开始游戏https://www.ormcc.com/play/gameStart/241 html <div id"gamediv&qu…

(leetcode)替换所有的问号 -- 模拟算法

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 本题链接 力扣&#xff08;LeetCode&#xff09; 输入描述 string modifyString(string s) 输入一个字符串&#xff0c;字符串中仅包含小写字母和 ‘?’ 字符。 输出描述 将问号替换为小写字母&#xff0c;且这个替…

数据结构期末复习

章节知识点分析 第一章绪论 基本概念 数据 数据元素&#xff08;记录、表目&#xff0c;是数据集合中一个个体&#xff09; 数据项&#xff1a;一个数据元素可由若干数据项组成 数据对象&#xff1a;性质相同的数据元素的集合&#xff0c;是数据的一个子集 数据结构&…

LLM漫谈(二)| QAnything支持任意格式文件或数据库的本地知识库问答系统

一、QAnything介绍 QAnything (Question and Answer based on Anything) 是致力于支持任意格式文件或数据库的本地知识库问答系统&#xff0c;可断网安装使用。 您的任何格式的本地文件都可以往里扔&#xff0c;即可获得准确、快速、靠谱的问答体验。 目前已支持格式: PDF&…

MiniCom串口调试工具使用

一、程序安装 执行下面代码&#xff0c;安装minicom。 sudo apt-get install minicom 二、查看串口设备名称 先拔掉串口运行下面指令&#xff0c;获得所有设备名称,插上串口再运行一次&#xff0c;新增的就是串口设备名称&#xff0c;记住串口设备名称&#xff0c;以串口设备名…

LeetCode-整数反转(7)

题目描述&#xff1a; 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [−231&#xff0c;231− 1] &#xff0c;就返回 0。 假设环境不允许存储 64 位整数&#xff08;有符号或无符号&#xff0…

[4K80 AI ISP IPC芯片]

4K80 AI ISP IPC芯片 Hi3403V100是一颗面向监控市场推出的专业 Ultra-HD Smart IP Camera SOC&#xff0c;该芯片最高支持四路sensor输入&#xff0c;支持最高4K60的ISP图像处理能力&#xff0c;支持3F WDR加粗样式、多级降噪、六轴防抖、硬件拼接等多种图像增强和处理算法&am…

C++多态性——(5)运算符重载(第二节)

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 身先才能率人&#xff0c;律己才能服人…

【SpringBoot】公共字段自动填充功能实现(枚举、自定义注解、AOP、反射)

1. 自定义注解 使用interface语法来定义注解&#xff08;Annotation&#xff09;。 注解的参数类似无参数方法&#xff0c;可以用default设定一个默认值&#xff0c;比如String value() default "";。 元注解&#xff1a;有一些注解可以修饰其他注解&#xff0c;这…

基础面试题整理2

1.抽象类与接口区别 语法&#xff1a; 抽象类用abstract定义&#xff1b;接口用interface定义抽象类被子类继承extends&#xff08;不可用final修饰&#xff09;&#xff1b;接口被类实现implements抽象类的属性访问无限制,方法不可用private修饰&#xff1b;接口中的方法只能…

【STM32】STM32学习笔记-DMA数据转运+AD多通道(24)

00. 目录 文章目录 00. 目录01. DMA简介02. DMA相关API2.1 DMA_Init2.2 DMA_InitTypeDef2.3 DMA_Cmd2.4 DMA_SetCurrDataCounter2.5 DMA_GetFlagStatus2.6 DMA_ClearFlag 03. DMA数据单通道接线图04. DMA数据单通道示例05. DMA数据多通道接线图06. DMA数据多通道示例一07. DMA数…

计算机网络(2)

计算机网络&#xff08;2&#xff09; 小程一言专栏链接: [link](http://t.csdnimg.cn/ZUTXU) 计算机网络和因特网&#xff08;2&#xff09;分组交换网中的时延、丢包和吞吐量时延丢包吞吐量总结 协议层次及其服务模型模型类型OSI模型分析TCP/IP模型分析 追溯历史 小程一言 我…

数据结构——堆排序

什么是堆排序 堆排序就是利用堆&#xff08;假设利用大堆&#xff09;进行排序的算法。他的基本思想是&#xff0c;将待排序的序列构造成一个大顶堆。此时&#xff0c;整个序列的最大值就是堆顶的根节点。将他移走&#xff08;其实就是将其与堆数组的末尾元素交换&#xff0c;…

简单 Web Server 程序的设计与实现 (2024)

1.题目描述 Web 服务是 Internet 最方便与受用户欢迎的服务类型&#xff0c;它的影响力也远远超出了专业技术范畴&#xff0c; 已广泛应用于电子商务、远程教育、远程医疗与信息服务等领域&#xff0c;并且有继续扩大的趋势。目前很多 的 Internet 应用都是基于 Web 技术的&…

Java快速排序希尔排序归并排序

快速排序算法 快速排序的原理&#xff1a;选择一个关键值作为基准值。比基准值小的都在左边序列&#xff08;一般是无序的&#xff09;&#xff0c;比基准值大的都在右边&#xff08;一般是无序的&#xff09;。一般选择序列的第一个元素。 一次循环&#xff1a;从后往前比较&…

VMware中删除虚拟机

虚拟机使用完成后&#xff0c;需要删除虚拟机如何操作呢&#xff1f; 1.首先进入VMware 2.选择需要删除的虚拟机&#xff0c;点击右键 3.直接选择“移除”&#xff1f; 当然不是&#xff0c;这只是从这么目录显示中去掉了&#xff0c;并非 “真正” 删除该虚拟机 注意&#x…

使用sentinel作为熔断器

什么是sentinel Sentinel&#xff0c;中文翻译为哨兵&#xff0c;是为微服务提供流量控制、熔断降级的功能&#xff0c;它和Hystrix提供的功能一样&#xff0c;可以有效的解决微服务调用产生的“雪崩”效应&#xff0c;为微服务系统提供了稳定性的解决方案。随着Hytrxi进入了维…

labelme的json转mask,实测有效

1、创建一个conda的虚拟环境 conda creat -n labelme python3.82、转到你的标注文件夹&#xff08;包括json和图片&#xff09; cd C:/Users/Administrator/Desktop/json3、你需要在标注文件夹下用txt写下以下代码&#xff0c;并保存bat文件。 放在最后一个就可以了 echo of…