|
QT finance chart in a mdiArea? |
Posted by Mehmet Ali Atlihan on Sep-25-2012 16:11 |
|
Hi,
I am wondering how is it if possible to display a finance chart in a QT mdiArea. QT mdiArea
has a method of addSubwindow(QWidget*) which is not what financechart type is. I have
tried creating a QChartViewer * widget, widget->setChart(financeChart) and adding that to
the mdiArea. The compiler did not complain but I receive run time error. Can you please
advise?
Thanks,
Mehmet |
Re: QT finance chart in a mdiArea? |
Posted by Peter Kwan on Sep-26-2012 04:40 |
|
Hi Mehmet,
I have just tried the "Finance Chart (1)" sample code, and modified it to display the QChartViewer in a QmdiArea using addSubwindow(QWidget*), and it worked correctly. I have attached my test code for your reference.
#include <QApplication>
#include <QMainWindow>
#include <QMdiArea>
#include <QMdiSubWindow>
#include "qchartviewer.h"
#include "financechart.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.setFixedSize(800,600);
window.setWindowTitle(QString::fromUtf8("My QMdiWindow"));
QMdiArea* area = new QMdiArea();
area->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
QChartViewer *viewer = new QChartViewer();
// Create a finance chart demo containing 100 days of data
int noOfDays = 100;
// To compute moving averages starting from the first day, we need to get extra
// data points before the first day
int extraDays = 30;
// In this exammple, we use a random number generator utility to simulate the
// data. We set up the random table to create 6 cols x (noOfDays + extraDays)
// rows, using 9 as the seed.
RanTable *rantable = new RanTable(9, 6, noOfDays + extraDays);
// Set the 1st col to be the timeStamp, starting from Sep 4, 2002, with each row
// representing one day, and counting week days only (jump over Sat and Sun)
rantable->setDateCol(0, Chart::chartTime(2002, 9, 4), 86400, true);
// Set the 2nd, 3rd, 4th and 5th columns to be high, low, open and close data.
// The open value starts from 100, and the daily change is random from -5 to 5.
rantable->setHLOCCols(1, 100, -5, 5);
// Set the 6th column as the vol data from 5 to 25 million
rantable->setCol(5, 50000000, 250000000);
// Now we read the data from the table into arrays
DoubleArray timeStamps = rantable->getCol(0);
DoubleArray highData = rantable->getCol(1);
DoubleArray lowData = rantable->getCol(2);
DoubleArray openData = rantable->getCol(3);
DoubleArray closeData = rantable->getCol(4);
DoubleArray volData = rantable->getCol(5);
// Create a FinanceChart object of width 640 pixels
FinanceChart *c = new FinanceChart(640);
// Add a title to the chart
c->addTitle("Finance Chart Demonstration");
// Set the data into the finance chart object
c->setData(timeStamps, highData, lowData, openData, closeData, volData, extraDays
);
// Add the main chart with 240 pixels in height
c->addMainChart(240);
// Add a 5 period simple moving average to the main chart, using brown color
c->addSimpleMovingAvg(5, 0x663300);
// Add a 20 period simple moving average to the main chart, using purple color
c->addSimpleMovingAvg(20, 0x9900ff);
// Add HLOC symbols to the main chart, using green/red for up/down days
c->addHLOC(0x008000, 0xcc0000);
// Add 20 days bollinger band to the main chart, using light blue (9999ff) as the
// border and semi-transparent blue (c06666ff) as the fill color
c->addBollingerBand(20, 2, 0x9999ff, 0xc06666ff);
// Add a 75 pixels volume bars sub-chart to the bottom of the main chart, using
// green/red/grey for up/down/flat days
c->addVolBars(75, 0x99ff99, 0xff9999, 0x808080);
// Append a 14-days RSI indicator chart (75 pixels high) after the main chart.
// The main RSI line is purple (800080). Set threshold region to +/- 20 (that is,
// RSI = 50 +/- 25). The upper/lower threshold regions will be filled with red
// (ff0000)/blue (0000ff).
c->addRSI(75, 14, 0x800080, 20, 0xff0000, 0x0000ff);
// Append a 12-days momentum indicator chart (75 pixels high) using blue (0000ff)
// color.
c->addMomentum(75, 12, 0x0000ff);
viewer->setChart(c);
// In this sample project, we do not need to chart object any more, so we
// delete it now.
delete c;
//Add subWindow to Main QMdiWindow here
area->addSubWindow(viewer);
window.setCentralWidget(area);
window.show();
return app.exec();
}
Hope this can help.
Regards
Peter Kwan |
Re: QT finance chart in a mdiArea? |
Posted by Mehmet Atlihan on Sep-26-2012 11:29 |
|
Thanks for the reply. It is now working. I guess it has to do with the calling sequence.
Can you also advise on what the best way is to resize the chart when its parent window is resized? From what I have seen in the forums, the chart has to be re-painted with the resized witdh and height.
Peter Kwan wrote:
Hi Mehmet,
I have just tried the "Finance Chart (1)" sample code, and modified it to display the QChartViewer in a QmdiArea using addSubwindow(QWidget*), and it worked correctly. I have attached my test code for your reference.
#include <QApplication>
#include <QMainWindow>
#include <QMdiArea>
#include <QMdiSubWindow>
#include "qchartviewer.h"
#include "financechart.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.setFixedSize(800,600);
window.setWindowTitle(QString::fromUtf8("My QMdiWindow"));
QMdiArea* area = new QMdiArea();
area->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
QChartViewer *viewer = new QChartViewer();
// Create a finance chart demo containing 100 days of data
int noOfDays = 100;
// To compute moving averages starting from the first day, we need to get extra
// data points before the first day
int extraDays = 30;
// In this exammple, we use a random number generator utility to simulate the
// data. We set up the random table to create 6 cols x (noOfDays + extraDays)
// rows, using 9 as the seed.
RanTable *rantable = new RanTable(9, 6, noOfDays + extraDays);
// Set the 1st col to be the timeStamp, starting from Sep 4, 2002, with each row
// representing one day, and counting week days only (jump over Sat and Sun)
rantable->setDateCol(0, Chart::chartTime(2002, 9, 4), 86400, true);
// Set the 2nd, 3rd, 4th and 5th columns to be high, low, open and close data.
// The open value starts from 100, and the daily change is random from -5 to 5.
rantable->setHLOCCols(1, 100, -5, 5);
// Set the 6th column as the vol data from 5 to 25 million
rantable->setCol(5, 50000000, 250000000);
// Now we read the data from the table into arrays
DoubleArray timeStamps = rantable->getCol(0);
DoubleArray highData = rantable->getCol(1);
DoubleArray lowData = rantable->getCol(2);
DoubleArray openData = rantable->getCol(3);
DoubleArray closeData = rantable->getCol(4);
DoubleArray volData = rantable->getCol(5);
// Create a FinanceChart object of width 640 pixels
FinanceChart *c = new FinanceChart(640);
// Add a title to the chart
c->addTitle("Finance Chart Demonstration");
// Set the data into the finance chart object
c->setData(timeStamps, highData, lowData, openData, closeData, volData, extraDays
);
// Add the main chart with 240 pixels in height
c->addMainChart(240);
// Add a 5 period simple moving average to the main chart, using brown color
c->addSimpleMovingAvg(5, 0x663300);
// Add a 20 period simple moving average to the main chart, using purple color
c->addSimpleMovingAvg(20, 0x9900ff);
// Add HLOC symbols to the main chart, using green/red for up/down days
c->addHLOC(0x008000, 0xcc0000);
// Add 20 days bollinger band to the main chart, using light blue (9999ff) as the
// border and semi-transparent blue (c06666ff) as the fill color
c->addBollingerBand(20, 2, 0x9999ff, 0xc06666ff);
// Add a 75 pixels volume bars sub-chart to the bottom of the main chart, using
// green/red/grey for up/down/flat days
c->addVolBars(75, 0x99ff99, 0xff9999, 0x808080);
// Append a 14-days RSI indicator chart (75 pixels high) after the main chart.
// The main RSI line is purple (800080). Set threshold region to +/- 20 (that is,
// RSI = 50 +/- 25). The upper/lower threshold regions will be filled with red
// (ff0000)/blue (0000ff).
c->addRSI(75, 14, 0x800080, 20, 0xff0000, 0x0000ff);
// Append a 12-days momentum indicator chart (75 pixels high) using blue (0000ff)
// color.
c->addMomentum(75, 12, 0x0000ff);
viewer->setChart(c);
// In this sample project, we do not need to chart object any more, so we
// delete it now.
delete c;
//Add subWindow to Main QMdiWindow here
area->addSubWindow(viewer);
window.setCentralWidget(area);
window.show();
return app.exec();
}
Hope this can help.
Regards
Peter Kwan
|
Re: QT finance chart in a mdiArea? |
Posted by Peter Kwan on Sep-26-2012 17:37 |
|
Hi Mehmet,
Resizing a chart usually means completely redrawing the chart. For example, if you use the Windows performance monitor (enter "perfmon" in the command line), when you resize the chart, you can see the labels on the axis do not get larger when the chart resizes, and the line width is not thicker. Instead, the chart contains more labels. The same happens to the chart in the task manager. So resizing a chart is not to make the contents bigger, but to show things in more details, and this requires a complete redraw.
To resize a chart, in the resize event handler of your widget, please put the one line of code as follows:
drawChart();
The drawChart is the subroutine that draws the chart. It should be the same subroutine that draws the chart when your program starts up. (So you may put all your charting code in that subroutine.) In the drawChart subroutine, the chart size is not hard coded, but is based on the window size. (So it always draw the chart according to the current window size.)
The above method makes resizing very simple. You just need to have one chart drawing subroutine for your application that draws the chart based on the current window size, and no additional code is required to support resizing (apart from calling drawChart).
Hope this can help.
Regards
Peter Kwan |
Re: QT finance chart in a mdiArea? |
Posted by Mehmet Atlihan on Sep-28-2012 12:10 |
|
Hi Peter,
Can you please share a working code about resizing the finance chart when the current widget that holds the finance chart is chartviewer ? I am not able to resize the chart so far.
Regards,
Mehmet |
Re: QT finance chart in a mdiArea? |
Posted by Peter Kwan on Sep-29-2012 03:32 |
|
Hi Mehmet,
I have just written an example for you. Basically, you just need to redraw the chart in the resize event handler. The chart size should be based on the current window size.
Hope this can help.
Regards
Peter Kwan
helloworld.cpp |
---|
#include <QApplication>
#include <QMainWindow>
#include <QMdiArea>
#include "financechart.h"
#include "helloworld.h"
void MyWindow::onViewPortChanged()
{
// Create a finance chart demo containing 100 days of data
int noOfDays = 100;
// To compute moving averages starting from the first day, we need to get extra
// data points before the first day
int extraDays = 30;
// In this exammple, we use a random number generator utility to simulate the
// data. We set up the random table to create 6 cols x (noOfDays + extraDays)
// rows, using 9 as the seed.
RanTable *rantable = new RanTable(9, 6, noOfDays + extraDays);
// Set the 1st col to be the timeStamp, starting from Sep 4, 2002, with each row
// representing one day, and counting week days only (jump over Sat and Sun)
rantable->setDateCol(0, Chart::chartTime(2002, 9, 4), 86400, true);
// Set the 2nd, 3rd, 4th and 5th columns to be high, low, open and close data.
// The open value starts from 100, and the daily change is random from -5 to 5.
rantable->setHLOCCols(1, 100, -5, 5);
// Set the 6th column as the vol data from 5 to 25 million
rantable->setCol(5, 50000000, 250000000);
// Now we read the data from the table into arrays
DoubleArray timeStamps = rantable->getCol(0);
DoubleArray highData = rantable->getCol(1);
DoubleArray lowData = rantable->getCol(2);
DoubleArray openData = rantable->getCol(3);
DoubleArray closeData = rantable->getCol(4);
DoubleArray volData = rantable->getCol(5);
int width = size().width() - 40;
int height = size().height() - 140;
if (width < 400) width = 400;
if (height < 240) height = 240;
// Create a FinanceChart object of width 640 pixels
FinanceChart *c = new FinanceChart(width);
// Add a title to the chart
c->addTitle("Finance Chart Demonstration");
// Set the data into the finance chart object
c->setData(timeStamps, highData, lowData, openData, closeData, volData, extraDays
);
// Add the main chart with 240 pixels in height
c->addMainChart(height * 6 / 10);
// Add a 5 period simple moving average to the main chart, using brown color
c->addSimpleMovingAvg(5, 0x663300);
// Add a 20 period simple moving average to the main chart, using purple color
c->addSimpleMovingAvg(20, 0x9900ff);
// Add HLOC symbols to the main chart, using green/red for up/down days
c->addHLOC(0x008000, 0xcc0000);
// Add 20 days bollinger band to the main chart, using light blue (9999ff) as the
// border and semi-transparent blue (c06666ff) as the fill color
c->addBollingerBand(20, 2, 0x9999ff, 0xc06666ff);
// Add a 75 pixels volume bars sub-chart to the bottom of the main chart, using
// green/red/grey for up/down/flat days
c->addVolBars(height * 2 / 10, 0x99ff99, 0xff9999, 0x808080);
// Append a 14-days RSI indicator chart (75 pixels high) after the main chart.
// The main RSI line is purple (800080). Set threshold region to +/- 20 (that is,
// RSI = 50 +/- 25). The upper/lower threshold regions will be filled with red
// (ff0000)/blue (0000ff).
c->addRSI(height * 2 / 10, 14, 0x800080, 20, 0xff0000, 0x0000ff);
// Append a 12-days momentum indicator chart (75 pixels high) using blue (0000ff)
// color.
c->addMomentum(height * 2 / 10, 12, 0x0000ff);
delete viewer->getChart();
viewer->setChart(c);
}
MyWindow::MyWindow()
{
this->setWidget(viewer = new QChartViewer());
connect(viewer, SIGNAL(viewPortChanged()), SLOT(onViewPortChanged()));
}
MyWindow::~MyWindow()
{
delete viewer->getChart();
}
void MyWindow::resizeEvent(QResizeEvent *event)
{
QMdiSubWindow::resizeEvent(event);
viewer->updateViewPort(true, true);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.resize(800,600);
QMdiArea* area = new QMdiArea();
area->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
area->addSubWindow(new MyWindow())->resize(600, 400);
window.setCentralWidget(area);
window.show();
return app.exec();
}
|
|
helloworld.h |
---|
#ifndef HELLOWORLD_H
#define HELLOWORLD_H
#include "qchartviewer.h"
#include <QMdiSubWindow>
class MyWindow : public QMdiSubWindow
{
Q_OBJECT
public :
MyWindow();
~MyWindow();
void resizeEvent(QResizeEvent *event);
private :
QChartViewer *viewer;
private slots:
void onViewPortChanged();
};
#endif // HELLOWORLD_H
|
| |
Re: QT finance chart in a mdiArea? |
Posted by Mehmet Atlihan on Oct-06-2012 08:08 |
|
Hi Peter,
Thanks for the great support. I have succesfully implemented the resizing based on your feedback as well as scrolling/zooming based on the documentation example. I have a few follow up problems that I will need your help with
1) In the drawChart method, when I add an oscillator like willamsR, the finance chart window starts growing in height as soon as it shows up and it will continue to grow indefinetly unless I maximize the window.When I shrink the window size, same thing happens.
2) When the oscillator is added (I currently do not have a volume layer), the timestamp on X axis also disappears. I am guessing there is a setting to increase the gap between the axis and the oscillator that is added but I am unable to find that in the documentation other than a method called setBarGap which is for Bar charts.
Please see the code below that causes infinite growth of height in the finance chart window. In my debugging session, I also confirm the "height" local parameter keeps changing as such the view keeps being updated. When I remove williamsR oscillator, the problem disappears. I am guessing this will happen for every oscillator or any other layer that I will add to the bottom of the chart. Please advise.
///////////////////////////////////////////////////////////////////////////////////////////////////
int height = this->size().height() - 150; //this is the line where height is set.
////////////////////////////////////////////////////////////////////////////////////////////////////////
//this is the partial code based on your feedback and mixed of scrolling and zooming example //////
double viewPortStartDate = viewer->getValueAtViewPort("x", viewer->getViewPortLeft());
double viewPortEndDate = viewer->getValueAtViewPort("x", viewer->getViewPortLeft() +
viewer->getViewPortWidth());
// Get the array indexes that corresponds to the visible start and end dates
int startIndex = (int)floor(Chart::bSearch(mTimeStamp, viewPortStartDate));
int endIndex = (int)ceil(Chart::bSearch(mTimeStamp, viewPortEndDate));
int noOfPoints = endIndex - startIndex + 1;
DoubleArray timeStamps = DoubleArray(mTimeStamp.data+startIndex,noOfPoints);//rantable->getCol(0);
DoubleArray highData= DoubleArray(mHigh.data+startIndex,noOfPoints);//rantable->getCol(1);
DoubleArray lowData= DoubleArray(mLow.data+startIndex,noOfPoints);//rantable->getCol(2);
DoubleArray openData= DoubleArray(mOpen.data+startIndex,noOfPoints);//rantable->getCol(3);
DoubleArray closeData=DoubleArray(mClose.data+startIndex,noOfPoints);// rantable->getCol(4);
DoubleArray volData= DoubleArray(mVolume.data+startIndex,noOfPoints); //rantable->getCol(5);
int width = this->size().width() - 40;
int height = this->size().height() - 150;
//int height = 500;
if (width < 400) width = 400;
if (height < 240) height = 240;
FinanceChart *c = new FinanceChart(width);
//c->addInd
int lightGray = 0x657383;
int backgroundColor = 0x708090;
c->setPlotAreaStyle(backgroundColor,lightGray,lightGray,lightGray,lightGray);
// Add a title to the chart
c->addTitle("Finance Chart Demonstration");
// Set the data into the finance chart object
c->setData(timeStamps, highData, lowData, openData, closeData, volData, extraDays
);
// Add the main chart with 240 pixels in height
c->addMainChart(height);
// Add an HLOC symbols to the main chart, using green/red for up/down days
c->addCandleStick(0x00ff00, 0xff0000);
// Add a 75 pixels volume bars sub-chart to the bottom of the main chart, using
// green/red/grey for up/down/flat days
c->addVolBars(75, 0x99ff99, 0xff9999, 0x808080);
c->addWilliamR(200,21,0X00FFFF,30,0x0000FF,0XFF0000); |
Re: QT finance chart in a mdiArea? |
Posted by Peter Kwan on Oct-08-2012 23:42 |
|
Hi Mehmet,
In your code, you set the "height" to:
int height = this->size().height() - 150;
which is 150 pixels less than the height of the window.
Now you use the entire height as the height of the main chart, like:
c->addMainChart(height);
So after adding the main chart, there are still 150 pixels in the window, which should be sufficient for the contents outside the main chart (which are the axis labels below the chart, and the chart title above the chart).
However, then you add the WilliamR and configure it to be 200 pixels in size. This will overflow the window, which only has 150 pixels left. As a result, part of the chart will fall outside the window, and you may not see the bottom x-axis labels (as they are outside the window). Furthermore, as the chart is now larger than the window, your window may automatic grow in height to accommodate the chart. But then the chart can become even larger (when the window height increases, your code also increases the main price chart height using the code "int height = this->size().height() - 150;"), and so the window needs to increases its height once more, and the loop continues. That's why the chart will grow in size.
To solve the problem, please do not draw a chart that is larger than the window. In my original code, I only use 60% of the height of the main price chart (not 100% of the height as in your code), and I use 20% of the height for the two indicator charts (not hard coded the height as 200 pixels as in your code).
For your case, your code must first determine how to allocate the available height to the main price chart and to the indicator charts. You can allocate the main price chart so that it is always 3 times the height of the indicator charts, and so that the main price chart plus all the indicator charts consume 100% of the height, or you can use any other allocation method you like. Then you can draw the chart using those heights to make sure the chart will not overflow the window.
Hope this can help.
Regards
Peter Kwan |
|