File indexing completed on 2024-05-19 15:26:53
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 <QFileDialog> 0038 #include <QPrinter> 0039 #include <QPrintPreviewDialog> 0040 0041 using namespace KChart; 0042 0043 static QPixmap drawIntoPixmap( const QSize& size, KChart::Chart* chart ) 0044 { 0045 QPixmap pix( size ); 0046 pix.fill( Qt::white ); 0047 QPainter painter( &pix ); 0048 chart->paint( &painter, QRect( 0, 0, size.width(), size.height() ) ); 0049 return pix; 0050 } 0051 0052 // When set, this example uses FrameWidget which uses Chart::paint to paint itself. 0053 // When not set, this example uses a Chart widget directly. 0054 #define USE_FRAME_WIDGET 1 0055 0056 0057 MainWindow::MainWindow( QWidget* parent ) : 0058 QWidget( parent ) 0059 { 0060 setupUi( this ); 0061 0062 QHBoxLayout* chartLayout = new QHBoxLayout( chartFrame ); 0063 #ifdef USE_FRAME_WIDGET 0064 FrameWidget* chartFrameWidget = new FrameWidget(); 0065 chartLayout->addWidget( chartFrameWidget ); 0066 #endif 0067 hSBar->setVisible( false ); 0068 vSBar->setVisible( false ); 0069 0070 m_model.loadFromCSV( ":/data" ); 0071 0072 // Set up the diagram 0073 m_lines = new LineDiagram(); 0074 m_lines->setModel( &m_model ); 0075 0076 CartesianAxis *xAxis = new CartesianAxis( m_lines ); 0077 CartesianAxis *yAxis = new CartesianAxis( m_lines ); 0078 CartesianAxis *axisTop = new CartesianAxis( m_lines ); 0079 CartesianAxis *axisRight = new CartesianAxis( m_lines ); 0080 xAxis->setPosition( KChart::CartesianAxis::Bottom ); 0081 yAxis->setPosition( KChart::CartesianAxis::Left ); 0082 axisTop->setPosition( KChart::CartesianAxis::Top ); 0083 axisRight->setPosition( KChart::CartesianAxis::Right ); 0084 0085 m_lines->addAxis( xAxis ); 0086 m_lines->addAxis( yAxis ); 0087 m_lines->addAxis( axisTop ); 0088 m_lines->addAxis( axisRight ); 0089 0090 m_chart = new Chart(); 0091 //m_chart->setGlobalLeading(10,10,10,10); // by default there is no leading 0092 0093 #ifdef USE_FRAME_WIDGET 0094 chartFrameWidget->setChart( m_chart ); 0095 // make sure, we re-draw after changing one of the chart's properties 0096 connect( m_chart, SIGNAL(propertiesChanged()), 0097 chartFrameWidget, SLOT(update()) ) ; 0098 #else 0099 chartLayout->addWidget( m_chart ); 0100 #endif 0101 0102 m_chart->coordinatePlane()->replaceDiagram( m_lines ); 0103 0104 for ( int iColumn = 0; iColumn < m_lines->model()->columnCount(); ++iColumn ) { 0105 QPen pen(m_lines->pen( iColumn )); 0106 pen.setWidth(4); 0107 m_lines->setPen( iColumn, pen ); 0108 } 0109 0110 FrameAttributes faChart( m_chart->frameAttributes() ); 0111 faChart.setVisible( true ); 0112 faChart.setPen( QPen(QColor( 0x60, 0x60, 0xb0 ), 8 ) ); 0113 m_chart->setFrameAttributes( faChart ); 0114 0115 BackgroundAttributes baChart( m_chart->backgroundAttributes() ); 0116 baChart.setVisible( true ); 0117 baChart.setBrush( QColor( 0xd0, 0xd0, 0xff ) ); 0118 m_chart->setBackgroundAttributes( baChart ); 0119 0120 // Set up the legend 0121 m_legend = new Legend( m_lines, m_chart ); 0122 0123 m_legend->setPosition( Position::South ); 0124 m_legend->setAlignment( Qt::AlignRight ); 0125 m_legend->setShowLines( false ); 0126 m_legend->setTitleText( tr( "Legend" ) ); 0127 m_legend->setOrientation( Qt::Horizontal ); 0128 0129 // setting the legend frame and background to the same color: 0130 const QColor legendColor( 0xff, 0xe0, 0x80 ); 0131 FrameAttributes faLegend( m_legend->frameAttributes() ); 0132 faLegend.setVisible( true ); 0133 faLegend.setPen( QPen( legendColor, 1 ) ); 0134 m_legend->setFrameAttributes( faLegend ); 0135 0136 BackgroundAttributes baLegend( m_legend->backgroundAttributes() ); 0137 baLegend.setVisible( true ); 0138 baLegend.setBrush( legendColor ); 0139 m_legend->setBackgroundAttributes( baLegend ); 0140 0141 m_chart->addLegend( m_legend ); 0142 0143 // for illustration we paint the same chart at different sizes: 0144 QSize size1 = QSize( 200, 200 ); 0145 QSize size2 = QSize( 800, 800 ); 0146 m_pix1 = drawIntoPixmap( size1, m_chart ); 0147 m_pix2 = drawIntoPixmap( size2, m_chart ); 0148 m_pix2 = m_pix2.scaled( size1 ); 0149 0150 m_smallChart1 = new QLabel( this ); 0151 m_smallChart1->setWindowTitle( "200x200" ); 0152 m_smallChart1->setPixmap( m_pix1 ); 0153 m_smallChart1->setFixedSize( m_pix1.size() ); 0154 m_smallChart1->move( width() - m_pix1.width() * 2, 0155 height() / 2 - m_pix1.height() - 5 ); 0156 m_smallChart1->show(); 0157 0158 m_smallChart2 = new QLabel( this ); 0159 m_smallChart2->setWindowTitle( "800x800 scaled down" ); 0160 m_smallChart2->setPixmap( m_pix2 ); 0161 m_smallChart2->setFixedSize( m_pix2.size() ); 0162 m_smallChart2->move( width() - m_pix2.width() * 2, 0163 height() / 2 + 5 ); 0164 m_smallChart2->show(); 0165 0166 faChart.setPen( QPen( QColor( 0xb0, 0xb0, 0xff ), 8 ) ); 0167 m_chart->setFrameAttributes( faChart ); 0168 0169 // initialize attributes; this is necessary because we need to enable data value attributes before 0170 // any of them (e.g. only markers) can be displayed. but if we enable data value attributs, a default 0171 // data value text is included, even if we only wanted to set markers. so we enable DVA and then 0172 // individually disable the parts we don't want. 0173 on_paintValuesCB_toggled( false ); 0174 on_paintMarkersCB_toggled( false ); 0175 } 0176 0177 void MainWindow::slotPaintRequested(QPrinter *printer) 0178 { 0179 QPainter painter(printer); 0180 m_chart->paint(&painter, painter.window()); 0181 } 0182 0183 void MainWindow::on_printButton_clicked() 0184 { 0185 static QPrinter printer; 0186 QPrintPreviewDialog dialog(&printer); 0187 connect(&dialog, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPaintRequested(QPrinter*))); 0188 dialog.exec(); 0189 } 0190 0191 void MainWindow::on_lineTypeCB_currentIndexChanged( const QString & text ) 0192 { 0193 if ( text == "Normal" ) 0194 m_lines->setType( LineDiagram::Normal ); 0195 else if ( text == "Stacked" ) 0196 m_lines->setType( LineDiagram::Stacked ); 0197 else if ( text == "Percent" ) 0198 m_lines->setType( LineDiagram::Percent ); 0199 else 0200 qWarning (" Does not match any type"); 0201 } 0202 0203 0204 void MainWindow::on_paintLegendCB_toggled( bool checked ) 0205 { 0206 KChart::Legend* legend = m_chart->legend(); 0207 if ( checked != ( legend != nullptr ) ) { 0208 if ( checked ) 0209 m_chart->addLegend( m_legend ); 0210 else 0211 m_chart->takeLegend( legend ); 0212 } 0213 } 0214 0215 void MainWindow::on_paintValuesCB_toggled( bool checked ) 0216 { 0217 const int colCount = m_lines->model()->columnCount(); 0218 for ( int iColumn = 0; iColumn < colCount; ++iColumn ) { 0219 DataValueAttributes a = m_lines->dataValueAttributes( iColumn ); 0220 a.setVisible( true ); 0221 0222 TextAttributes ta = a.textAttributes(); 0223 ta.setRotation( 0 ); 0224 ta.setFont( QFont( "Comic", 10 ) ); 0225 ta.setPen( m_lines->brush( iColumn ).color() ); 0226 ta.setVisible( checked ); 0227 0228 a.setTextAttributes( ta ); 0229 m_lines->setDataValueAttributes( iColumn, a ); 0230 } 0231 } 0232 0233 0234 void MainWindow::on_paintMarkersCB_toggled( bool checked ) 0235 { 0236 paintMarkers( checked, QSize() ); 0237 } 0238 0239 void MainWindow::on_markersStyleCB_currentIndexChanged( const QString & text ) 0240 { 0241 Q_UNUSED( text ); 0242 on_paintMarkersCB_toggled( paintMarkersCB->isChecked() ); 0243 } 0244 0245 0246 void MainWindow::on_markersWidthSB_valueChanged( int i ) 0247 { 0248 Q_UNUSED( i ); 0249 markersHeightSB->setValue( markersWidthSB->value() ); 0250 on_paintMarkersCB_toggled( paintMarkersCB->isChecked() ); 0251 } 0252 0253 void MainWindow::on_markersHeightSB_valueChanged( int i ) 0254 { 0255 Q_UNUSED( i ); 0256 markersWidthSB->setValue( markersHeightSB->value() ); 0257 on_paintMarkersCB_toggled( paintMarkersCB->isChecked() ); 0258 } 0259 0260 0261 void MainWindow::on_displayAreasCB_toggled( bool checked ) 0262 { 0263 const int colCount = m_lines->model()->columnCount(); 0264 for ( int iColumn = 0; iColumn < colCount; ++iColumn ) { 0265 LineAttributes la( m_lines->lineAttributes( iColumn ) ); 0266 la.setDisplayArea( checked ); 0267 if ( checked ) 0268 la.setTransparency( transparencySB->value() ); 0269 m_lines->setLineAttributes( iColumn, la ); 0270 } 0271 } 0272 0273 void MainWindow::on_transparencySB_valueChanged( int alpha ) 0274 { 0275 Q_UNUSED( alpha ); 0276 if ( !displayAreasCB->isChecked() ) 0277 displayAreasCB->setChecked( true ); 0278 else 0279 on_displayAreasCB_toggled( true ); 0280 } 0281 0282 void MainWindow::on_zoomFactorSB_valueChanged( qreal factor ) 0283 { 0284 const bool isZoomedIn = factor > 1.0f; 0285 hSBar->setVisible( isZoomedIn ); 0286 vSBar->setVisible( isZoomedIn ); 0287 if ( !isZoomedIn ) { 0288 hSBar->setValue( 500 ); 0289 vSBar->setValue( 500 ); 0290 } 0291 m_chart->coordinatePlane()->setZoomFactorX( factor ); 0292 m_chart->coordinatePlane()->setZoomFactorY( factor ); 0293 } 0294 0295 void MainWindow::on_hSBar_valueChanged( int hPos ) 0296 { 0297 m_chart->coordinatePlane()->setZoomCenter( QPointF( hPos / 1000.0, vSBar->value() / 1000.0 ) ); 0298 m_chart->update(); 0299 } 0300 0301 void MainWindow::on_vSBar_valueChanged( int vPos ) 0302 { 0303 m_chart->coordinatePlane()->setZoomCenter( QPointF( hSBar->value() / 1000.0, vPos / 1000.0 ) ); 0304 } 0305 0306 // since DataValue markers have no relative sizing mode we need to scale them for printing 0307 void MainWindow::paintMarkers( bool checked, const QSize& printSize ) 0308 { 0309 MarkerAttributes::MarkerStylesMap map; 0310 map.insert( 0, MarkerAttributes::MarkerSquare ); 0311 map.insert( 1, MarkerAttributes::MarkerCircle ); 0312 map.insert( 2, MarkerAttributes::MarkerRing ); 0313 map.insert( 3, MarkerAttributes::MarkerCross ); 0314 map.insert( 4, MarkerAttributes::MarkerDiamond ); 0315 0316 // next: Specify column- / cell-specific attributes! 0317 const int colCount = m_lines->model()->columnCount(); 0318 for ( int iColumn = 0; iColumn < colCount; ++iColumn ) { 0319 0320 DataValueAttributes dva = m_lines->dataValueAttributes( iColumn ); 0321 dva.setVisible( true ); 0322 MarkerAttributes ma( dva.markerAttributes() ); 0323 0324 switch ( markersStyleCB->currentIndex() ) { 0325 case 0: 0326 ma.setMarkerStyle( MarkerAttributes::MarkerSquare ); 0327 break; 0328 case 1: 0329 // Column-specific attributes 0330 ma.setMarkerStyle( map.value( iColumn ) ); 0331 break; 0332 case 2: 0333 ma.setMarkerStyle( MarkerAttributes::MarkerCircle ); 0334 break; 0335 case 3: 0336 ma.setMarkerStyle( MarkerAttributes::MarkerDiamond ); 0337 break; 0338 case 4: 0339 ma.setMarkerStyle( MarkerAttributes::Marker1Pixel ); 0340 break; 0341 case 5: 0342 ma.setMarkerStyle( MarkerAttributes::Marker4Pixels ); 0343 break; 0344 case 6: 0345 ma.setMarkerStyle( MarkerAttributes::MarkerRing ); 0346 break; 0347 case 7: 0348 ma.setMarkerStyle( MarkerAttributes::MarkerCross ); 0349 break; 0350 case 8: 0351 ma.setMarkerStyle( MarkerAttributes::MarkerFastCross ); 0352 break; 0353 default: 0354 Q_ASSERT( false ); 0355 } 0356 ma.setVisible( checked ); 0357 0358 qreal factorWidth = printSize.isValid() ? ( printSize.width() / m_chart->rect().width() ) : 1.0f; 0359 qreal factorHeight = printSize.isValid() ? ( printSize.height() / m_chart->rect().height() ) : 1.0f; 0360 ma.setMarkerSize( QSize( markersWidthSB->value() * factorWidth, markersHeightSB->value() * factorHeight ) ); 0361 0362 dva.setMarkerAttributes( ma ); 0363 m_lines->setDataValueAttributes( iColumn, dva ); 0364 0365 // make a special one for certain values 0366 DataValueAttributes yellowAttributes( dva ); 0367 MarkerAttributes yellowMarker( yellowAttributes.markerAttributes() ); 0368 yellowMarker.setMarkerColor( Qt::yellow ); 0369 yellowAttributes.setMarkerAttributes( yellowMarker ); 0370 0371 const int rowCount = m_lines->model()->rowCount(); 0372 for ( int j = 0; j < rowCount; ++j ) { 0373 QModelIndex index = m_lines->model()->index( j, iColumn, QModelIndex() ); 0374 QBrush brush = m_lines->model()->headerData( iColumn, Qt::Vertical, DatasetBrushRole ).value<QBrush>(); 0375 qreal value = m_lines->model()->data( index ).toReal(); 0376 /* Set a specific color - marker for a specific value */ 0377 if ( value == 13 ) { 0378 m_lines->setDataValueAttributes( index, yellowAttributes ); 0379 } 0380 } 0381 } 0382 } 0383 0384 void MainWindow::on_savePB_clicked() 0385 { 0386 const QString file = QFileDialog::getSaveFileName( this, tr( "Choose PNG File..." ) ); 0387 if ( file.isEmpty() ) 0388 return; 0389 qDebug() << "Painting into PNG"; 0390 QPixmap qpix( 600, 600 ); 0391 QPainter painter( &qpix ); 0392 painter.setBrush( Qt::white ); 0393 painter.fillRect( 0, 0, 600, 600, Qt::white); 0394 m_chart->paint( &painter, 0395 QRect( 100, 100, 400, 400 ) ); 0396 painter.end(); 0397 qpix.save( file, "PNG" ); 0398 qDebug() << "Painting into PNG - done"; 0399 } 0400 0401 void MainWindow::on_savePDF_clicked() 0402 { 0403 const QString file = QFileDialog::getSaveFileName( this, tr( "Choose PDF File..." ) ); 0404 if ( file.isEmpty() ) 0405 return; 0406 qDebug() << "Painting into PDF"; 0407 QPrinter printer( QPrinter::HighResolution ); 0408 printer.setOrientation( QPrinter::Landscape ); 0409 printer.setOutputFormat( QPrinter::PdfFormat ); 0410 printer.setOutputFileName( file ); 0411 paintMarkers( paintMarkersCB->isChecked(), printer.pageRect().size() ); 0412 QPainter painter; 0413 painter.begin( &printer ); 0414 m_chart->paint( &painter, printer.pageRect() ); 0415 painter.end(); 0416 paintMarkers( paintMarkersCB->isChecked(), m_chart->geometry().size() ); 0417 qDebug() << "Painting into PDF - done"; 0418 } 0419 0420 void MainWindow::resizeEvent( QResizeEvent * ) 0421 { 0422 m_smallChart1->move( width() - m_pix1.width() * 2, 0423 height() / 2 - m_pix1.height() - 5 ); 0424 m_smallChart2->move( width() - m_pix2.width() * 2, 0425 height() / 2 + 5 ); 0426 }