qt笔记之qml和C++的交互系列(一):初记

code review!

—— 杭州 2023-11-16 夜


文章目录

  • 一.qt笔记之qml和C++的交互:官方文档阅读理解
    • 0.《Overview - QML and C++ Integration》中给出五种QML与C+集成的方法
    • 1.Q_PROPERTY:将C++类的成员变量暴露给QML
    • 2.Q_INVOKABLE()或public slots:将C++类的成员函数暴露给QML
    • 3.on\<Signal\>其中\<Signal\>第一个字母大写:暴露C++中的信号以及信号中传递的参数给QML
  • 二.qt笔记之qml和C++的交互笔记
    • 1.设置上下文属性(setContextProperty())
      • 1.1.fileio.h
      • 1.2.fileio.cpp
      • 1.3.main.cc
      • 1.4.main.qml
    • 2.在QML引擎里面注册新类型(qmlRegisterType)
      • 2.1.fileio.h
      • 2.2.fileio.cpp
      • 2.3.main.cc
      • 2.4.main.qml
    • 3.导出对应的QML扩展插件——略

一.qt笔记之qml和C++的交互:官方文档阅读理解

参考资料:

官方文档《Exposing Attributes of C++ Types to QML》(将C++类暴露给QML)
官方文档《Data Type Conversion Between QML and C++》
官方文档《The Property System》
官方文档《Defining QML Types from C++》(在QML中定义C++类)
官方文档《Overview - QML and C++ Integration》

0.《Overview - QML and C++ Integration》中给出五种QML与C+集成的方法

  • 1.Exposing Attributes of C++ Classes to QML
  • 2.Defining QML Types from C++
  • 3.Embedding C++ Objects into QML with Context Properties
  • 4.Interacting with QML Objects from C++
  • 5.Data Type Conversion Between QML and C++

1.Q_PROPERTY:将C++类的成员变量暴露给QML

Q_PROPERTY(…)
This macro is used for declaring properties in classes that inherit QObject. Properties behave like class data members, but they have additional features accessible through the Meta-Object System.
翻译:
这个宏用于在继承 QObject 的类中声明属性。属性的行为类似于类数据成员,但通过元对象系统可以访问额外的功能。

在这里插入图片描述

翻译:

为了与QML最大程度地互操作,任何可写的属性都应该有一个关联的NOTIFY信号,在属性值变化时发出。这允许该属性与属性绑定(property binding)一起使用,属性绑定是QML的一个重要特性,它通过在任何依赖项值变化时自动更新属性来强制属性之间的关系。

在上述示例中,author属性的关联NOTIFY信号是authorChanged,如Q_PROPERTY()宏调用中所指定的。这意味着每当信号被发出时——比如在Message::setAuthor()中当author发生变化时——它会通知QML引擎需要更新任何涉及author属性的绑定,进而引擎将通过再次调用Message::author()来更新text属性。

如果author属性可写,但没有关联的NOTIFY信号,text值将使用Message::author()返回的初始值进行初始化,但不会更新为此属性的任何后续更改。此外,任何尝试从QML绑定到该属性的操作都会导致引擎产生运行时警告。

注意:建议将NOTIFY信号命名为<property>Changed,其中<property>是属性的名称。由QML引擎生成的关联属性更改信号处理程序的形式始终为on<Property>Changed,而不管相关的C++信号的名称如何,因此建议信号名称遵循此约定,以避免任何混淆。

GPT解读:
在上述代码中,Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged) 声明了一个名为 author 的属性,它具有读取方法 author() 和写入方法 setAuthor(const QString&)。该属性还使用了信号 authorChanged(),以便在属性值更改时发出通知。

setAuthor函数中修改了m_author的值后,Q_PROPERTY声明的属性author的值也会相应地改变。这是因为在setAuthor函数中,当m_author的值发生变化时,通过emit authorChanged()语句发出了信号authorChanged(),这个信号与Q_PROPERTY中的NOTIFY关键字相关联。

Q_PROPERTYNOTIFY关键字用于指定一个信号,当属性的值发生变化时,会发出这个信号。在这种情况下,authorChanged()信号与author属性相关联,意味着当m_author的值发生变化时,会发出authorChanged()信号。

