一、說明:
在實際項目中,主要是使用Qt開發CS程序,當然主要是客戶端。公司項目中有這個需求是實時顯示多個設備的流量曲線圖,設備將流量信息發給服務端,服務端再將信息通過Socket發給Qt客戶端,Qt客戶端通過Socket接收後實時顯示在程序的一個窗口上;這個顯示是以曲線圖的展示方式。
二、界面模型
接到這個功能需求後,使用的界面模型如下圖所示,圖示已經標示的很清楚了,我就不多詳細描述了:
三、功能分析
1、由於設備較多,超過100台,所以不可能每個設備的流量曲線都用一種顏色,因此只選擇幾種比較明顯的顏色作為設備的流量曲線顏色,每次上來一個設備,就用其中的一種顏色繪制曲線。
2、使用QSS來設置部件的樣式信息,如前景、背景、被選擇時、鼠標移動時等等。
3、用一個部件用作專門的繪制部件,該部件放在窗口中,因此安裝事件過濾器,用於重繪子部件信息,繪制曲線圖。
4、處理設備上線/下線的網絡消息以及設備主動發送的動態流量信息;處理Qt客戶端與服務端的連接/斷開事件。
四、界面效果
開發出來的最終效果圖如下所示:
初始所有設備的流量圖如下圖
選擇設備名為a5的流量圖,其中a5設備的流量曲線加粗,背景半透明等效果如下圖
選擇設備名為a7的流量圖,其中a7設備的流量曲線加粗,背景半透明等效果如下圖
五、主要代碼
1 //消息過濾,主要用於重繪子控件,過濾Paint事件 2 bool QAPRTCurWidget::eventFilter(QObject *watched, QEvent *event) 3 { 4 if(watched==ui->widget_rxtx && event->type()==QEvent::Paint) 5 { 6 updateWidgetRTX(); 7 } 8 return QFrame::eventFilter(watched,event); 9 }
1 //繪圖操作 2 void QAPRTCurWidget::updateWidgetRTX() 3 { 4 QPainter painter(ui->widget_rxtx); 5 painter.setFont(QFont("Times", 12, QFont::Bold)); 6 //繪制背景顏色 7 painterBackground(painter); 8 //畫最左邊一條虛線,用於和List隔開 9 painterLeftDashLine(painter); 10 //畫縱坐標文本標識 11 updateVTextID(painter); 12 //畫縱坐標文本刻度以及橫縱坐標軸 13 updateVTextMarkAndCoord(painter); 14 //畫RX曲線 15 paintRXLineInfo(painter); 16 //畫TX曲線 17 paintTXLineInfo(painter); 18 }
1 //畫縱坐標文本刻度以及橫縱坐標軸 2 void QAPRTCurWidget::updateVTextMarkAndCoord(QPainter &painter) 3 { 4 painter.save(); 5 //繪圖區間的實際高度(部件高度-頂部間隔-底部間隔) 6 int nActPaintHeight = ui->widget_rxtx->height()-INTERVAL_WIDGET_TOP-INTERVAL_WIDGET_BOTTOM; 7 //每隔的間隔高度 8 float fIntervalHeight = ((float)nActPaintHeight)/(m_nVSingleLinePointCount-1); 9 float fYPointForZero = ui->widget_rxtx->height()-INTERVAL_WIDGET_BOTTOM; 10 double dDivideValue = 0; 11 if(ui->toolButton_rxflow->isChecked()) 12 { 13 dDivideValue = ((double)nRXMaxValue)/(m_nVSingleLinePointCount-1); 14 } 15 if(ui->toolButton_txflow->isChecked()) 16 { 17 dDivideValue = ((double)nTXMaxValue)/(m_nVSingleLinePointCount-1); 18 } 19 for(int nIndex=0;nIndex<m_nVSingleLinePointCount;++nIndex) 20 { 21 //設置文本顏色 22 painter.setPen(TEXTCOLOR_WIDGET_PAINT); 23 //將原來的字體變小,設置為8 24 QFont objFont = painter.font(); 25 objFont.setPointSize(8); 26 painter.setFont(objFont); 27 //畫文本,加3的目的是為了是其和橫線能保持中間持平 28 painter.drawText(INTERVAL_VMARK_LEFT,fYPointForZero-nIndex*fIntervalHeight+3,QCommonOP::getKMStrForBit(dDivideValue*nIndex)); 29 //設置橫線顏色 30 painter.setPen(COORDCOLOR_WIDGET_PAINT); 31 //畫橫線(第一條和最後一條為實線,中間的為虛線) 32 QPen objPen = painter.pen(); 33 if(0==nIndex || (m_nVSingleLinePointCount-1)==nIndex) 34 { 35 objPen.setStyle(Qt::SolidLine); 36 } 37 else 38 { 39 objPen.setStyle(Qt::DashLine); 40 } 41 painter.setPen(objPen); 42 float x1 = ui->widget_rxtx->width()-INTERVAL_WIDGET_RIGHT; 43 float y1 = fYPointForZero-nIndex*fIntervalHeight; 44 painter.drawLine(INTERVAL_HCOORD_LEFT,fYPointForZero-nIndex*fIntervalHeight,x1,y1); 45 } 46 int nActPaintWidth = ui->widget_rxtx->width()-INTERVAL_HCOORD_LEFT-INTERVAL_WIDGET_RIGHT; 47 //每隔的間隔高度--橫向:注意使用(float)nActPaintWidth)作為分子,即浮點數 48 float fIntervalWidth = ((float)nActPaintWidth)/(m_nHSingleLinePointCount-1); 49 for(int nIndex=0;nIndex<m_nHSingleLinePointCount;++nIndex) 50 { 51 QPen objPen = painter.pen(); 52 if(0==nIndex || (m_nHSingleLinePointCount-1)==nIndex) 53 { 54 objPen.setStyle(Qt::SolidLine); 55 } 56 else 57 { 58 objPen.setStyle(Qt::DashLine); 59 } 60 painter.setPen(objPen); 61 int nXPoint = INTERVAL_HCOORD_LEFT+nIndex*fIntervalWidth; 62 painter.drawLine(nXPoint,INTERVAL_WIDGET_TOP,nXPoint,ui->widget_rxtx->height()-INTERVAL_WIDGET_BOTTOM); 63 } 64 painter.restore(); 65 }