zoukankan      html  css  js  c++  java
  • QT学习笔记——06-Day17_C++_QT

    在学习QT总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

    06-Day17_C++_QT

    目录:
    Qt案例笔记
    1、对话框列表
    2、简单的二人聊天Udp聊天程序
    3、核心功能——群聊实现
    4、新用户进入
    5、用户离开
    6、代码

    Qt案例笔记

    1、对话框列表

    1)Toolbox群成员

    2)内部,做出一个垂直布局

    3)添加按钮

      图标、文字、图标大小、风格、文字图标都显示、按钮保存到QVector容器中

    (1)右击项目名,在弹出的快捷菜单中选择“添加新文件...”菜单项,在弹出的对话框中选择“Qt”选项。选择Qt设计师界面类,单击“Choose...”按钮;

    界面模板选择Widget,点击下一步

    类名填写 DialogList (可以起其他名称)点击下一步

    在汇总中单击“完成”按钮,系统会为我们添加“dialoglist.h”头文件和“dialoglist.cpp”源文件以及dialoglist.ui设计文件

    (2)资源导入

    (3)聊天窗口搭建

    2、简单的二人聊天Udp聊天程序

    1)UdpSocket  (在.pro中添加network)

    2)new出套接字

    3)绑定端口

    4)书写报文,writeDatagram

    5)ReadyRead 监听信号

    6)读取报文

    7)报文长度 qint64 size = udp->pendingDatagramSize();

    8)同步聊天记录

    新建工程:选择“QWidget”,勾选“显示主界面”(默认勾选)

    在.pro中更改:

     1 #-------------------------------------------------
     2 #
     3 # Project created by QtCreator 2020-06-24T08:48:03
     4 #
     5 #-------------------------------------------------
     6 
     7 QT       += core gui network
     8 
     9 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    10 
    11 TARGET = QUdpDemo
    12 TEMPLATE = app
    13 
    14 
    15 SOURCES += main.cpp
    16         udp1.cpp 
    17     udp2.cpp
    18 
    19 HEADERS  += udp1.h 
    20     udp2.h
    21 
    22 FORMS    += udp1.ui 
    23     udp2.ui
    24 
    25 CONFIG += c++11

    udp1.ui中设计界面

    udp1.h中修改如下:

     1 #ifndef UDP1_H
     2 #define UDP1_H
     3 
     4 #include <QWidget>
     5 #include<QUdpSocket>//在.pro中添加network
     6 
     7 namespace Ui {
     8 class Udp1;
     9 }
    10 
    11 class Udp1 : public QWidget
    12 {
    13     Q_OBJECT
    14 
    15 public:
    16     explicit Udp1(QWidget *parent = 0);
    17     ~Udp1();
    18 
    19 private:
    20     Ui::Udp1 *ui;
    21 
    22 public:
    23     //套接字
    24     QUdpSocket* udp;
    25 
    26 };
    27 
    28 #endif // UDP1_H

    udp1.cpp中修改如下:

     1 #include "udp1.h"
     2 #include "ui_udp1.h"
     3 
     4 Udp1::Udp1(QWidget *parent) :
     5     QWidget(parent),
     6     ui(new Ui::Udp1)
     7 {
     8     ui->setupUi(this);
     9 
    10     //初始化属性
    11     ui->myPort->setText("8888");
    12     ui->toPort->setText("9999");
    13     ui->toIp->setText("127.0.0.1");
    14 
    15     //创建套接字
    16     udp = new QUdpSocket(this);
    17 
    18     //绑定自身端口号,QString转int——.toInt()
    19     udp->bind(ui->myPort->text().toInt());
    20 
    21     //点击发送按钮,发送报文
    22     connect(ui->sendBtn,&QPushButton::clicked,[=](){
    23         //书写报文(参数1:内容,参数2:对方Ip,参数3:对方端口)
    24        udp->writeDatagram(ui->input->toPlainText().toUtf8(),QHostAddress(ui->toIp->text()),ui->toPort->text().toInt());
    25     //QString转QByteArray:QString转char*的中间就是转QByteArray——.toUtf8()
    26        ui->record->append("my Say:"+ui->input->toPlainText());
    27 
    28        //清空输入框
    29        ui->input->clear();
    30 
    31     });
    32 
    33     //接收数据
    34     connect(udp,&QUdpSocket::readyRead,[=](){
    35 
    36         //获取报文长度
    37         qint64 size = udp->pendingDatagramSize();
    38 
    39         QByteArray array = QByteArray(size, 0);
    40 
    41         //读取报文
    42         udp->readDatagram(array.data(), size);
    43 
    44         //将数据同步到聊天记录中
    45         ui->record->append(array);
    46 
    47     });
    48 
    49 
    50 
    51 }
    52 
    53 Udp1::~Udp1()
    54 {
    55     delete ui;
    56 }

    添加新文件:Qt—设计师界面类,

    udp2.ui中设计界面:全部拷贝udp1.ui中设计界面

    udp2.h中修改如下:(拷贝udp1.h)

     1 #ifndef UDP2_H
     2 #define UDP2_H
     3 
     4 #include <QWidget>
     5 #include<QUdpSocket>
     6 
     7 
     8 namespace Ui {
     9 class Udp2;
    10 }
    11 
    12 class Udp2 : public QWidget
    13 {
    14     Q_OBJECT
    15 
    16 public:
    17     explicit Udp2(QWidget *parent = 0);
    18     ~Udp2();
    19 
    20 private:
    21     Ui::Udp2 *ui;
    22 
    23 public:
    24     QUdpSocket* udp;
    25 
    26 };
    27 
    28 #endif // UDP2_H

    udp2.cpp中修改如下:(拷贝udp1.cpp)

     1 #include "udp2.h"
     2 #include "ui_udp2.h"
     3 
     4 Udp2::Udp2(QWidget *parent) :
     5     QWidget(parent),
     6     ui(new Ui::Udp2)
     7 {
     8     ui->setupUi(this);
     9 
    10 
    11     //初始化属性
    12     ui->myPort->setText("9999");
    13     ui->toPort->setText("8888");
    14     ui->toIp->setText("127.0.0.1");
    15 
    16     //创建套接字
    17     udp = new QUdpSocket(this);
    18 
    19     //绑定自身端口号
    20     udp->bind(ui->myPort->text().toInt());
    21 
    22     //点击发送按钮,发送报文
    23     connect(ui->sendBtn,&QPushButton::clicked,[=](){
    24         //书写报文(参数1:内容,参数2:对方Ip,参数3:对方端口)
    25        udp->writeDatagram(ui->input->toPlainText().toUtf8(),QHostAddress(ui->toIp->text()),ui->toPort->text().toInt());
    26 
    27        ui->record->append("my Say:"+ui->input->toPlainText());
    28 
    29        //清空输入框
    30        ui->input->clear();
    31 
    32     });
    33 
    34     //接收数据
    35     connect(udp,&QUdpSocket::readyRead,[=](){
    36 
    37         //获取报文长度
    38         qint64 size = udp->pendingDatagramSize();
    39 
    40         QByteArray array = QByteArray(size, 0);
    41 
    42         //读取报文
    43         udp->readDatagram(array.data(), size);
    44 
    45         //将数据同步到聊天记录中
    46         ui->record->append(array);
    47 
    48     });
    49 }
    50 
    51 Udp2::~Udp2()
    52 {
    53     delete ui;
    54 }

    在main.cpp中更改:

     1 #include "udp1.h"
     2 #include <QApplication>
     3 #include"udp2.h"
     4 
     5 int main(int argc, char *argv[])
     6 {
     7     QApplication a(argc, argv);
     8     Udp1 w;
     9     w.show();
    10 
    11     Udp2 u2;
    12     u2.show();
    13 
    14     return a.exec();
    15 }

    3、核心功能——群聊实现

    1)通信套接字

    2)bind(端口,共享地址|断线重连)

    3)获取用户名

    4)sndMsg(枚举(普通聊天,用户进入、离开))

    5)发送3段数据(类型、用户名、具体内容)

    6)书写报文,广播发送

    7)接收:利用数据流,做分段

      解析:第一段(类型);把用户发送的内容追加到聊天记录中

    4、新用户进入

    1)提供新用户进入函数

    2)更新右侧TableWidget

    3)更新聊天记录

    4)更新在线用户人数

    5、用户离开

    1)提供用户处理函数

    2)更新右侧TableWidget

    3)更新聊天记录

    4)更新在线用户人数

    5)在closeEvent事件中,发送用户离开消息

    6)端口套接字断开

    7)离开按钮处理

    6、代码

    dialoglist.h如下:

     1 #ifndef DIALOGLIST_H
     2 #define DIALOGLIST_H
     3 
     4 #include <QWidget>
     5 
     6 namespace Ui {
     7 class DialogList;
     8 }
     9 
    10 class DialogList : public QWidget
    11 {
    12     Q_OBJECT
    13 
    14 public:
    15     explicit DialogList(QWidget *parent = 0);
    16     ~DialogList();
    17 
    18 private:
    19     Ui::DialogList *ui;
    20 
    21     QVector<bool>isShow;
    22 };
    23 
    24 #endif // DIALOGLIST_H

    dialoglist.cpp如下:

     1 #include "dialoglist.h"
     2 #include "ui_dialoglist.h"
     3 #include<QToolButton>
     4 #include"widget.h"
     5 #include<QMessageBox>
     6 
     7 DialogList::DialogList(QWidget *parent) :
     8     QWidget(parent),
     9     ui(new Ui::DialogList)
    10 {
    11     ui->setupUi(this);
    12 
    13     //设置标题
    14     setWindowTitle("MySelfQQ 2020");
    15     //设置图标
    16     setWindowIcon(QPixmap(":/images/qq.png"));
    17 
    18     //准备图标
    19     QList<QString>nameList;
    20     nameList << "水票奇缘" << "忆梦如澜" <<"北京出版人"<<"Cherry"<<"淡然"
    21              <<"娇娇girl"<<"落水无痕"<<"青墨暖暖"<<"无语";
    22 
    23 
    24     QStringList iconNameList; //图标资源列表
    25     iconNameList << "spqy"<< "ymrl" <<"qq" <<"Cherry"<< "dr"
    26                  <<"jj"<<"lswh"<<"qmnn"<<"wy";
    27 
    28     QVector<QToolButton*>vToolBtn;
    29 //    QVector<bool>isShow;
    30 
    31     for(int i = 0; i < 9; i++)
    32     {
    33         //设置头像
    34         QToolButton* btn = new QToolButton;
    35         //设置文字
    36         btn->setText(nameList[i]);
    37         //设置头像
    38         QString str = QString(":/images/%1.png").arg(iconNameList.at(i));
    39         btn->setIcon(QPixmap(str));
    40         //设置头像大小
    41         btn->setIconSize(QPixmap(str).size());
    42         //设置按钮风格,透明
    43         btn->setAutoRaise(true);
    44         //设置文字和图片一起显示
    45         btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    46         //加到垂直布局中
    47         ui->vLayout->addWidget(btn);
    48         //容器保存住9个按钮,方便以后再次操作
    49         vToolBtn.push_back(btn);
    50         //9个标识默认初始化
    51         isShow.push_back(false);
    52 
    53     }
    54 
    55     //对9个按钮,进行添加信号槽
    56     for(int i = 0; i < vToolBtn.size(); i++)
    57     {
    58         connect(vToolBtn[i],&QToolButton::clicked,[=](){
    59             //如果被打开了,就不要再次打开
    60             if(isShow[i])
    61             {
    62                 QString str = QString("%1窗口已经被打开了").arg(vToolBtn[i]->text());
    63                 QMessageBox::warning(this, "警告", str);
    64                 return;
    65             }
    66             isShow[i] = true;
    67 
    68             //弹出聊天对话框
    69             //构造聊天窗口时候,告诉这个窗口他的名字(参数1:顶层方式弹出,参数2:窗口名字)
    70             //注意:Widget构造函数,并没有这两个参数
    71             Widget* widget = new Widget(0,vToolBtn[i]->text());
    72             //设置窗口标题
    73             widget->setWindowTitle(vToolBtn[i]->text());
    74             //设置头像
    75             widget->setWindowIcon(vToolBtn[i]->icon());
    76             //显示窗口
    77             widget->show();
    78 
    79             connect(widget,&Widget::closeWidget,[=](){
    80                 isShow[i] = false;
    81             });
    82 
    83         });
    84 
    85     }
    86 
    87 
    88 
    89 }
    90 
    91 DialogList::~DialogList()
    92 {
    93     delete ui;
    94 }

    widget.h如下:

     1 #ifndef WIDGET_H
     2 #define WIDGET_H
     3 
     4 #include <QWidget>
     5 #include<QUdpSocket>
     6 
     7 namespace Ui {
     8 class Widget;
     9 }
    10 
    11 class Widget : public QWidget
    12 {
    13     Q_OBJECT
    14 
    15 public:
    16     enum MsgType{Msg,UsrEnter,UsrLeft};
    17 
    18 public:
    19     explicit Widget(QWidget *parent, QString name);
    20     ~Widget();
    21 
    22 private:
    23     Ui::Widget *ui;
    24 
    25 signals:
    26     //关闭窗口,发送关闭信息
    27     void closeWidget();
    28 public:
    29     //关闭事件
    30     void closeEvent(QCloseEvent*);
    31 
    32 public:
    33    void sndMsg(MsgType type); //广播UDP消息
    34    void usrEnter(QString username);//处理新用户加入
    35    void usrLeft(QString usrname,QString time); //处理用户离开
    36    QString getUsr(); //获取用户名
    37    QString getMsg(); //获取聊天信息
    38 
    39    void ReceiveMessage();   //接收UDP消息
    40 private:
    41    QUdpSocket * udpSocket; //udp套接字
    42    qint16 port; //端口
    43    QString uName; //用户名
    44 
    45 
    46 
    47 };
    48 
    49 #endif // WIDGET_H

    widget.cpp如下:

      1 #include "widget.h"
      2 #include "ui_widget.h"
      3 #include<QDataStream>
      4 #include<QMessageBox>
      5 #include<QDateTime>
      6 #include<QColorDialog>
      7 #include<QFileDialog>
      8 #include<QTextStream>
      9 
     10 Widget::Widget(QWidget *parent, QString name) :
     11     QWidget(parent),
     12     ui(new Ui::Widget)
     13 {
     14     ui->setupUi(this);
     15 
     16     //初始化操作
     17 
     18     udpSocket = new QUdpSocket(this);
     19     //用户名获取
     20     uName = name;
     21     //端口号
     22     this->port = 9999;
     23 
     24     //绑定端口号,绑定模式(共享地址|断线重连)
     25     udpSocket->bind(this->port,QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
     26 
     27     //发送新用户进入
     28     sndMsg(UsrEnter);
     29 
     30     //点击发送按钮发送消息
     31     connect(ui->sendBtn,&QPushButton::clicked,[=](){
     32         sndMsg(Msg);
     33     });
     34 
     35     //监听别人发送的数据
     36     connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::ReceiveMessage);
     37 
     38     //点击退出按钮,实现关闭窗口
     39     connect(ui->exitBtn,&QPushButton::clicked,[=](){
     40         this->close();
     41     });
     42 
     43 
     44     // //////////////////////辅助功能/////////
     45     //设置字体
     46     connect(ui->fontCbx,&QFontComboBox::currentFontChanged,[=](const QFont &font){
     47         ui->msgTxtEdit->setCurrentFont(font);
     48         ui->msgTxtEdit->setFocus();
     49     });
     50 
     51     //设置字号
     52     void (QComboBox:: * cbxSingal)(const QString &text) = &QComboBox::currentIndexChanged;
     53     connect(ui->sizeCbx,cbxSingal,this,[=](const QString &text){
     54         ui->msgTxtEdit->setFontPointSize(text.toDouble());
     55         ui->msgTxtEdit->setFocus();
     56     });
     57 
     58     //加粗
     59     connect(ui->boldTBtn,&QToolButton::clicked,this,[=](bool checked){
     60         if(checked)
     61         {
     62             ui->msgTxtEdit->setFontWeight(QFont::Bold);
     63         }
     64         else
     65         {
     66             ui->msgTxtEdit->setFontWeight(QFont::Normal);
     67         }
     68         ui->msgTxtEdit->setFocus();
     69     });
     70 
     71     //倾斜
     72     connect(ui->italicTBtn,&QToolButton::clicked,this,[=](bool checked){
     73 
     74         ui->msgTxtEdit->setFontItalic(checked);
     75 
     76         ui->msgTxtEdit->setFocus();
     77     });
     78 
     79     //下划线
     80     connect(ui->underlineTBtn,&QToolButton::clicked,this,[=](bool checked){
     81 
     82         ui->msgTxtEdit->setFontUnderline(checked);
     83 
     84         ui->msgTxtEdit->setFocus();
     85     });
     86 
     87     //文本颜色
     88     connect(ui->colorTBtn,&QToolButton::clicked,this,[=](){
     89         QColor color = QColorDialog::getColor(color,this); //color对象可以在widget.h中定义私有成员
     90         if(color.isValid())
     91         {
     92             ui->msgTxtEdit->setTextColor(color);
     93             ui->msgTxtEdit->setFocus();
     94         }
     95     });
     96 
     97     //保存聊天记录
     98     connect(ui->saveTBtn,&QToolButton::clicked,this,[=](){
     99         if(ui->msgBrowser->document()->isEmpty())
    100         {
    101             QMessageBox::warning(this,"警告","聊天记录为空,无法保存!",QMessageBox::Ok);
    102             return;
    103         }
    104         else
    105         {
    106             QString fName = QFileDialog::getSaveFileName(this,"保存聊天记录","聊天记录","(*.txt)");
    107             if(!fName.isEmpty())
    108             {
    109                 //保存名称不为空,再做保存操作
    110                 QFile file(fName);
    111                 //打开模式追加换行
    112                 file.open(QIODevice::WriteOnly | QFile::Text);
    113 
    114                 QTextStream stream(&file);
    115                 stream << ui->msgBrowser->toPlainText();
    116                 file.close();
    117             }
    118         }
    119     });
    120 
    121     //清空聊天记录
    122     connect(ui->clearTBtn,&QToolButton::clicked,[=](){
    123         ui->msgBrowser->clear();
    124     });
    125 
    126 
    127 }
    128 
    129 //接收UDP消息
    130 void Widget::ReceiveMessage()
    131 {
    132     //拿到数据报文
    133     //获取长度
    134     qint64 size = udpSocket->pendingDatagramSize();
    135 
    136     QByteArray array = QByteArray(size,0);
    137     udpSocket->readDatagram(array.data(),size);
    138 
    139     //解析数据
    140     //第一段:类型,第二段:用户名,第三段:内容
    141     QDataStream stream(&array, QIODevice::ReadOnly);
    142 
    143     int msgType;//读取到类型
    144     QString usrName;//读取到用户名
    145     QString msg;//读取到内容
    146 
    147     //获取当前时间
    148     QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    149 
    150     stream >> msgType;
    151 
    152     switch (msgType) {
    153     case Msg://普通聊天
    154         stream >> usrName >> msg;
    155 
    156         //追加聊天记录
    157         ui->msgBrowser->setTextColor(Qt::blue);
    158         ui->msgBrowser->append("["+ usrName + "]" + time);
    159         ui->msgBrowser->append(msg);
    160 
    161         break;
    162     case UsrEnter:
    163 
    164         stream >> usrName;
    165         usrEnter(usrName);
    166 
    167 
    168         break;
    169     case UsrLeft:
    170         stream >> usrName;
    171         usrLeft(usrName,time);
    172 
    173         break;
    174     default:
    175         break;
    176     }
    177 
    178 
    179 
    180 
    181 
    182 }
    183 
    184 //处理用户离开
    185 void Widget::usrLeft(QString usrname,QString time)
    186 {
    187     //更新右侧TableWidget
    188     bool isEmpty1 = ui->usrTb1Widget->findItems(usrname,Qt::MatchExactly).isEmpty();
    189     if(!isEmpty1)
    190     {
    191         int row = ui->usrTb1Widget->findItems(usrname,Qt::MatchExactly).first()->row();
    192         ui->usrTb1Widget->removeRow(row);
    193 
    194         //追加聊天记录
    195         ui->msgBrowser->setTextColor(Qt::gray);
    196         ui->msgBrowser->append(QString("%1 于 %2 离开").arg(usrname).arg(time));
    197         //在线人数更新
    198         ui->usrNumLb1->setText(QString("在线用户:%1人").arg(ui->usrTb1Widget->rowCount()));
    199 
    200     }
    201 
    202 }
    203 
    204 //处理新用户加入
    205 void Widget::usrEnter(QString usrname)
    206 {
    207 
    208     //更新右侧TableWidget
    209     bool isEmpty = ui->usrTb1Widget->findItems(usrname,Qt::MatchExactly).isEmpty();
    210     if(isEmpty)
    211     {
    212 
    213         QTableWidgetItem* usr = new QTableWidgetItem(usrname);
    214 
    215         //插入行
    216         ui->usrTb1Widget->insertRow(0);
    217         ui->usrTb1Widget->setItem(0,0,usr);
    218 
    219         //追加聊天记录
    220         ui->msgBrowser->setTextColor(Qt::gray);
    221         ui->msgBrowser->append(QString("%1 上线了").arg(usrname));
    222         //在线人数更新
    223         ui->usrNumLb1->setText(QString("在线用户:%1人").arg(ui->usrTb1Widget->rowCount()));
    224 
    225 
    226 
    227         //把自身信息广播出去???
    228         //sndMsg(UsrEnter);
    229 
    230     }
    231 
    232 }
    233 
    234 
    235 
    236 //广播UDP消息
    237 void Widget::sndMsg(MsgType type)
    238 {
    239     //发送的消息分为3种类型
    240     //发送的数据做分段处理:第一段(类型),第二段(用户名),第三段(具体内容)
    241 
    242     QByteArray array;
    243 
    244     QDataStream stream(&array,QIODevice::WriteOnly);
    245 
    246     stream << type << getUsr();//第一段内容添加到流中,第二段(用户名)
    247 
    248     switch (type) {
    249     case Msg: //普通消息发送
    250 
    251         if(ui->msgTxtEdit->toPlainText() == "")//判断如果用户没有输入内容,不发任何消息
    252         {
    253             QMessageBox::warning(this,"警告","发送内容不能为空") ;
    254             return;
    255         }
    256         //第三段数据,具体说的话
    257         stream << getMsg();
    258 
    259         break;
    260     case UsrEnter://新用户进入消息
    261 
    262         break;
    263     case UsrLeft://用户离开消息
    264 
    265         break;
    266 
    267     default:
    268         break;
    269     }
    270 
    271     //书写报文,广播发送(255.255.255.255)
    272     udpSocket->writeDatagram(array,QHostAddress::Broadcast,port);
    273 
    274 
    275 }
    276 
    277 //获取用户名
    278 QString Widget::getUsr()
    279 {
    280     return this->uName;
    281 }
    282 
    283 
    284 //获取聊天信息
    285 QString Widget::getMsg()
    286 {
    287     QString str = ui->msgTxtEdit->toHtml();
    288 
    289     //清空输入框
    290     ui->msgTxtEdit->clear();
    291     ui->msgTxtEdit->setFocus();//让光标定位回输入框
    292 
    293     return str;
    294 }
    295 
    296 
    297 
    298 void Widget::closeEvent(QCloseEvent* e)
    299 {
    300     emit this->closeWidget();
    301 
    302     sndMsg(UsrLeft);
    303     //断开套接字
    304     udpSocket->close();
    305     udpSocket->destroyed();
    306 
    307     QWidget::closeEvent(e);//其他事情交给父类处理
    308 }
    309 
    310 
    311 Widget::~Widget()
    312 {
    313     delete ui;
    314 }

    main.cpp如下:

     1 #include "widget.h"
     2 #include <QApplication>
     3 #include"dialoglist.h"
     4 
     5 
     6 int main(int argc, char *argv[])
     7 {
     8     QApplication a(argc, argv);
     9 //    Widget w;
    10 //    w.show();
    11 
    12     DialogList list;
    13     list.show();
    14 
    15     return a.exec();
    16 }

    注意:

    Qt5.5目前Issue:

    1)进入:对于新进入的用户,新用户列表未更新,加入sndMsg(UsrEnter);会陷入死循环,解决不了!!!
    2)退出:对于最早进入的用户,退出,后来的用户检测不到,列表未更新

    在学习QT总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 相关阅读:
    发音技巧
    SCROM标准和一些概念(转)
    我要告诉测试新手的 (转)
    LCMS与LMS
    SCORM标准的LMS ELearning 学习平台介绍
    【转载】经常在网上看人家的帖子,分享给组里面的兄弟共赏
    选择学习管理系统(LMS)不可忽略的十大要素
    委托(delegate)的使用
    LMS/LCMS相关概念简介
    软件测试
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_QT_04.html
Copyright © 2011-2022 走看看