因此,当m_author的值在setAuthor函数中被修改时,会发出authorChanged()信号,这将导致与author属性相关联的代码(例如绑定到该属性的UI元素)能够接收到信号并相应地更新属性的值。

QString author() constMessage 类的成员函数,用于读取私有成员变量 m_author 的值并返回。

QString m_authorMessage 类的私有成员变量,用于存储作者的名称。

main 函数中,通过创建 Message 类的实例 msg,将其设置为上下文属性,使其可以在 QML 文件中访问。

MyItem.qml 中,通过 msg.author 可以读取 Message 类中的 author 属性值。这将调用 Message::author() 方法。

Component.onCompleted 中,将 msg.author 设置为 “Jonah”,这将调用 Message::setAuthor() 方法,并且在属性值更改后会发出 authorChanged() 信号。

在这里插入图片描述

2.Q_INVOKABLE()或public slots:将C++类的成员函数暴露给QML

Exposing Methods (Including Qt Slots):
在这里插入图片描述

3.on<Signal>其中<Signal>第一个字母大写:暴露C++中的信号以及信号中传递的参数给QML

在这里插入图片描述

翻译:

任何继承自QObject类型的公共信号都可以在QML代码中访问。

QML引擎会自动为在QML中使用的任何继承自QObject类型的信号创建信号处理器。信号处理器的命名规则是on<信号名>,其中<信号名>是信号的名称,首字母大写。通过参数名,可以在信号处理器中访问所有通过信号传递的参数。

例如,假设MessageBoard类具有一个带有单个参数subject的newMessagePosted()信号:

class MessageBoard : public QObject
{
    Q_OBJECT
public:
   // ...
signals:
   void newMessagePosted(const QString &subject);
};

如果MessageBoard类型已在QML类型系统中注册,那么在QML中声明的MessageBoard对象可以通过名为onNewMessagePosted的信号处理器接收newMessagePosted()信号,并检查subject参数的值:

MessageBoard {
    onNewMessagePosted: (subject)=> console.log("New message received:", subject)
}

二.qt笔记之qml和C++的交互笔记

原文链接:

QML进阶(八)实现QML界面与C++类型交互

在QML工程中,一般QML界面只负责前端交互,而真正的业务逻辑都是C++模块实现的。为了实现前端和后端的顺利衔接,我们需要做好QML界面与C++的交互。这里就介绍一下如何在QML中调用对应的C++模块。在QML中调用C++模块的方法主要有三种,分别是:

1.设置上下文属性(setContextProperty())
2.在QML引擎里面注册新类型(qmlRegisterType)
3.导出对应的QML扩展插件。

下面介绍一下三个方法的优缺点:
对于小型应用来说,方法一设置上下文属性是最简单实用的方法。开发者只需要将对应的接口和变量暴露给QML就行。由于设置在QML中的变量是全局的,一定要注意避免名称冲突。

在QML引擎里面注册新的类型,允许用户在QML文件中控制C++对象的生命周期,这是设置上下文属性这种方法无法实现的。同时注册新类型的方法,不会污染全局命名空间。但是这种方法也有一个缺点,就是QML中的类型都需要提前注册,所有用到的库都需要在程序启动的时候链接,无法动态链接。但在绝大多数情况下,这并不是一个问题。

QML扩展插件是弹性最好,但也是最复杂的方法。QML允许用户在插件里面注册对应的新类型。这些新类型在QML第一次导入对应的符号的时候被加载。同时,通过使用QML单例引入,我们的新类型不会污染全局命名空间。由于新类型被插件化了,我们可以很轻松的在多个项目中复用我们之前定义的新类型。

1.设置上下文属性(setContextProperty())

1.1.fileio.h

在这里插入图片描述

1.2.fileio.cpp

在这里插入图片描述

1.3.main.cc

在这里插入图片描述

1.4.main.qml

在这里插入图片描述

代码
fileio.h

#ifndef FILEIO_H
#define FILEIO_H

