QT学习汇总

QT学习汇总

**

更新时间2022-06-21

**
学无止境,温故而知新。
一、pro文件有哪些东西?由那些东西组成?如何使用pro文件?
先看下图:
在这里插入图片描述
当你新建一个项目后,pro文件他会自动帮你生成。其他东西需要你自行添加。
比如程序的图标,生成路径,生成方式,资源文件,第三方库lib等。
下面举例几个常用项:
1.设置程序图标。
准备一个ico图片文件(我的是32*32)放到你的项目中。
然后在pro文件设置目录即可。
下面是效果:
在这里插入图片描述
2. 添加并使用资源文件。
首先右键添加资源类
在这里插入图片描述
添加你所需要的的资源文件在这里插入图片描述

大家可以看一下这个生成的qrc的代码是什么样子的:

在这里插入图片描述

然后设置一个前缀后,添加你所需要添加的资源文件即可。
代码:

    QImage img(":/pic/images/myico.ico"); //新建一个image对象
    ui->label_2->setPixmap(QPixmap::fromImage(img));

下面是使用效果:
在这里插入图片描述
3.添加第三方库使用。这里以opencv为例子。
在这里插入图片描述
首先是包含他的引用文件目录。然后就是他的lib文件目录。
对应有debug和release版本的库使用。

二、有哪些配置文件使用方式?如何使用配置文件?
一个程序,必不可少的就是它的配置文件,随着不同的场景,或者是情况,进行修改。你不可以每次修改项目都重新编译一次项目,所以配置文件就产生了。
1.xml
Extensible Markup Language 可扩展标记语言。
xml格式:

    <?xml version="1.0" encoding="UTF-8"?>
    <doc>
        <config id="5"/>
        <courses institution="机构" teacher="老王" count="4">
            <lesson id="1" url="https://blog.csdn.net/weixin_44353958" fee="免费">QT总结</lesson>
        </courses>
    </doc>

下面给出读写示例代码:
需要添加头部信息

QT += xml
#include <QDebug>
#include <QDomDocument>
#include <QFile>
#include <QTextStream>

void MainWindow::fun_xml()
{
    QString strPath = QCoreApplication::applicationDirPath();
    qDebug()<<strPath;
    if (!strPath.endsWith("/")) {
        strPath += "/";
    }
    //QString strFileName = strPath + "test.xml";   //方式一
    //QString strFileName = ":/config/xml/test.xml"; // 程序运行目录下的xml文件--
    //调用资源文件用不了,不知道为啥,我这里贪方便,用的绝对路径。一般可以用方式一
    QFile file("F:/qtdemo/demo/untitled1/xml/test.xml");
    if (!file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate))
    { // QFile::Truncate,清空原来的内容
        qDebug()<<"clean";

        return ;
    }else
    {
        qDebug()<<"open success";
    }

    QTextStream out(&file);
    out.setCodec("UTF-8");

    //指明版本
    QDomDocument document;      //xml对象
    QDomProcessingInstruction instruction;  //添加处理指令
    instruction = document.createProcessingInstruction("xml",
        "version=\"1.0\" encoding=\"UTF-8\""); // 请注意此处的编码和源代码文件的编码保持一致。

    document.appendChild(instruction);

    // doc  --元素1
    QDomElement rootDoc = document.createElement("doc");
    document.appendChild(rootDoc);
    //config --元素2
    QDomElement eleConfig = document.createElement("config");
    eleConfig.setAttribute("id", 5);
    rootDoc.appendChild(eleConfig);

    QString strName;
    QString strValue;
    // courses --元素3   2和3是同级元素
    QDomElement eleCourses = document.createElement("courses");
    rootDoc.appendChild(eleCourses);  //追加子类

    strName = "institution";
    strValue = QString::fromUtf8("机构");
    eleCourses.setAttribute(strName, strValue);//设置属性名,属性值

    strName = "teacher";
    strValue = QString::fromUtf8("老王");
    eleCourses.setAttribute(strName, strValue);

    strName = "count";
    strValue = QString("%1").arg(4);
    eleCourses.setAttribute(strName, strValue);
    // lesson --元素4
    QDomElement eleLesson = document.createElement("lesson");

    strName = "id";
    strValue = QString("%1").arg(1);
    eleLesson.setAttribute(strName, strValue);

    strName = "url";
    strValue = "https://blog.csdn.net/weixin_44353958";
    eleLesson.setAttribute(strName, strValue);

    strName = "fee";
    strValue = QString::fromUtf8("免费");
    eleLesson.setAttribute(strName, strValue);

    //设置文本节点
    QDomText dtText = document.createTextNode(QString::fromUtf8("QT总结"));
    eleLesson.appendChild(dtText);
    eleCourses.appendChild(eleLesson);

    // 4:缩进值
    document.save(out, 4, QDomNode::EncodingFromTextStream);

    qDebug()<<document.toString();

    file.close();

