基于视频的电熔镁炉工况识别系统→6.电熔镁炉服务器设计

基于视频的电熔镁炉工况识别系统→6.电熔镁炉服务器设计

《基于视频的电熔镁炉工况识别系统→6.电熔镁炉服务器设计》


程序目的
总结
  1. 主线程
    1. 当有新的客户端连接时
      1. 显示工况数据表
      2. 读取数据库工况数据
        1. 启动子线程1thread,使能子线程1处理函数isStop= false
        2. 主线程发出信号startThread,用于启动子线程1中处理函数VideoThread::myVideoPlay读取数据
      3. 绘制需量趋势图
        1. 启动绘图子线程2,此时并没有启动子线程2中处理函数,启动子线程2的处理函数的触发信号在子线程1
    2. 子线程1的处理:
      1. 当接收到工况数据信号mySignal(data)时,使用dealSignal槽函数处理一条组包为data的工况数据
      2. 在dealSignal槽函数中:
        1. 显示奇数帧视频图片
        2. 传输数据到客户端
        3. 在消息滚动中播放工况状态
        4. 通过playStopFlag来控制全部数据处理完后的操作
    3. 子线程2的处理:
      1. 当接收到图像数据信号updateImage(image)时,使用getImage槽函数接收一张坐标x轴为11个时间单位图片
      2. 在getImage槽函数中,将图片显示到主界面中
    4. 断开连接按钮:
      1. 关闭子线程
      2. 主动和客户端断开连接
    5. 其他按钮:暂停、继续;加速、减速;
  2. 在子线程1处理函数VideoThread::myVideoPlay
    1. 读取一条工况数据,组包为data,发出mySignal(data)信号
    2. 每25帧获取需量数据到demmandTre数组中一次,每隔11s即11个25帧发送一次绘图信号paintSignal(i),用于启动线程2中处理函数VoltTreThread::myVoltPaint来绘制图像
    3. 其他:
      1. 使用sleepSpeed控制视频播放速度,默认为80,即80ms传输一次数据信号mySignal(data)
        1. 由于显示奇数帧视频图片,因此相当于40ms显示1帧,1s显示25帧原视频帧率
  3. 在子线程2处理函数VoltTreThread::myVoltPaint(int sec)
    1. 每隔11s绘制一张曲线图,并发出updateImage(image)信号
错误赵
  1. 如果void Widget::dealSignal(QString data)中不添加
1
2
3
4
if(tcpSocket==NULL)
    {
        return;
    }
那么在点击断开连接时程序会出错,因为 断开连接后tcpSocket==NULL,但是子线程1还没完全关闭,还会发送工况数据信号mySignal(data)触发dealSignal槽函数,此时针对tcpSocket的write操作会使程序崩溃(2.173)
  1. release下继续播放按钮失效,但debug状态下有反应
    1. 因此在debug模式发布程序
    2. 在debug模式发布程序也是可以的,按照需要手动添加模块就行 参考见Qt补充→添加资源文件以及发布程序



widget.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#ifndef WIDGET_H
#define WIDGET_H

#include <QMainWindow>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlTableModel>
#include <QTcpServer>
#include <QTcpSocket>

#include "videothread.h"
#include "volttrethread.h"
#include <QThread>


namespace Ui {
class Widget;
}

extern QSqlDatabase db;
extern QSqlQuery query;
extern QSqlTableModel *model;

extern bool isStop;//结束和开启子线程1的处理函数
extern int sendSuccess;//每条工况数据传输成功标志
extern bool playStopFlag;//暂停、继续子线程1处理函数
extern int demmandTre[1550];//绘图用到的需量值,使用下标1-1449存储数据
extern int sleepSpeed;//视频播放线程速度控制,默认25帧/s
extern int i;//用于绘图的时间累加器,单位s,每11s传递一次绘图信号

class Widget : public QMainWindow
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    void dealSignal(QString data);//自定义播放视频线程信号处理槽函数
    void getImage(QImage); //自定义绘图线程信号处理槽函数
    void dataFinished();//数据传送完成 or 断开连接

signals:
    void startThread(); //触发视频播放线程处理函数的信号