#include <QtCore>
//用来打开的保存对应的文件
class FileIO : public QObject
{
    Q_OBJECT
    //定义QML可以访问的属性,定义格式如下
    //Q_PROPERTY(变量类型 访问名称 READ 读方法 WRITE 写方法 NOTIFY 发生变化的通知信号)
    //需要定义在Q_OBJECT之后第一个public之前
    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)

    //ui_title是在QML使用的别名,m_title_content是对应的变量名称
    //CONSTANT说明是只读的
    Q_PROPERTY(QString ui_title MEMBER m_title_content CONSTANT)
public:
    FileIO(QObject *parent = 0);
    ~FileIO();

    //定义QML可以访问的方法
    Q_INVOKABLE void read();
    Q_INVOKABLE void write();

    QUrl source() const;
    QString text() const;
public slots:
    void setSource(QUrl source);
    void setText(QString text);
signals:
    void sourceChanged(QUrl arg);
    void textChanged(QString arg);
private:
    QUrl m_file_source;
    QString m_file_content;
    //用来测试的只读title数据
    QString m_title_content;
};

#endif // FILEIO_H

fileio.cpp

#include "fileio.h"
FileIO::FileIO(QObject *parent)
    : QObject(parent),
      m_title_content(QString("fileio"))
{
}

FileIO::~FileIO()
{
}

void FileIO::read()
{
    if(m_file_source.isEmpty()) {
        return;
    }
    QFile file(m_file_source.toLocalFile());
    if(!file.exists()) {
        qWarning() << "Does not exits: " << m_file_source.toLocalFile();
        return;
    }
    if(file.open(QIODevice::ReadOnly)) {
        QTextStream stream(&file);
        m_file_content = stream.readAll();
        emit textChanged(m_file_content);
    }
}

void FileIO::write()
{
    if(m_file_source.isEmpty()) {
        return;
    }
    QFile file(m_file_source.toLocalFile());
    if(file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << m_file_content;
    }
}

QUrl FileIO::source() const
{
    return m_file_source;
}

QString FileIO::text() const
{
    return m_file_content;
}

void FileIO::setSource(QUrl source)
{
    if (m_file_source == source)
        return;

    m_file_source = source;
    emit sourceChanged(source);
}

void FileIO::setText(QString text)
{
    if (m_file_content == text)
        return;
    m_file_content = text;
    emit textChanged(text);
}

main.cc

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QFont>
#include "fileio.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    //根据不同的QT版本设置对应的编码
    app.setFont(QFont("Microsoft Yahei", 9));
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
    QTextCodec *codec = QTextCodec::codecForName("gbk");
#else
    QTextCodec *codec = QTextCodec::codecForName("utf-8");
#endif
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    QTextCodec::setCodecForTr(codec);
#else
    QTextCodec *codec = QTextCodec::codecForName("utf-8");
    QTextCodec::setCodecForLocale(codec);
#endif

    //定义对应的类型指针
    QScopedPointer<FileIO> current_file_io(new FileIO());
    QQmlApplicationEngine engine;
    //在加载对应的URL之前, 设置上下文属性
    engine.rootContext()->setContextProperty("qmlfileio",current_file_io.data());
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}

main.qml

import QtQuick 2.8
import QtQuick.Window 2.2
import Qt.labs.platform 1.0

Window {
    visible: true
    width: 440
    height: 300
    title: qsTr("Context fileIO")
    Column{
        Rectangle{
            id:contentRect
            x:10; y:10
            width: 400
            height: 150

            //用于显示打开的文本文件的内容
            Text{                
                id:content
                anchors.top :contentRect.top
                anchors.bottom: contentRect.bottom
                anchors.left: contentRect.left
                anchors.right: contentRect.right
                text: qmlfileio.text
            }
            border.color: "#CCCCCC"
        }
       
        //点击的按钮用来选择对应的文件
        Rectangle{
            anchors.horizontalCenter:contentRect.horizontalCenter
            color: "#4D9CF8"
            width:200
            height: 30
            Text{
                anchors.centerIn: parent
                text:"点击打开文件"
            }
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    fileDialog.open();
                }
            }
        }
    }
    //文件选择窗口,选择需要打开的文件
    //并读取文件中对应的内容
    FileDialog{
        id: fileDialog
        folder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
        onFileChanged: {
            qmlfileio.source = fileDialog.file;
            qmlfileio.read();
        }
    }
}