//    <?xml version="1.0" encoding="UTF-8"?>
//    <doc>
//        <config id="5"/>
//        <courses institution="机构" teacher="老王" count="4">
//            <lesson id="1" url="https://blog.csdn.net/weixin_44353958" fee="免费">QT总结</lesson>
//        </courses>
//    </doc>
}

2.ini
Initialization File(初始化文件)
我在其他文章有写过使用QSetting的方式来读取ini配置文件信息。
下面给出使用的类文件—下面这个是别人写的。
头文件:


#pragma once

#include <QFile>
#include <QString>
#include <QVector>


namespace ini {

// ini格式配置文件处理类
//-----------------------------------------


class CIniConfig: public QObject
{
    Q_OBJECT
public:
	CIniConfig();
	~CIniConfig();

    /**
    * @brief 设置配置文件的文件名,使用全路径,不支持环境变量.
    * @param[in] strFileName 文件名
    * @return true:成功,false:失败
    */
	bool  setFileName(const QString& strFileName);

	/**
	* @brief 读取bool类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] i_nDefault 默认值
	* @param[out] o_bRet true:成功, false:失败
	* @return 数据
	*/
	bool  getBoolean(const QString& strKey, const QString& strSubKey, bool i_nDefault, bool* o_bRet = NULL);
	/**
	* @brief 读取int类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] i_nDefault 默认值
	* @param[out] o_bRet true:成功, false:失败
	* @return 数据
	*/
	int  getInteger(const QString& strKey, const QString& strSubKey, int i_nDefault, bool* o_bRet = NULL);
	/**
	* @brief 读取浮点类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] i_fDefault 默认值
	* @param[out] o_bRet true:成功, false:失败
	* @return 数据
	*/
	double  getDouble(const QString& strKey, const QString& strSubKey, double i_fDefault, bool* o_bRet = NULL);
	/**
	* @brief 读取string类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] strDefault 默认值
	* @param[out] o_bRet true:成功, false:失败
	* @return 数据
	*/
	QString getString(const QString& strKey, const QString& strSubKey, const QString& strDefault, bool* o_bRet = NULL);
	/**
	* @brief 读取string类型的键值(扩展接口),支持多行读取
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] strDefault 默认值
	* @param[out] o_bRet true:成功, false:失败
	* @return 数据
	*/
	QString getStringMultiline(const QString& strKey, const QString& strSubKey, const QString& strDefault, bool* o_bRet = NULL);
	/**
	* @brief 设置bool类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] i_nValue 子键的值
	* @return true:成功, false:失败
	*/
	bool  setBoolean(const QString& strKey, const QString& strSubKey, bool i_nValue);
	/**
	* @brief 设置int类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] i_nValue 子键的值
	* @return true:成功, false:失败
	*/
	bool  setInteger(const QString& strKey, const QString& strSubKey, int i_nValue);
	/**
	* @brief 设置浮点类型的键值
	* @param[in] strKey 主键
	* @param[in] strSubKey 子键
	* @param[in] i_fValue 子键的值
	* @return true:成功, false:失败
	*/
	bool  setDouble(const QString& strKey, const QString& strSubKey, double i_fValue);
	/**
	* @brief 设置字符串类型的键值, 比如,配置文件内容如下:
	*           [config]
	*           x=xx
	*           y=yy
	*           z=zz
	* @param[in] strKey 主键=config
	* @param[in] strSubKey 子键=x
	* @param[in] strValue 子键的值, 为""表示删除该子健。
	* @return true:成功, false:失败
	*/
	bool  setString(const QString& strKey, const QString& strSubKey, const QString& strValue);
    /**
    * @brief 删除全部键值
    * @return true:成功,false:失败
    */
	bool  deleteAllKeys();
    /**
    * @brief 删除指定主键
    * @param[in] strKey 主键
    * @return true:成功,false:失败
    */
	bool  removeKey(const QString& strKey);	
	/**
    * @brief 删除指定子键
    * @param[in] strKey 主键
    * @param[in] strSubKey 子键
    * @return true:成功,false:失败
    */
	bool  removeSubKey(const QString& strKey, const QString& strSubKey);


 
    /**
    * @brief 读取键值列表, ,比如传入("config""),得到, "x=xx\ny=yy\nz=zz"
    * @param[in] strKey 主键
    * @return 键值列表
    */
    QString getAllKeys(const QString& strKey);