private slots:
    void on_stopSelcet_clicked();//暂停
    void on_playSelcet_clicked();//继续播放
    void on_accelerateSelcet_clicked();//加速数据传输
    void on_moderateSelcet_clicked();//减速数据传输
    void on_help_clicked();//帮助按钮
    void on_stopConnect_clicked();//停止连接按钮

private:
    Ui::Widget *ui;
    VideoThread *myT;
    QThread *thread;//视频播放子线程

    VoltTreThread *myT2;
    QThread *thread2;//绘图子线程
    QImage image;//保存子线程绘制的图

    QTcpServer *tcpServer; //监听套接字
    QTcpSocket *tcpSocket; //通信套接字

};

#endif // WIDGET_H

widget.cpp
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#include "widget.h"
#include "ui_widget.h"

#include <QPixmap>
#include <QMenuBar>
#include <QMenu>
#include <QMessageBox>
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //===设置标题及页面===
    setWindowTitle("电熔镁炉数据中继服务器");
    setWindowIcon(QIcon(QPixmap(":/image/服务器.bmp")));

    //===设置界面按钮外观===
    ui->playSelcet->setStyleSheet("QPushButton{border-image: url(:/image/播放.bmp);}\
                                  QPushButton:hover{border-image: url(:/image/播放鼠标悬浮.bmp);}");
    ui->stopSelcet->setStyleSheet("QPushButton{border-image: url(:/image/暂停.bmp);}\
                                  QPushButton:hover{border-image: url(:/image/暂停鼠标悬浮.bmp);}");
    ui->accelerateSelcet->setStyleSheet("QPushButton{border-image: url(:/image/加速.bmp);}\
                                        QPushButton:hover{border-image: url(:/image/加速鼠标悬浮.bmp);}");
    ui->moderateSelcet->setStyleSheet("QPushButton{border-image: url(:/image/减速.bmp);}\
                                      QPushButton:hover{border-image: url(:/image/减速鼠标悬浮.bmp);}");
    ui->stopConnect->setStyleSheet("QPushButton{border-image: url(:/image/断开连接.bmp);}\
                                   QPushButton:hover{border-image: url(:/image/断开连接鼠标悬浮.bmp);}");
    ui->help->setStyleSheet("QPushButton{border-image: url(:/image/帮助.bmp);}\
                            QPushButton:hover{border-image: url(:/image/帮助鼠标悬浮.bmp);}");

    //===MenuBar===
    QMenuBar *mBar = menuBar();
    QMenu *pFile = mBar->addMenu("编辑");
    QAction *pNew = pFile->addAction("断开数据传输");
    connect(pNew, &QAction::triggered, this, &Widget::dataFinished);
    QMenu *pFile2 = mBar->addMenu("帮助");
    QAction *pNew2 = pFile2->addAction("关于服务器");
    connect(pNew2, &QAction::triggered,
           [=]()
           {
               QMessageBox::about(this,"关于服务器",\
               QString("<center><h4>服务器端功能</h4></center><BODY>\
                        ---在线工况视频播放<BR>---工况数据表显示<BR>\
                        ---需量趋势图绘制<BR>---数据传输控制(调速、启停)<BR>\
                        ---客户端连接信息显示<BR>---当前工况播报</BODY>"));
           }
           );

    //===数据库===
    //添加数据库连接
    db = QSqlDatabase::addDatabase("QSQLITE","a");
    //设置数据库信息
    db.setDatabaseName("../Resource/database.db");

    //打开数据库
    if(!db.open())
    {
        qDebug() << "Failed to open database1";
    }
    else
    {
        qDebug() << "succeed in opening database1";
    }
    //以下执行相关sql语句
    query = QSqlQuery(db);
    //设置模型,替代QSqlQuery
    model = new QSqlTableModel(this,db);
    //指定数据库表
    model->setTable("sheet1");
    //显示model里的数据
    model->select();

    //===SOCKET===
    tcpSocket = NULL;
    //监听套接字
    tcpServer = new QTcpServer(this);
    //QHostAddress::Any绑定我当前网卡所有的iP 正式监听
    tcpServer->listen(QHostAddress::Any, 8888);
    //如果连接成功,服务器会触发newConnection()
    connect(tcpServer, &QTcpServer::newConnection,
            [=]()
            {
                qDebug() << "服务器被客户端连接!";

                //数据初始化
                sleepSpeed = 80;//视频播放线程速度控制,默认25帧/s
                playStopFlag = true;//暂停、继续子线程1处理函数
                for(int m=0;m<1550;m++)
                {
                    demmandTre[m] = 0;//绘图用到的需量值,使用下标1-1449存储数据
                }
                i = 1;//用于绘图的时间累加器,单位s,每11s传递一次绘图信号

                //==显示工况数据表==
                //把model放在QTabelView组件中
                ui->tableView->setModel(model);
                //设置model的编辑策略:不能编辑
                ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
                ui->tableView->setAlternatingRowColors(true);//奇偶行区分颜色样式

                //==读取数据库工况数据==
                //启动子线程1
                thread->start();
                //使能子线程1处理函数
                isStop = false;
                //主线程发出信号,用于启动子线程1中处理函数来读取数据
                emit startThread();

                //==绘制需量趋势图==
                //启动绘图子线程2
                thread2->start();

                //==显示客户端连接信息==
                //取出队列中建立好连接的通信套接字
                tcpSocket = tcpServer->nextPendingConnection();
                //获取对方(客户端)的IP和端口
                              QString ip = tcpSocket->peerAddress().toString();
                              qint16 port = tcpSocket->peerPort();
                              QString temp = QString("<BR><BR><BR><center><h3>客户端[%1:%2]\
                                                成功连接</h3></center>").arg(ip).arg(port);
                              ui->textEditRead->setText(temp);
                connect(tcpSocket, &QTcpSocket::readyRead,
                        [=]()
                        {
                            QByteArray array = tcpSocket->readAll();
                            ui->textEditRead->append(array);
                        }
                        );
            }
            );

    //===子线程1处理===
    myT = new VideoThread;
    thread = new QThread(this);
    myT->moveToThread(thread);
    connect(this, &Widget::startThread, myT, &VideoThread::myVideoPlay);
    connect(myT, &VideoThread::mySignal, this, &Widget::dealSignal);

    //===子线程2处理===
    myT2 = new VoltTreThread;
    thread2 =new QThread(this);
    myT2->moveToThread(thread2);
    connect(myT,&VideoThread::paintSignal,myT2,&VoltTreThread::myVoltPaint);
    connect(myT2,&VoltTreThread::updateImage,this,&Widget::getImage);
}


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