2.在QML引擎里面注册新类型(qmlRegisterType)

2.1.fileio.h

在这里插入图片描述

2.2.fileio.cpp

在这里插入图片描述

2.3.main.cc

在这里插入图片描述

2.4.main.qml

在这里插入图片描述

代码
fileio.h

#ifndef FILEIO_H
#define FILEIO_H

#include <QtCore>
//用来打开的保存对应的文件
class FileIO : public QObject
{
    Q_OBJECT
    //定义QML可以访问的属性,定义格式如下
    //Q_PROPERTY(变量类型 访问名称 READ 读方法 WRITE 写方法 NOTIFY 发生变化的通知信号)
    //需要定义在Q_OBJECT之后第一个public之前
    Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)

    //ui_title是在QML使用的别名,m_title_content是对应的变量名称
    //CONSTANT说明是只读的
    Q_PROPERTY(QString ui_title MEMBER m_title_content CONSTANT)
public:
    FileIO(QObject *parent = 0);
    ~FileIO();

    //定义QML可以访问的方法
    Q_INVOKABLE void read();
    Q_INVOKABLE void write();

    QUrl source() const;
    QString text() const;
public slots:
    void setSource(QUrl source);
    void setText(QString text);
signals:
    void sourceChanged(QUrl arg);
    void textChanged(QString arg);
private:
    QUrl m_file_source;
    QString m_file_content;
    //用来测试的只读title数据
    QString m_title_content;
};

#endif // FILEIO_H

fileio.cpp

#include "fileio.h"
FileIO::FileIO(QObject *parent)
    : QObject(parent),
      m_title_content(QString("fileio"))
{
}

FileIO::~FileIO()
{
}

void FileIO::read()
{
    if(m_file_source.isEmpty()) {
        return;
    }
    QFile file(m_file_source.toLocalFile());
    if(!file.exists()) {
        qWarning() << "Does not exits: " << m_file_source.toLocalFile();
        return;
    }
    if(file.open(QIODevice::ReadOnly)) {
        QTextStream stream(&file);
        m_file_content = stream.readAll();
        emit textChanged(m_file_content);
    }
}

void FileIO::write()
{
    if(m_file_source.isEmpty()) {
        return;
    }
    QFile file(m_file_source.toLocalFile());
    if(file.open(QIODevice::WriteOnly)) {
        QTextStream stream(&file);
        stream << m_file_content;
    }
}

QUrl FileIO::source() const
{
    return m_file_source;
}

QString FileIO::text() const
{
    return m_file_content;
}

void FileIO::setSource(QUrl source)
{
    if (m_file_source == source)
        return;

    m_file_source = source;
    emit sourceChanged(source);
}

void FileIO::setText(QString text)
{
    if (m_file_content == text)
        return;
    m_file_content = text;
    emit textChanged(text);
}

main.cc

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QFont>
#include "fileio.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    //在engine声明之前注册C++类型
    //@1:类在qml中别名 @2:版本主版本号 @3:版本的次版本号 @4类的名称
    qmlRegisterType<FileIO>("org.fileio",1,0,"FileIO");
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    return app.exec();
}

main.qml:import org.fileio 1.0

import QtQuick 2.8
import QtQuick.Window 2.2
import Qt.labs.platform 1.0
import org.fileio 1.0

