PDA

View Full Version : Draw a bar chart inisde the QScrollArea



ultrasonic
3rd March 2007, 17:04
Hi,

I am writing a program which reads lots of data (more than 1000) and show them by drawing a bar chart. I subclassed QWidget , reimplemented paintEvent() to draw my chart and called QScrollArea::setWidget() to setup the chart into the QScrollArea. But when I dragged the scroll bar in the QScrollArea, the scrollbar and chart moved extremely slowly. How do I resolve the problem?:confused:

Here is my source code.

fullmetalcoder
3rd March 2007, 17:09
I am writing a program which reads lots of data (more than 1000) and show them by drawing a bar chart. I subclassed QWidget , reimplemented paintEvent() to draw my chart and called QScrollArea::setWidget() to setup the chart into the QScrollArea. But when I dragged the scroll bar in the QScrollArea, the scrollbar and chart moved extremely slowly. How do I resolve the problem?:confused:

AFAIK QScrollArea repaint its child each times the scrollbars' values change... A solution would be to cache your chart by drawing it into an image/pixmap and displaying this cache. Alternatively you could handle scrolling internally (in your custom widget) without relying on QScrollArea. A third solution could be to reimplement QAbstractScrollArea instead of QWidget, draw your chart and make sure a full repaint isn't done each time the scrollbars move (you might want to take inspiration from QTextEdit source code then...)

ultrasonic
4th March 2007, 13:57
THX fullmetalcoder.

I made my custom class which inherits QAbstractScrollArea, and drew my chart with paintEvent(). Now the scroll bar could be easily moved, but the content (my chart) is not changed. Did I forget something that should be handled?

Here is my code I just fixed tonight.

fullmetalcoder
4th March 2007, 16:00
Did I forget something that should be handled?
Certainly but I don't remember what exactly...:o Try having a look at other scrollable widget or use a cache image instead like this :

cmpaction.h :

#ifndef CMPACTION_H
#define CMPACTION_H

#include <QImage>
#include <QAbstractScrollArea>

class CmpAction : public QAbstractScrollArea
{
Q_OBJECT

public:
CmpAction(QWidget *parent = 0);
void openDir(QString dirpath);

public slots:
void setText(const QString &newText) { text = newText; }

protected:
virtual void paintEvent(QPaintEvent *event);
virtual void resizeEvent(QResizeEvent *event);

void updateGeometries();
void scrollContentsBy(int dx, int dy);

private:
int ARM[10000];
int BUS[10000];
int DWT[10000];
int TIER1[10000];
int OFF_CHIP[10000];
QString text;
int my_width;
int my_height;

void init();
void updateChart();

QImage img;
bool bDirty;
};

#endif


cmpaction.cpp :

#include <QtGui>
#include "cmpaction.h"

CmpAction::CmpAction(QWidget *parent)
: QAbstractScrollArea(parent),
bDirty(false)
{
setMinimumSize(800,400);
my_width=100+10000;
my_height=400;
horizontalScrollBar()->setRange(0, my_width-800);
horizontalScrollBar()->setPageStep(800);
verticalScrollBar()->setRange(0, my_height-400);
verticalScrollBar()->setPageStep(400);

//pix = QPixmap(viewport()->size());
img = QImage(viewport()->size(), QImage::Format_ARGB32);

init();
}


void CmpAction::init()
{
for(int i = 0;i<10000;i++) ARM[i] = BUS[i] = DWT[i] =
TIER1[i] = OFF_CHIP[i] = 0;
}

void CmpAction::resizeEvent(QResizeEvent *e)
{
QAbstractScrollArea::resizeEvent(e);

bDirty = true;

updateGeometries();
}

void CmpAction::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)

if ( bDirty )
{
updateChart();
}

QPainter p(viewport());
const int w = width(), h = height();
const int x = horizontalScrollBar()->value(), y = verticalScrollBar()->value();

//p.drawPixmap(QRect(0, 0, w, h), pix.copy(QRect(x, y, w, h)));
p.drawImage(QRect(0, 0, w, h), img.copy(QRect(x, y, w, h)));
}


void CmpAction::scrollContentsBy(int dx, int dy)
{
viewport()->scroll(dx,dy);
}


void CmpAction::updateGeometries()
{
horizontalScrollBar()->setPageStep(viewport()->width());
verticalScrollBar()->setPageStep(viewport()->height());
horizontalScrollBar()->setRange(0,qMax(0, my_width-viewport()->width()) );
verticalScrollBar()->setRange(0, qMax(0, my_height-viewport()->height()) );
}