//接收线程1中的一条组包为data的工况数据并处理
void Widget::dealSignal(QString data)
{
    //在新的连接被建立时,才可以取出队列中建立好连接的通信套接字
    //在此之前,tcpSocket仅是个没有指向的指针,因此执行tcpSocket操作会出错
    if(tcpSocket==NULL)
    {
        return;
    }
    int frame = data.section("b",0,0).toInt();
    //显示奇数帧视频图片
    if(frame%2 != 0)
    {
       ui->videoPlay->setPixmap(QPixmap(QString("../Resource/videoPictureWhole/%1.jpg").arg(frame)));
       ui->videoPlay->setScaledContents(true);
    }
    //传输数据到客户端
    sendSuccess = tcpSocket->write( data.toUtf8() );
    while(sendSuccess==-1)
    {
       QMessageBox::warning(this,"警告","发送失败,请关闭此次连接建立新连接");
    }
    //显示工况状态
    switch (data.section("b",5,5).toInt()) {
    case 1:
       ui->messageScroll->setText(QString("<BR><BR><BR><center><h3>当前数据\
        传送到第 %1 帧<br>状态:火焰形态稳定、颜色明亮</h3></center>").arg(frame));
       break;
    case 2:
       ui->messageScroll->setText(QString("<BR><BR><BR><center><h3>当前数据\
        传送到第 %1 帧<br>状态:火焰面积明显小于正常熔炼及欠烧的火焰面积,\
        火焰颜色发暗</h3></center>").arg(frame));
       break;
    case 3:
       ui->messageScroll->setText(QString("<BR><BR><BR><center><h3>当前数据\
        传送到第 %1 帧<br>状态:亮度持续增加,火焰可视区域覆盖整个炉口</h3></center>").arg(frame));
       break;
    case 4:
       ui->messageScroll->setText(QString("<BR><BR><BR><center><h3>当前数据\
        传送到第 %1 帧<br>状态:炉口有火星溅出</h3></center>").arg(frame));
       break;
    case 5:
       ui->messageScroll->setText(QString("<BR><BR><BR><center><h3>当前数据\
       传送到第 %1 帧<br>状态:亮度相对正常工况偏低</h3></center>").arg(frame));
       break;
    default:
       break;
    }
    //全部数据处理完后的操作
    if (frame == 36233)
    {
       //暂停子线程1处理函数
       playStopFlag = false;

    //       int ret = QMessageBox::question(this,"提示","全部数据已经传输完成,\
       是否要继续重新传送数据?",
    //                             QMessageBox::Ok|QMessageBox::Cancel);
       int ret = QMessageBox::Ok;
       switch (ret) {
       case QMessageBox::Ok:
           //继续子线程1处理函数,再读一遍工况数据
           playStopFlag = true;
           break;
       case QMessageBox::Cancel:
           Widget::dataFinished();
           break;
       default:
           break;
       }
    }
}
//将在线程2中绘制的图片显示到主界面中
void Widget::getImage(QImage temp)
{
    ui->voltageTrend->setPixmap(QPixmap::fromImage(temp));
    ui->voltageTrend->setScaledContents(true);
}