    /**
    * @brief 设置键值列表, ,比如传入("config", "x=xx\ny=yy\nz=zz")
    *           执行后的结果:
    *           [config]
    *           x=xx
    *           y=yy
    *           z=zz
    * @param[in] strKey 主键
    * @param[in] str 子键值值列表,\n分隔。比如: "x=xx\ny=yy\nz=zz"  
    * @return 结果,true:成功, false:失败
    */	
    bool setAllKeys(const QString& strKey, const QString& Str);

private:
	int findSubKey(const QString& strKey, const QString& strSubKey);
	bool save2File();

	bool getValue(int i_nIndex, QString& o_pValue);
	bool setValue(int i_nIndex, const QString& strValue);
	void addValue(const QString& strKey, const QString& strSubKey, const QString& strValue, int i_nRet);

	QFile				m_file;    // 文件对象
	QVector<QString>	m_vecString;
	bool				m_bOpened;  // 配置文件是否已打开
};

}

cpp文件:


#include "iniconfig.h"
#include <QTextStream>



namespace ini {

static const int c_bufLen = 10240;
CIniConfig::CIniConfig() :m_bOpened(false) {
}

CIniConfig::~CIniConfig() {
}

bool CIniConfig::setFileName(const QString& strFileName) {
    if (strFileName.length() == 0)
        return false;

    QString tStr;

    m_file.setFileName(strFileName);

    if (!m_file.open(QFile::ReadOnly))		// 文件不存在则返回false
    {
        m_file.close();
        return false;
    }

    // 文件长度=0则返回false
    int t_nFileLen = m_file.size();

    if (t_nFileLen <= 0) {
        m_file.close();
        return false;
    }
    m_bOpened = true;
    m_vecString.clear();

    QTextStream in(&m_file);
    in.setCodec("UTF-8");
    // 将文件内容读入行链表
    while (!in.atEnd())	{
        tStr = in.readLine();
        tStr = tStr.trimmed();

        m_vecString.push_back(tStr);
    }

    m_file.close();

    return true;
}

bool CIniConfig::removeSubKey(const QString& strKey, const QString& strSubKey) {
    if (strKey.length() == 0 || strSubKey.length() == 0)
        return false;

    int nIndex = findSubKey(strKey, strSubKey);

    if (nIndex > 0)
        m_vecString.removeAt(nIndex);

    return save2File();
}

bool CIniConfig::removeKey(const QString& strKey) {
    if (strKey == NULL)
        return false;

    int nBegin = -1;
    int nEnd = -1;
    bool bFindKey = false;
    QString	strTmp;
    strTmp = "[";
    strTmp += strKey;
    strTmp += "]";

    for (int i = 0; i < m_vecString.size(); ++i) {
        if (m_vecString[i].left(1) == ";")			// 注释
            continue;

        if (!bFindKey) {// 未找到主键

            if (m_vecString[i].indexOf(strTmp, Qt::CaseInsensitive) == 0) {

                bFindKey = true;
                nEnd = nBegin = i; //如果主键没有子键,则删除主键不成功。
            }
        }
        else {			// 已经找到主键

            if (m_vecString[i].indexOf("[") == 0) {	// 子键不存在

                nEnd = i;
                break;
            }
            if (i == m_vecString.size() - 1)
                nEnd = i + 1;
        }
    }

    if (nBegin >= 0 && nEnd >= 0) {

        for (int j = nBegin; j < nEnd; j++)
            m_vecString.removeAt(nBegin);

        return save2File();
    }
    return false;
}

bool CIniConfig::deleteAllKeys() {
    if (m_bOpened)  {
        m_file.open(QFile::WriteOnly | QFile::Truncate);
        m_file.close();
        m_vecString.clear();
        return true;
    }
    else
        return false;
}

bool CIniConfig::getBoolean(const QString& strKey, const QString& strSubKey, bool i_bDefault, bool* o_bRet) {
    QString t_strResult;

    if (o_bRet != NULL)
        *o_bRet = true;

    // 抽取结果字符串
    if (!getValue(findSubKey(strKey, strSubKey), t_strResult)) {
        if (o_bRet != NULL)
            *o_bRet = false;
    }

    // 将结果字符串转换为整形数
    if (t_strResult == "Y" || t_strResult == "y")
        return true;
    else if (t_strResult == "N" || t_strResult == "n")
        return false;
    else {
        if (o_bRet != NULL)
            *o_bRet = false;
        return i_bDefault;
    }
}

bool CIniConfig::setBoolean(const QString& strKey, const QString& strSubKey, bool i_bValue) {
    if (strKey == NULL || strSubKey == NULL)
        return false;

    int nLine = findSubKey(strKey, strSubKey);

    char  t_szBool[2];

    if (i_bValue)
        sprintf(t_szBool, "%s", "Y");
    else
        sprintf(t_szBool, "%s", "N");

    if (nLine > 0) {// 存在主键和子键

        if (!setValue(nLine, t_szBool))
            return false;
    }
    else {
        if (nLine == (-m_vecString.size() - 1))
            nLine = 0;
        addValue(strKey, strSubKey, t_szBool, nLine);
    }

    return save2File();
}

int CIniConfig::getInteger(const QString& strKey, const QString& strSubKey, int i_nDefault, bool* o_bRet) {
    QString t_strResult;

    if (o_bRet != NULL)
        *o_bRet = true;

    // 抽取结果字符串
    if (!getValue(findSubKey(strKey, strSubKey), t_strResult)) {
        if (o_bRet != NULL)
            *o_bRet = false;
        return i_nDefault;
    }

    // 将结果字符串转换为整形数
    return atoi(t_strResult.toLocal8Bit().data());
}

bool CIniConfig::setInteger(const QString& strKey, const QString& strSubKey, int i_nValue) {
    if (strKey == NULL || strSubKey == NULL)
        return false;

    char  t_szInt[64];
    sprintf(t_szInt, "%d", i_nValue);

    int nLine = findSubKey(strKey, strSubKey);

    if (nLine > 0) {// 存在主键和子键

        if (!setValue(nLine, t_szInt))
            return false;
    }
    else {
        if (nLine == (-m_vecString.size() - 1))
            nLine = 0;
        addValue(strKey, strSubKey, t_szInt, nLine);
    }

    return save2File();
}

double CIniConfig::getDouble(const QString& strKey, const QString& strSubKey, double i_fDefault, bool* o_bRet) {
    QString t_strResult;

    if (o_bRet != NULL)
        *o_bRet = true;

    // 抽取结果字符串
    if (!getValue(findSubKey(strKey, strSubKey), t_strResult)) {
        if (o_bRet != NULL)
            *o_bRet = false;
        return i_fDefault;
    }

    // 将结果字符串转换为浮点数
    return atof(t_strResult.toLocal8Bit().data());
}

bool CIniConfig::setDouble(const QString& strKey, const QString& strSubKey, double i_fValue) {
    if (strKey == NULL || strSubKey == NULL)
        return false;

    char  t_szReal[64];
    sprintf(t_szReal, "%.3f", i_fValue);

    int nLine = findSubKey(strKey, strSubKey);

    if (nLine > 0)	{// 存在主键和子键

        if (!setValue(nLine, t_szReal))
            return false;
    }
    else {
        if (nLine == (-m_vecString.size() - 1))
            nLine = 0;
        addValue(strKey, strSubKey, t_szReal, nLine);
    }

    return save2File();
}

QString CIniConfig::getString(const QString& strKey, const QString& strSubKey, const QString& strDefault, bool* o_bRet) {
    QString tStr;

    if (o_bRet != NULL)
        *o_bRet = true;

    // 抽取结果字符串
    if (!getValue(findSubKey(strKey, strSubKey), tStr)) {
        if (o_bRet != NULL)
            *o_bRet = false;
        return strDefault;
    }
    return tStr;
}
QString CIniConfig::getStringMultiline(const QString& strKey, const QString& strSubKey, const QString& strDefault, bool* o_bRet/*=NULL*/) {
    QString tStr;

    if (o_bRet != NULL)
        *o_bRet = true;

    int nIndex = findSubKey(strKey, strSubKey);
    // 抽取结果字符串
    if (!getValue(nIndex, tStr)) {
        if (o_bRet != NULL)
            *o_bRet = false;
        return strDefault;
    }

    // 满值再读一行
    QString tNextLine = m_vecString[nIndex];
    while (tNextLine.length() == (c_bufLen - 1)) {
        tNextLine = m_vecString[++nIndex];
        tStr += tNextLine;
    }

    return tStr;
}

bool CIniConfig::setString(const QString& strKey, const QString& strSubKey, const QString& strValue) {
    if (strKey == NULL || strSubKey == NULL)
        return false;

    if (strValue.length() == 0)
        return removeSubKey(strKey, strSubKey);

    int nLine = findSubKey(strKey, strSubKey);

    if (nLine > 0) {// 存在主键和子键

        if (!setValue(nLine, strValue))
            return false;
    }
    else {
        if (nLine == (-m_vecString.size() - 1))
            nLine = 0;
        addValue(strKey, strSubKey, strValue, nLine);
    }

    return save2File();
}

QString CIniConfig::getAllKeys(const QString& strKey) {
    bool bFindKey = false;
    QString	strTmp;
    strTmp = "[";
    strTmp += strKey;
    strTmp += "]";
    bool bFirstTime = true;

    QString tStr;
    for (int i = 0; i < m_vecString.size(); ++i) {
        if (m_vecString[i][0] == ';')			// 注释
            continue;

        if (!bFindKey) {// 未找到主键

            if (m_vecString[i].indexOf(strTmp, Qt::CaseInsensitive) == 0)
                bFindKey = true;
        }
        else {		// 已经找到主键

            if (m_vecString[i].indexOf("[") == 0)				// 子键的搜索到头
                return tStr;

            if (bFirstTime) {

                tStr = m_vecString[i];
                bFirstTime = false;
            }
            else {
                tStr += "\r\n";
                tStr += m_vecString[i];
            }
        }
    }
    return tStr;
}

bool CIniConfig::setAllKeys(const QString& strKey, const QString& i_pStr) {
    QString	strTmp;
    strTmp = "[";
    strTmp += strKey;
    strTmp += "]";
    int tBeginPos = -1;
    QString tStr = i_pStr;

    for (int i = 0; i < m_vecString.size(); ++i) {
        if (m_vecString[i][0] == ';')			// 注释
            continue;

        if (m_vecString[i].indexOf(strTmp, Qt::CaseInsensitive) == 0) {
            tBeginPos = i;
            break;
        }
    }

    if (tBeginPos < 0) {// 未找到主键

        m_vecString.push_front(strTmp);
        tBeginPos = 1;
    }
    else {
        tBeginPos += 1;
        while (tBeginPos < m_vecString.size() && m_vecString[tBeginPos].indexOf("[") != 0) {
            m_vecString.removeAt(tBeginPos);
        }
    }

    // 插入处理,
    QStringList strList = tStr.split("\n");
    QStringList::iterator iteStr = strList.begin();
    while (iteStr != strList.end()) {
        tStr = *iteStr;
        m_vecString.insert(tBeginPos, tStr);
        iteStr++;
    }

    return save2File();
}

//=======================================================
// 私有函数
//=======================================================
int CIniConfig::findSubKey(const QString& strKey, const QString& strSubKey) {
    int nRet = -m_vecString.size() - 1;
    bool bFindKey = false;
    int nTmpPos = 0;
    QString tStr;
    QString strTmp;
    strTmp = "[";
    strTmp += strKey;
    strTmp += "]";

    for (int i = 0; i < m_vecString.size(); ++i) {
        if (m_vecString[i][0] == ';')			// 注释
            continue;

        if (!bFindKey)	{// 未找到主键

            if (m_vecString[i].indexOf(strTmp, Qt::CaseInsensitive) == 0)
            {
                bFindKey = true;
                nRet = -i - 1;										// 有主键
            }
        }
        else { // 已经找到主键
            nTmpPos = m_vecString[i].indexOf("=");
            tStr = m_vecString[i].left(nTmpPos);
            tStr = tStr.trimmed();

            if (tStr == strSubKey)	{// 找到子键

                nRet = i;
                break;
            }

            if (m_vecString[i][0] == '[')							// 子键不存在
                break;
        }
    }
    return nRet;
}

bool CIniConfig::save2File() {
    if (!m_file.open(QFile::WriteOnly))
        return false;

    // 将缓存区写入文件
    m_file.seek(0);
    QTextStream out(&m_file);
    out.setCodec("UTF-8");
    QString str;
    for (int i = 0; i < m_vecString.size(); ++i) {
        str = m_vecString[i];
        if ((str.right(1) != '\r') && (str.right(1) != '\n')) {
            str += "\r\n";
        }
        out << str;
 //       m_file.write(str.toUtf8());
    }
    m_file.close();
    return true;
}

bool CIniConfig::getValue(int i_nIndex, QString& o_pValue) {
    if (i_nIndex < 0 || i_nIndex >= m_vecString.size())
        return false;

    int nBegin = m_vecString[i_nIndex].indexOf("=") + 1;

    if (nBegin < 0)				// 没有"="号则错误
        return false;

    o_pValue = m_vecString[i_nIndex].mid(nBegin);
    o_pValue = o_pValue.trimmed();
    return true;
}

bool CIniConfig::setValue(int i_nIndex, const QString& strValue) {
    if (i_nIndex < 0 || i_nIndex >= m_vecString.size())
        return false;

    int nBegin = m_vecString[i_nIndex].indexOf("=") + 1;

    if (nBegin < 0)				// 没有"="号则错误
        return false;

    QString tStr = m_vecString[i_nIndex].mid(nBegin);
    m_vecString[i_nIndex].replace(nBegin, tStr.length(), strValue);
    return true;
}

void CIniConfig::addValue(const QString& strKey, const QString& strSubKey, const QString& strValue, int i_nRet) {
    QString strTmp;
    if (i_nRet == 0)	{// 无主键

        // 增加主键
        strTmp = "[";
        strTmp += strKey;
        strTmp += "]";
        m_vecString.push_back("");
        m_vecString.push_back(strTmp);

        // 增加子键
        strTmp = strSubKey;
        strTmp += "=";
        strTmp += strValue;
        m_vecString.push_back(strTmp);
    }
    else	{// 有主键无子键

        // 增加子键
        strTmp = strSubKey;
        strTmp += "=";
        strTmp += strValue;
        m_vecString.insert(-i_nRet, strTmp);
    }
}
}

使用例子:

void MainWindow::fun_setIni()
{
    QString strFileName = "F:/qtdemo/demo/untitled1/config.ini";
    ini::CIniConfig cfg;
    cfg.setFileName(strFileName);
    cfg.setAllKeys("config", "x=xx\ny=yy\nz=zz");
    cfg.setBoolean("datatype", "bool-1", true);
    cfg.setInteger("datatype", "int-1", 0);
    cfg.setDouble("datatype", "real-1", 0.03);
    cfg.setString("datatype", "string", QString::fromUtf8("你好"));
}

void MainWindow::fun_readIni()
{
    QString strFileName = "F:/qtdemo/demo/untitled1/config.ini";
    ini::CIniConfig cfg;
    cfg.setFileName(strFileName);
    QString str;
    str = cfg.getString("datatype", "string", "啦啦啦");
    qDebug()<<str;
}

qtcreator 代码高亮显示

在这里插入图片描述

三、常用窗口化程序如何设计?
四、如何使用图表?
五、如何使用画笔进行绘图?
六、开发插件

以上为菜鸡的我总结。
欢迎各位大佬互相交流。
QQ:1107097641

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值