File indexing completed on 2024-05-12 15:53:54
0001 /** 0002 * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * This program is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU General Public License as 0008 * published by the Free Software Foundation; either version 2 of 0009 * the License, or (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "mainwindow.h" 0021 #include "framewidget.h" 0022 0023 #include <KChartChart> 0024 #include <KChartAbstractCoordinatePlane> 0025 #include <KChartLineDiagram> 0026 #include <KChartLineAttributes> 0027 #include <KChartTextAttributes> 0028 #include <KChartDataValueAttributes> 0029 #include <KChartThreeDLineAttributes> 0030 #include <KChartMarkerAttributes> 0031 #include <KChartFrameAttributes> 0032 #include <KChartBackgroundAttributes> 0033 #include <KChartLegend> 0034 0035 #include <QDebug> 0036 #include <QPainter> 0037 #include <QTime> 0038 #include <QElapsedTimer> 0039 0040 using namespace KChart; 0041 0042 static QPixmap drawIntoPixmap( const QSize& size, KChart::Chart* chart ) 0043 { 0044 QPixmap pix( size ); 0045 pix.fill( Qt::white ); 0046 QPainter painter( &pix ); 0047 chart->paint( &painter, QRect( 0, 0, size.width(), size.height() ) ); 0048 return pix; 0049 } 0050 0051 // When set, this example uses FrameWidget which uses Chart::paint to paint itself. 0052 // When not set, this example uses a Chart widget directly. 0053 #define USE_FRAME_WIDGET 1 0054 0055 0056 MainWindow::MainWindow( QWidget* parent ) : 0057 QWidget( parent ) 0058 { 0059 0060 setupUi( this ); 0061 0062 connect( lineTypeCB, SIGNAL(currentIndexChanged(QString)), this, SLOT(setLineType(QString)) ); 0063 connect( paintLegendCB, SIGNAL(toggled(bool)), this, SLOT(setLegendVisible(bool)) ); 0064 connect( paintValuesCB, SIGNAL(toggled(bool)), this, SLOT(setValuesVisible(bool)) ); 0065 connect( paintMarkersCB, SIGNAL(toggled(bool)), this, SLOT(setMarkersVisible(bool)) ); 0066 connect( markersStyleCB, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMarkers()) ); 0067 connect( markersWidthSB, SIGNAL(valueChanged(int)), this, SLOT(updateMarkersHeight()) ); 0068 connect( markersHeightSB, SIGNAL(valueChanged(int)), this, SLOT(updateMarkersWidth()) ); 0069 connect( displayAreasCB, SIGNAL(toggled(bool)), this, SLOT(updateAreas(bool)) ); 0070 connect( transparencySB, SIGNAL(valueChanged(int)), this, SLOT(updateAreasTransparency()) ); 0071 connect( zoomFactorSB, SIGNAL(valueChanged(double)), this, SLOT(setZoomFactor(qreal)) ); 0072 connect( hSBar, SIGNAL(valueChanged(int)), this, SLOT(setHPos(int)) ); 0073 connect( vSBar, SIGNAL(valueChanged(int)), this, SLOT(setVPos(int)) ); 0074 connect( savePB, SIGNAL(clicked()), this, SLOT(saveChart()) ); 0075 0076 QHBoxLayout* chartLayout = new QHBoxLayout( chartFrame ); 0077 #ifdef USE_FRAME_WIDGET 0078 FrameWidget* chartFrameWidget = new FrameWidget(); 0079 chartLayout->addWidget( chartFrameWidget ); 0080 #endif 0081 hSBar->setVisible( false ); 0082 vSBar->setVisible( false ); 0083 0084 m_model.loadFromCSV( ":/empty" ); 0085 0086 // Set up the diagram 0087 m_lines = new LineDiagram(); 0088 0089 m_lines->setModel( &m_model ); 0090 0091 CartesianAxis *xAxis = new CartesianAxis( m_lines ); 0092 CartesianAxis *yAxis = new CartesianAxis ( m_lines ); 0093 CartesianAxis *axisTop = new CartesianAxis ( m_lines ); 0094 CartesianAxis *axisRight = new CartesianAxis ( m_lines ); 0095 xAxis->setPosition ( KChart::CartesianAxis::Bottom ); 0096 yAxis->setPosition ( KChart::CartesianAxis::Left ); 0097 axisTop->setPosition( KChart::CartesianAxis::Top ); 0098 axisRight->setPosition( KChart::CartesianAxis::Right ); 0099 0100 m_lines->addAxis( xAxis ); 0101 m_lines->addAxis( yAxis ); 0102 m_lines->addAxis( axisTop ); 0103 m_lines->addAxis( axisRight ); 0104 0105 m_chart = new Chart(); 0106 //m_chart->setGlobalLeading(10,10,10,10); // by default there is no leading 0107 0108 #ifdef USE_FRAME_WIDGET 0109 chartFrameWidget->setChart( m_chart ); 0110 // make sure, we re-draw after changing one of the chart's properties 0111 connect( m_chart, SIGNAL(propertiesChanged()), 0112 chartFrameWidget, SLOT(update()) ) ; 0113 #else 0114 chartLayout->addWidget( m_chart ); 0115 #endif 0116 0117 m_chart->coordinatePlane()->replaceDiagram( m_lines ); 0118 0119 for ( int iColumn = 0; iColumn<m_lines->model()->columnCount(); ++iColumn ) { 0120 QPen pen(m_lines->pen( iColumn )); 0121 pen.setWidth(4); 0122 m_lines->setPen( iColumn, pen ); 0123 } 0124 0125 FrameAttributes faChart( m_chart->frameAttributes() ); 0126 faChart.setVisible( true ); 0127 faChart.setPen( QPen(QColor(0x60,0x60,0xb0), 8) ); 0128 m_chart->setFrameAttributes( faChart ); 0129 0130 BackgroundAttributes baChart( m_chart->backgroundAttributes() ); 0131 baChart.setVisible( true ); 0132 baChart.setBrush( QColor(0xd0,0xd0,0xff) ); 0133 m_chart->setBackgroundAttributes( baChart ); 0134 0135 // Set up the legend 0136 m_legend = new Legend( m_lines, m_chart ); 0137 0138 m_legend->setPosition( Position::South ); 0139 m_legend->setAlignment( Qt::AlignRight ); 0140 m_legend->setShowLines( false ); 0141 m_legend->setTitleText( QStringLiteral( "Legend" ) ); 0142 m_legend->setOrientation( Qt::Horizontal ); 0143 0144 // setting the legend frame and background to the same color: 0145 const QColor legendColor(0xff,0xe0,0x80); 0146 FrameAttributes faLegend( m_legend->frameAttributes() ); 0147 faLegend.setVisible( true ); 0148 faLegend.setPen( QPen(legendColor, 1) ); 0149 m_legend->setFrameAttributes( faLegend ); 0150 0151 BackgroundAttributes baLegend( m_legend->backgroundAttributes() ); 0152 baLegend.setVisible( true ); 0153 baLegend.setBrush( legendColor ); 0154 m_legend->setBackgroundAttributes( baLegend ); 0155 0156 m_chart->addLegend( m_legend ); 0157 0158 // for illustration we paint the same chart at different sizes: 0159 QSize size1 = QSize( 200, 200 ); 0160 QSize size2 = QSize( 800, 800 ); 0161 m_pix1 = drawIntoPixmap( size1, m_chart ); 0162 m_pix2 = drawIntoPixmap( size2, m_chart ); 0163 m_pix2 = m_pix2.scaled( size1 ); 0164 0165 m_smallChart1 = new QLabel( this ); 0166 m_smallChart1->setWindowTitle( "200x200" ); 0167 m_smallChart1->setPixmap( m_pix1 ); 0168 m_smallChart1->setFixedSize( m_pix1.size() ); 0169 m_smallChart1->move( width() - m_pix1.width()*2, 0170 height()/2 - m_pix1.height()-5 ); 0171 m_smallChart1->show(); 0172 0173 m_smallChart2 = new QLabel( this ); 0174 m_smallChart2->setWindowTitle( "800x800 scaled down" ); 0175 m_smallChart2->setPixmap( m_pix2 ); 0176 m_smallChart2->setFixedSize( m_pix2.size() ); 0177 m_smallChart2->move( width() - m_pix2.width()*2, 0178 height()/2 + 5 ); 0179 m_smallChart2->show(); 0180 0181 faChart.setPen( QPen(QColor(0xb0,0xb0,0xff), 8) ); 0182 m_chart->setFrameAttributes( faChart ); 0183 0184 // initialize attributes; this is necessary because we need to enable data value attributes before 0185 // any of them (e.g. only markers) can be displayed. but if we enable data value attributs, a default 0186 // data value text is included, even if we only wanted to set markers. so we enable DVA and then 0187 // individually disable the parts we don't want. 0188 setValuesVisible( false ); 0189 setMarkersVisible( false ); 0190 } 0191 0192 void MainWindow::updateData(QString data) 0193 { 0194 QElapsedTimer t; 0195 t.start(); 0196 0197 m_model.loadFromCSV( data ); 0198 0199 qDebug("Time for loading data %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0200 t.restart(); 0201 0202 QSize size1 = QSize( 200, 200 ); 0203 QSize size2 = QSize( 800, 800 ); 0204 m_pix1 = drawIntoPixmap( size1, m_chart ); 0205 m_pix2 = drawIntoPixmap( size2, m_chart ); 0206 0207 qDebug("Time for drawing pixmap %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0208 t.restart(); 0209 0210 m_lines->setModel( &m_model ); 0211 0212 qDebug("Time for setting model %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0213 t.restart(); 0214 0215 m_smallChart1->setPixmap( m_pix1 ); 0216 m_smallChart2->setPixmap( m_pix2 ); 0217 0218 m_smallChart1->show(); 0219 m_smallChart2->show(); 0220 0221 qDebug("Time for setting pixmap %s: %lld ms", data.toLatin1().constData(), t.elapsed()); 0222 t.restart(); 0223 0224 } 0225 0226 void MainWindow::setLineType( const QString & text ) 0227 { 0228 if ( text == "Normal" ) 0229 m_lines->setType( LineDiagram::Normal ); 0230 else if ( text == "Stacked" ) 0231 m_lines->setType( LineDiagram::Stacked ); 0232 else if ( text == "Percent" ) 0233 m_lines->setType( LineDiagram::Percent ); 0234 else 0235 qWarning (" Does not match any type"); 0236 } 0237 0238 void MainWindow::setLegendVisible(bool visible ) 0239 { 0240 KChart::Legend* legend = m_chart->legend(); 0241 if ( visible != ( legend != nullptr ) ) { 0242 if ( visible ) 0243 m_chart->addLegend( m_legend ); 0244 else 0245 m_chart->takeLegend( legend ); 0246 } 0247 } 0248 0249 void MainWindow::setValuesVisible(bool visible ) 0250 { 0251 const int colCount = m_lines->model()->columnCount(); 0252 for ( int iColumn = 0; iColumn<colCount; ++iColumn ) { 0253 DataValueAttributes a = m_lines->dataValueAttributes( iColumn ); 0254 a.setVisible( true ); 0255 0256 TextAttributes ta = a.textAttributes(); 0257 ta.setRotation( 0 ); 0258 ta.setFont( QFont( "Comic", 10 ) ); 0259 ta.setPen( m_lines->brush( iColumn ).color() ); 0260 ta.setVisible( visible ); 0261 0262 a.setTextAttributes( ta ); 0263 m_lines->setDataValueAttributes( iColumn, a); 0264 } 0265 } 0266 0267 0268 void MainWindow::setMarkersVisible( bool visible ) 0269 { 0270 paintMarkers( visible, QSize() ); 0271 } 0272 0273 void MainWindow::updateMarkers() 0274 { 0275 setMarkersVisible( paintMarkersCB->isChecked() ); 0276 } 0277 0278 void MainWindow::updateMarkersHeight() 0279 { 0280 markersHeightSB->setValue( markersWidthSB->value() ); 0281 updateMarkers(); 0282 } 0283 0284 void MainWindow::updateMarkersWidth() 0285 { 0286 markersWidthSB->setValue( markersHeightSB->value() ); 0287 updateMarkers(); 0288 } 0289 0290 void MainWindow::updateAreas( bool visible ) 0291 { 0292 const int colCount = m_lines->model()->columnCount(); 0293 for ( int iColumn = 0; iColumn<colCount; ++iColumn ) { 0294 LineAttributes la( m_lines->lineAttributes( iColumn ) ); 0295 la.setDisplayArea( visible ); 0296 if ( visible ) 0297 la.setTransparency( transparencySB->value() ); 0298 m_lines->setLineAttributes( iColumn, la ); 0299 } 0300 } 0301 0302 void MainWindow::updateAreasTransparency() 0303 { 0304 if ( !displayAreasCB->isChecked() ) 0305 displayAreasCB->setChecked( true ); 0306 else 0307 updateAreas( true ); 0308 } 0309 0310 void MainWindow::setZoomFactor( qreal factor ) 0311 { 0312 const bool isZoomedIn = factor > 1.0f; 0313 hSBar->setVisible( isZoomedIn ); 0314 vSBar->setVisible( isZoomedIn ); 0315 if ( !isZoomedIn ) { 0316 hSBar->setValue( 500 ); 0317 vSBar->setValue( 500 ); 0318 } 0319 m_chart->coordinatePlane()->setZoomFactorX( factor ); 0320 m_chart->coordinatePlane()->setZoomFactorY( factor ); 0321 } 0322 0323 void MainWindow::setHPos( int hPos ) 0324 { 0325 m_chart->coordinatePlane()->setZoomCenter( QPointF(hPos/1000.0, vSBar->value()/1000.0) ); 0326 m_chart->update(); 0327 } 0328 0329 void MainWindow::setVPos( int vPos ) 0330 { 0331 m_chart->coordinatePlane()->setZoomCenter( QPointF( hSBar->value()/1000.0, vPos/1000.0) ); 0332 } 0333 0334 // since DataValue markers have no relative sizing mode we need to scale them for printing 0335 void MainWindow::paintMarkers( bool checked, const QSize& printSize ) 0336 { 0337 MarkerAttributes::MarkerStylesMap map; 0338 map.insert( 0, MarkerAttributes::MarkerSquare ); 0339 map.insert( 1, MarkerAttributes::MarkerCircle ); 0340 map.insert( 2, MarkerAttributes::MarkerRing ); 0341 map.insert( 3, MarkerAttributes::MarkerCross ); 0342 map.insert( 4, MarkerAttributes::MarkerDiamond ); 0343 0344 // next: Specify column- / cell-specific attributes! 0345 const int colCount = m_lines->model()->columnCount(); 0346 for ( int iColumn = 0; iColumn<colCount; ++iColumn ) { 0347 DataValueAttributes dva = m_lines->dataValueAttributes( iColumn ); 0348 dva.setVisible( true ); 0349 MarkerAttributes ma( dva.markerAttributes() ); 0350 0351 switch ( markersStyleCB->currentIndex() ) { 0352 case 0: 0353 ma.setMarkerStyle( MarkerAttributes::MarkerSquare ); 0354 break; 0355 case 1: 0356 // Column-specific attributes 0357 ma.setMarkerStyle( map.value( iColumn ) ); 0358 break; 0359 case 2: 0360 ma.setMarkerStyle( MarkerAttributes::MarkerCircle ); 0361 break; 0362 case 3: 0363 ma.setMarkerStyle( MarkerAttributes::MarkerDiamond ); 0364 break; 0365 case 4: 0366 ma.setMarkerStyle( MarkerAttributes::Marker1Pixel ); 0367 break; 0368 case 5: 0369 ma.setMarkerStyle( MarkerAttributes::Marker4Pixels ); 0370 break; 0371 case 6: 0372 ma.setMarkerStyle( MarkerAttributes::MarkerRing ); 0373 break; 0374 case 7: 0375 ma.setMarkerStyle( MarkerAttributes::MarkerCross ); 0376 break; 0377 case 8: 0378 ma.setMarkerStyle( MarkerAttributes::MarkerFastCross ); 0379 break; 0380 default: 0381 Q_ASSERT( false ); 0382 } 0383 ma.setVisible( checked ); 0384 0385 qreal factorWidth = printSize.isValid() ? ( printSize.width() / m_chart->rect().width() ) : 1.0f; 0386 qreal factorHeight = printSize.isValid() ? ( printSize.height() / m_chart->rect().height() ) : 1.0f; 0387 ma.setMarkerSize( QSize( markersWidthSB->value() * factorWidth, markersHeightSB->value() * factorHeight ) ); 0388 0389 dva.setMarkerAttributes( ma ); 0390 m_lines->setDataValueAttributes( iColumn, dva ); 0391 0392 // make a special one for certain values 0393 DataValueAttributes yellowAttributes( dva ); 0394 MarkerAttributes yellowMarker( yellowAttributes.markerAttributes() ); 0395 yellowMarker.setMarkerColor( Qt::yellow ); 0396 yellowAttributes.setMarkerAttributes( yellowMarker ); 0397 0398 const int rowCount = m_lines->model()->rowCount(); 0399 for ( int j=0; j< rowCount; ++j ) { 0400 QModelIndex index = m_lines->model()->index( j, iColumn, QModelIndex() ); 0401 QBrush brush = m_lines->model()->headerData( iColumn, Qt::Vertical, DatasetBrushRole ).value<QBrush>(); 0402 qreal value = m_lines->model()->data( index ).toReal(); 0403 /* Set a specific color - marker for a specific value */ 0404 if ( value == 13 ) { 0405 m_lines->setDataValueAttributes( index, yellowAttributes ); 0406 } 0407 } 0408 } 0409 } 0410 0411 void MainWindow::saveChart() 0412 { 0413 qDebug() << "Painting into PNG"; 0414 QPixmap qpix(600,600); 0415 QPainter painter(&qpix); 0416 painter.setBrush(Qt::white); 0417 painter.fillRect( 0, 0, 600, 600, Qt::white); 0418 m_chart->paint( &painter, 0419 QRect(100, 100, 400, 400) ); 0420 painter.end(); 0421 qpix.save("kchart-demo.png", "PNG"); 0422 qDebug() << "Painting into PNG - done"; 0423 } 0424 0425 void MainWindow::resizeEvent ( QResizeEvent * ) 0426 { 0427 m_smallChart1->move( width() - m_pix1.width()*2, 0428 height()/2 - m_pix1.height()-5 ); 0429 m_smallChart2->move( width() - m_pix2.width()*2, 0430 height()/2 + 5 ); 0431 } 0432 0433