//断开连接
void Widget::dataFinished()
{
    //在新的连接被建立时,才可以取出队列中建立好连接的通信套接字
    //在此之前,tcpSocket仅是个没有指向的指针,因此执行tcpSocket操作会出错
    if(tcpSocket==NULL)
    {
        return;
    }
    //关闭子线程
    isStop = true;//结束子线程1的处理函数
    thread->terminate();//结束子线程1
//    thread->wait();
    thread2->terminate();//结束子线程2
//    thread2->wait();

    //主动和客户端断开连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
    tcpSocket = NULL;

    //关闭提示
    ui->videoPlay->setPixmap(QPixmap(":/image/出错了.bmp"));
    ui->voltageTrend->clear();
    ui->textEditRead->setText("<center><h3>连接已经断开</h3></center>");
    ui->messageScroll->setText("<center><h3>连接已经断开</h3></center>");
    ui->tableView->setModel(new QSqlTableModel(this));
    model->select();//不显示数据
}

//暂停
void Widget::on_stopSelcet_clicked()
{
    playStopFlag = false;
}
//继续播放
void Widget::on_playSelcet_clicked()
{
    playStopFlag = true;
}

//数据加速传输
void Widget::on_accelerateSelcet_clicked()
{
    if(sleepSpeed != 80)
    {
        sleepSpeed -= 80;
    }
    else
    {
        QMessageBox::about(this,"警告","速度已经到达最大!!!");

    }
}
//数据减速传输
void Widget::on_moderateSelcet_clicked()
{
    if(sleepSpeed != 480)
    {
        sleepSpeed += 80;
    }
    else
    {
        QMessageBox::about(this,"警告","速度已经是最小!!!");
    }
}
//帮助按钮
void Widget::on_help_clicked()
{
    QMessageBox::about(this,"关于服务器",\
                       QString("<center><h4>服务器端功能</h4></center><BODY>\
                                ---在线工况视频播放<BR>---工况数据表显示<BR>\
                                ---需量趋势图绘制<BR>---数据传输控制(调速、启停)<BR>\
                                ---客户端连接信息显示<BR>---当前工况播报</BODY>"));
}
//停止按钮
void Widget::on_stopConnect_clicked()
{
    dataFinished();
}

videothread.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#ifndef VideoThread_H
#define VideoThread_H
#include <QObject>
#include <QSqlQuery>

extern QSqlQuery query;

extern bool isStop;//结束和开启子线程1的处理函数
extern int sendSuccess;//每条工况数据传输成功标志
extern bool playStopFlag;//暂停、继续子线程1处理函数标志
extern int demmandTre[1550];//绘图的时候按秒计时
extern int sleepSpeed;//视频播放线程速度控制,默认25帧/s
extern int i;//用于绘图的时间累加器,单位s,每11s传递一次绘图信号

class VideoThread : public QObject
{
    Q_OBJECT
public:
    explicit VideoThread(QObject *parent = 0);

    //线程处理函数
    void myVideoPlay();
    //工况数据
    int frame;//36233帧
    double current1;
    double current2;
    double current3;
    int voltage;
    int label;
    int demand;

signals:
    void mySignal(QString data);//播放视频信号
    void paintSignal(int sec);//画图信号 每秒画一次图

private:

public slots:
};