Window {
    visible: true
    width: 440
    height: 300
    title: qsTr("Context fileIO")
    Column{
        Rectangle{
            id:contentRect
            x:10; y:10
            width: 400
            height: 150

            //用于显示打开的文本文件的内容
            Text{                
                id:content
                anchors.top :contentRect.top
                anchors.bottom: contentRect.bottom
                anchors.left: contentRect.left
                anchors.right: contentRect.right
                text: fileIO.text
            }
            border.color: "#CCCCCC"
        }

        //点击的按钮用来选择对应的文件
        Rectangle{
            anchors.horizontalCenter:contentRect.horizontalCenter
            color: "#4D9CF8"
            width:200
            height: 30
            Text{
                anchors.centerIn: parent
                text:"点击打开文件"
            }
            //点击按钮弹出选择文件的对话框
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    fileDialog.open();
                }
            }
        }
    }
    //文件选择窗口,选择需要打开的文件
    //并读取文件中对应的内容
    FileDialog{
        id: fileDialog
        folder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
        onFileChanged: {
            fileIO.source = fileDialog.file;
            fileIO.read();
        }
    }
   
    //外部导入的C++类型,可以直接定义使用
    //外部通过ID来访问该模块
    FileIO{
        id:fileIO
    }
}

3.导出对应的QML扩展插件——略

在这里插入图片描述

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

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

相关文章

网络编程TCP/UDP通信

1 网络通信概述 1.1 IP 和端口 所有的数据传输&#xff0c;都有三个要素 &#xff1a;源、目的、长度。 怎么表示源或者目的呢&#xff1f;请看图 所以&#xff0c;在网络传输中需要使用“IP 和端口”来表示源或目的。 1.2 网络传输中的 2 个对象&#xff1a;server 和 cl…

Linux操作系统 - 进程控制

目录 进程创建 进程退出 进程等待 进程替换 进程创建 在操作系统中&#xff0c;除了系统启动之后的第一个进程(根进程&#xff0c;1号进程)由系统来创建外&#xff0c;其余进程都必须由已存在的进程来创建。其中&#xff0c;这个新创建的进程叫做子进程&#xff0c;而创建…

Nginx(四) absolute_redirect、server_name_in_redirect、port_in_redirect 请求重定向指令组合测试

本篇文章主要用来测试absolute_redirect、server_name_in_redirect和port_in_redirect三个指令对Nginx请求重定向的影响&#xff0c;Nginx配置详解请参考另一篇文章 Nginx(三) 配置文件详解 接下来&#xff0c;在Chrome无痕模式下进行测试。 测试1&#xff1a;absolute_redi…

微软Surface/Surface pro笔记本电脑进入bios界面

微软Surface笔记本电脑进入bios界面 方法一推薦這種方法&#xff1a;Surface laptop 进BIOS步骤 开机后&#xff0c;不停按音量键进bios界面。 方法二&#xff1a;Surface Book、Surface Pro进bios步骤 1、关闭Surface&#xff0c;然后等待大约10秒钟以确保其处于关闭状态。…

百度智能小程序源码系统:打造极致用户体验的关键 带完整搭建教程

大家好啊&#xff0c;今天罗峰来给大家分享一款百度智能小程序系统源码。一起来看看吧。 百度智能小程序源码系统是百度从做智能小程序的第一天开始就致力于打造真正开源开放的生态的产物。作为目前业内唯一真正开源的平台&#xff0c;百度智能小程序将开放性放在重要位置&…

大数据毕业设计选题推荐-机房信息大数据平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

win10查看wifi密码

文章目录 标题win10查看wifi密码命令方式窗口 标题win10查看wifi密码 命令方式 # name 为指定的wifi名称 netsh wlan show profiles name"TP-LINK_1946" keyclear窗口

春秋云境靶场CVE-2021-41402漏洞复现(任意代码执行漏洞)

文章目录 前言一、CVE-2021-41402描述二、CVE-2021-41402漏洞复现1、信息收集1、方法一弱口令bp爆破2、方法二7kb扫路径&#xff0c;后弱口令爆破 2、找可能可以进行任意php代码执行的地方3、漏洞利用找flag 总结 前言 此文章只用于学习和反思巩固渗透测试知识&#xff0c;禁止…

pwnable.kr--pwn游戏之fd

题目描述&#xff1a; 大致告诉我们研究的可能是Linux下的文件描述符。需要我们用ssh链接过去找到flag。于是我们就过去看看&#xff1a; 乍看情况有点像简单nc&#xff0c;我们尝试看看目录下都有什么&#xff1a; 看到flag&#xff0c;那么尝试输出呢&#xff1f; Permission…