void CmpAction::openDir(QString dirpath)
{

int i=0;
if(dirpath == NULL)
dirpath = QFileDialog::getExistingDirectory(this,
tr("Select File"),
QString(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);

qDebug() << dirpath;

QString arm,bus,dwt,t1,offchip;

arm = bus = dwt = t1 = offchip = dirpath;

arm.append(QString("arm_trace"));
bus.append(QString("bus_trace"));
dwt.append(QString("dwt_trace"));
t1.append(QString("t1_trace"));
offchip.append(QString("mem_trace"));

qDebug() << arm;
qDebug() << bus;
qDebug() << dwt;
qDebug() << t1;
qDebug() << offchip;


QFile f_arm(arm);
QFile f_bus(bus);
QFile f_dwt(dwt);
QFile f_t1(t1);
QFile f_offchip(offchip);
QString line;

if(f_arm.open(QFile::ReadOnly | QFile::Text))
{
QTextStream stream(&f_arm);
line = stream.readLine(0);
i=0;
while(!line.isEmpty())
{
if (line == "1")
{
ARM[i]=1;
}
i++;
line = stream.readLine(0);
}
}

if(f_bus.open(QFile::ReadOnly | QFile::Text))
{
QTextStream stream(&f_bus);
line = stream.readLine(0);
i=0;
while(!line.isEmpty())
{
if (line == "1")
{
BUS[i]=1;
}
i++;
line = stream.readLine(0);
}
}

if(f_dwt.open(QFile::ReadOnly | QFile::Text))
{
QTextStream stream(&f_dwt);
line = stream.readLine(0);
i=0;
while(!line.isEmpty())
{
if (line == "1")
{
DWT[i]=1;
}
i++;
line = stream.readLine(0);
}
}

if(f_t1.open(QFile::ReadOnly | QFile::Text))
{
QTextStream stream(&f_t1);
line = stream.readLine(0);
i=0;
while(!line.isEmpty())
{
if (line == "1")
{
TIER1[i]=1;
}
i++;
line = stream.readLine(0);
}
}

if(f_offchip.open(QFile::ReadOnly | QFile::Text))
{
QTextStream stream(&f_offchip);
line = stream.readLine(0);
i=0;
while(!line.isEmpty())
{
if (line == "1")
{
OFF_CHIP[i]=1;
}
i++;
line = stream.readLine(0);
}
}
f_arm.close();
f_bus.close();
f_dwt.close();
f_t1.close();
f_offchip.close();

bDirty = true;
}

/*
QSize CmpAction::sizeHint()
{
return QSize(800,400);
}*/

void CmpAction::updateChart()
{
qDebug("painting");

QPainter painter(&img);
//QPainter painter(&pix);

int i=10000;

const int start = 100;
const int act_unit_w = 1;
const int act_unit_h = 10;

QFontMetrics metrics(font());
QColor color;

QBrush Brush1(Qt::red,Qt::SolidPattern);
QBrush Brush2(Qt::green,Qt::SolidPattern);
QBrush Brush3(Qt::yellow,Qt::SolidPattern);
QBrush Brush4(Qt::blue,Qt::SolidPattern);
QBrush badBrush(Qt::black,Qt::SolidPattern);

for(int j=0;j<i;j++){
if(ARM[j]==1)
{
painter.fillRect(start+j*act_unit_w,100,act_unit_w ,act_unit_h,Brush1);
}

if(BUS[j]==1)
{
painter.fillRect(start+j*act_unit_w,150,act_unit_w ,act_unit_h,Brush2);
}
if(DWT[j]==1)
{
painter.fillRect(start+j*act_unit_w,200,act_unit_w ,act_unit_h,Brush3);
}
if(TIER1[j]==1)
{
painter.fillRect(start+j*act_unit_w,250,act_unit_w ,act_unit_h,Brush4);
}
if(OFF_CHIP[j]==1)
{
painter.fillRect(start+j*act_unit_w,300,act_unit_w ,act_unit_h,badBrush);
}
}

painter.save();
painter.setBrush(badBrush);
painter.setPen(QColor(Qt::black));

for( int j=start; j< 10000+start ; j += act_unit_w*100 ){
painter.drawLine(j,400,j,395);
painter.drawText(j,420,QString::number(j-start,10));
}
painter.drawText(0,100+30,QString("ARM"));
painter.drawText(0,150+30,QString("BUS"));
painter.drawText(0,200+30,QString("DWT"));
painter.drawText(0,250+30,QString("TIER1"));
painter.drawText(0,300+30,QString("MEMORY"));
painter.drawText(0,0,640,50,Qt::AlignCenter,QStrin g("Bus Activation Graph"));
painter.drawLine(start,75,start,400);
painter.drawLine(start,400,10000,400);

painter.restore();

//pix.save("chart.png");
img.save("chart.png");
bDirty = false;
}


P.S : It is recommended not to include the QtGui file unless you need so many classes that it become too long to write all includes :rolleyes: because it slows down the compilation a great deal...

P.S(2) : I've not been able to try this code with real data so you may need to fix/improve the drawing of the chart...

ultrasonic
5th March 2007, 07:25
I just figured out another way to resolve my problem. I called QPainter::translate() to translate my painter. Now my chart can display correctly.

Thanks fullmetalcoder again;) .

vinithr
9th August 2012, 18:49
Hi,

First of all thanks for this post. I was also trying to draw bar graph in my qt application.It helped me lot.

I am also facing the same bug that you have written. Could you please share the solution that you have found. You told that translate function can be used.?

Thanks in advance

Regards.
Vinithr

alitoh
9th August 2012, 20:06
From the looks of it, it seems like he translated the graph into a more appropiate position so now he just desn't need to scroll. Translate is just that, "move around this thing considering the coordinates system".

Also, thread revival black magic, bro. 5 years later.