#endif // VideoThread_H

videothread.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "videothread.h"
#include <QVariant>
#include <QThread>
#include <QDebug>

VideoThread::VideoThread(QObject *parent) : QObject(parent)
{

}

void VideoThread::myVideoPlay()
{
    while(!isStop)
    {
        query.exec("select * from sheet1");
        //query.next()指向查找到的第一条记录,然后每次后移一条记录
        while (query.next())
        {
            //读取数据库每一行的工况数据
            frame = query.value(0).toInt();
            current1 = query.value(1).toDouble();
            current2 = query.value(2).toDouble();
            current3 = query.value(3).toDouble();
            voltage = query.value(4).toInt();
            label = query.value(5).toInt();
            demand = query.value(6).toDouble();
            //b:每个特征的间隔 break;bw:每帧的间隔 break widely
            QString data = QString("%1b%2b%3b%4b%5b%6b%7bw")\
                    .arg(frame).arg(current1).arg(current2)\
                    .arg(current3).arg(voltage).arg(label).arg(demand);

            emit mySignal(data);
            //如果工况数据发送失败,停止子线程1处理函数来停止读取数据
            while (sendSuccess == -1)
            {
                isStop = true;
            }

            //获取需量数据到demmandTre数组中,每隔11s发送一次绘图信号
            if(frame>24)
            {
                //总共36233帧,当读取到1449×25=36225时
                //demmandTre的[1~1449]被赋值
                if(frame%25==0 && frame<=36225)
                {
                    demmandTre[i] = demand;
                    if (i==1449)
                    {
                        i = 1;
                    }
                    //每隔11s发送一次绘图信号,最后一次是i=1441
                    if (i%11 == 0)
                    {
                        emit paintSignal(i);
                    }
                    i++;
                }
            }
            //由于帧数太多,80ms显示奇数帧
            QThread::msleep(sleepSpeed);
            //暂停、继续子线程1处理函数
            while(!playStopFlag)
            {
                ;
            }
        }
    }
}

volttrethread.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef VoltTreThread_H
#define VoltTreThread_H

#include <QObject>
#include <QImage>

extern int demmandTre[1550];//绘图用到的需量值,使用下标1-1449存储数据

class VoltTreThread : public QObject
{
    Q_OBJECT
public:
    explicit VoltTreThread(QObject *parent = 0);
    //子线程2处理函数
    void myVoltPaint(int sec);

signals:
    void updateImage(QImage temp);

public slots:
};

#endif // VoltTreThread_H

volttrethread.cpp
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "VoltTreThread.h"
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QDebug>
#include <QThread>