全新的FL studio21.2版支持原生中文FL studio2024官方破解版

FL studio2024官方破解版是一款非常专业的音频编辑制作软件。目前它的版本来到了全新的FL studio21.2版&#xff0c;支持原生中文&#xff0c;全面升级的EQ、母带压线器等功能&#xff0c;让你操作起来更加方便&#xff0c;该版本经过破解处理&#xff0c;用户可永久免费使用&a…

【DevOps】Git 图文详解(一):简介及基础概念

Git 图文详解&#xff08;一&#xff09;&#xff1a;简介及基础概念 1.简介&#xff1a;认识 Git2.基础概念&#xff1a;Git 是干什么的&#xff1f;2.1 概念汇总2.2 工作区 / 暂存区 / 仓库2.3 Git 基本流程2.4 Git 状态 1.简介&#xff1a;认识 Git Git 是当前最先进、最主…

Python---列表 集合 字典 推导式(本文以 字典 为主)

推导式&#xff1a; 推导式comprehensions&#xff08;又称解析式&#xff09;&#xff0c;是Python的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列&#xff08;一个有规律的列表或控制一个有规律列表&#xff09;的结构体。 共有三种推导&#xff1a;列表…

【漏洞复现】OneThink前台注入漏洞

漏洞描述 OneThink 是一个基于 PHP 的开源内容管理框架&#xff0c;旨在简化和加速Web应用程序的开发过程。它提供了一系列通用的模块和功能&#xff0c;使开发者能够更轻松地构建具有灵活性和可扩展性的内容管理系统&#xff08;CMS&#xff09;和其他Web应用。 免责声明 …

RS485接线方式

用2个触点连接RS485设备——RS485引脚半双工分配&#xff1a; 用4个触点连接RS485设备——RS485引脚全双工分配&#xff1a; 参考文章&#xff1a;RS485引脚说明及接口说明 文章目录 RS485 接线方式引言RS485通信标准简介基本特性差分信号&#xff1a;RS485使用差分信号传输&am…

AOF是什么?

目录 一、AOF是什么&#xff1f; 二、使用AOF 三、命令写入 四、重写机制 4.1 触发AOF 4.2 AOF执行流程 一、AOF是什么&#xff1f; AOF是Append Only File&#xff0c;是Redis中实现持久化的一种方式。以独⽴⽇志的⽅式记录每次命令&#xff0c;重启时再重新执⾏ AOF ⽂件中的…

Day32力扣打卡

打卡记录 买卖股票的最佳时机 IV&#xff08;状态机DP&#xff09; 链接 class Solution:def maxProfit(self, k: int, prices: List[int]) -> int:n len(prices)max lambda x, y: x if x > y else yf [[-0x3f3f3f3f] * 2 for _ in range(k 2)]for i in range(k 2…

Vim 从何而来?

Vim 编辑器的创造者、维护者和终身领导者 Bram Moolenaar 为了纪念这位杰出的荷兰程序员&#xff0c;我们今天来聊一聊 Vim 的历史。 Vim 无处不在。它被很多人使用。同时 Vim 可能是世界上 “最难用的软件之一” &#xff0c;但是又多次被程序员们评价为 最受欢迎的 代码编辑…

设计模式—结构型模式之外观模式(门面模式)

设计模式—结构型模式之外观模式&#xff08;门面模式&#xff09; 外观&#xff08;Facade&#xff09;模式又叫作门面模式&#xff0c;是一种通过为多个复杂的子系统提供一个一致的接口&#xff0c;而使这些子系统更加容易被访问的模式。 例子 我们的电脑会有很多 组件&am…

搜维尔科技:业内普遍选择Varjo头显作为医疗VR/AR/XR解决方案

Varjo 的人眼分辨率混合现实和虚拟现实头显将医疗专业人员的注意力和情感投入提升到更高水平。借助逼真的 XR/VR&#xff0c;医疗和保健人员可以为最具挑战性的现实场景做好准备&#xff01; 在虚拟、增强和混合现实中进行最高水平的训练和表现 以逼真的 3D 方式可视化医疗数据…

JS原生-弹框+阿里巴巴矢量图

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…