VoltTreThread::VoltTreThread(QObject *parent) : QObject(parent)
{

}
//每隔11s才被触发一次,因此坐标x轴为11个时间单位(s)
void VoltTreThread::myVoltPaint(int sec)
{
    //定义QImage绘图设备
    QImage image(1100, 300, QImage::Format_ARGB32);//QImage::Format_ARGB32背景是透明
    //填充背景为黑色
    image.fill(Qt::black);
    //定义画家,指定绘图设备
    QPainter p(&image);
    //设置字体
    p.setFont(QFont("Times New Roman",14,50));//字体类型、大小、粗细
    //相对画布为1200×300的画布确定图像位置
    int pointx=100,pointy=250;//确定坐标轴起点坐标
    int width=960,height=230;//确定坐标轴宽度跟高度

    //绘制坐标框架
    QPen pen;
    pen.setColor(Qt::white);
    p.setPen(pen);
    p.drawRect(10,5,1080,290);//外围的矩形
    p.drawLine(pointx,pointy,width+pointx,pointy);
    p.drawLine(pointx,pointy-height,pointx,pointy);

    //绘制需量曲线 ,需量最大值为3.7722e+03 最小值为2.7234e+03
    double kx=(double)width/(10); //x轴的比例系数 9.6
    double ky=(double)height/(10);//y方向的比例系数 2.3
    pen.setColor(Qt::green);//画曲线的笔
    pen.setWidth(2);
    QPen penPoint;//描点的笔
    penPoint.setColor(Qt::white);
    penPoint.setWidth(5);
    p.setRenderHint(QPainter::Antialiasing);
    for(int k=sec-10;k<sec;k++)//1→10 12→21 23→32
    {
        //由于y轴是倒着的,所以y轴坐标要pointy-demmandTre[i]*ky 其中ky为比例系数
        //曲线绘制
        p.setPen(pen);
        p.drawLine(pointx+kx*(k-(sec-10)),pointy-(demmandTre[k]-2500)/150*ky,pointx+kx*(1+k-(sec-10)),pointy-(demmandTre[k+1]-2500)/150*ky);
        //描点显示
        p.setPen(penPoint);
        p.drawPoint(pointx+kx*(k-(sec-10)),pointy-(demmandTre[k]-2500)/150*ky);
    }
    p.drawPoint(pointx+kx*(sec-(sec-10)),pointy-(demmandTre[sec]-2500)/150*ky);//绘制最后一个点

    //绘制刻度线
    QPen penDegree,penDegree2;
    penDegree.setWidth(1);
    penDegree.setColor(Qt::green);
    penDegree.setStyle(Qt::DotLine);//绘制内部的绿点网格
    penDegree2.setWidth(2);
    penDegree2.setColor(Qt::white);
    penDegree2.setStyle(Qt::SolidLine);//最上、右边的线是白实线
    p.setPen(penDegree);
    //x轴刻度线
    double xInterval = (double)10/10;//x轴刻度间隔为1
    for(int i=-1;i<9;i++)//画10条(不算原点),最后一条在for外边
    {
        //选取合适的坐标,绘制一段长度为width的直线,用于表示刻度
        p.drawLine(pointx+(i+1)*width/10,pointy,pointx+(i+1)*width/10,pointy-height);
        p.setPen(penDegree2);
        p.drawText(pointx+(i+1)*width/10,
                         pointy+15,QString::number((int)(xInterval*(sec-9+i))));
        p.setPen(penDegree);
    }
    p.setPen(penDegree2);
    p.drawLine(pointx+(9+1)*width/10,pointy,pointx+(9+1)*width/10,pointy-height);
    p.drawText(pointx+(9+1)*width/10,
                     pointy+15,QString::number((int)(xInterval*(sec))));
    //y轴刻度线
    p.setPen(penDegree);
    double yInterval = (double)1500/10;//y轴刻度间隔150
    for(int j=0;j<9;j++)
    {
        //代码较长,但是掌握基本原理即可。
        //主要就是确定一个位置,然后画一条短短的直线表示刻度。
        p.drawLine(pointx,pointy-(j+1)*height/10,
                         pointx+width,pointy-(j+1)*height/10);
        p.setPen(penDegree2);
        p.drawText(pointx-40,pointy-(j+1)*height/10,
                         QString::number((int)(yInterval*(j+1)+2500)));
        p.setPen(penDegree);
    }
    p.setPen(penDegree2);
    p.drawLine(pointx,pointy-(9+1)*height/10,
                     pointx+width,pointy-(9+1)*height/10);
    p.drawText(pointx-40,pointy-(9+1)*height/10,
                     QString::number((int)(yInterval*(9+1)+2500)));
    //坐标名称:(横轴:Times;纵轴:Demand(KW))
    p.setFont(QFont("Times New Roman",14,75));
    p.drawText(pointx+(4+1)*width/10-15,
                     pointy+30,QString("Time(s)"));
    p.drawText(pointx-70,pointy-(7+1)*height/10,
                     QString("D"));
    p.drawText(pointx-70,pointy-(6+1)*height/10,
                     QString("e"));
    p.drawText(pointx-70,pointy-(5+1)*height/10,
                     QString("m"));
    p.drawText(pointx-70,pointy-(4+1)*height/10,
                     QString("a"));
    p.drawText(pointx-70,pointy-(3+1)*height/10,
                     QString("n"));
    p.drawText(pointx-70,pointy-(2+1)*height/10,
                     QString("d"));
    p.drawText(pointx-86,pointy-(1+1)*height/10,
                     QString("(KW)"));

    emit updateImage(image);

}


Show 运行结果
  1. 下图是运行后的界面

  1. 当有客户端连接时,会播放视频,显示工况数据表、需量趋势图



posted on 2018-10-18 14:36 LeisureZhao 阅读(...) 评论(...) 编辑 收藏

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值