Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Qwt и Qmdiarea
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt GUI
gvenihvivar
Добрый день.

Я взяла пример из библиотеки qwt и переделала немного под нужный мне вариант. Но в итоговом интерфейсе виджет должен работать в одном из subwindow элемента qmdiarea, но он не работает. Отдельно, как полноценный виджет, пожалуйста, а вот внутри никак. Причем не работает он частично, не рисуется сами графики в реальном времени и нет подложки для графика, хотя поле для этого выделено.

Вот код класса
cpuplot.h
Раскрывающийся текст

#ifndef CPUPLOT_H
#define CPUPLOT_H
#define HISTORY 300 // seconds
#include <qwt_plot.h>
#include <qapplication.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qpainter.h>
#include <qwt_plot_layout.h>
#include <qwt_plot_curve.h>
#include <qwt_scale_draw.h>
#include <qwt_scale_widget.h>
#include <qwt_legend.h>
#include <qwt_legend_item.h>
#include <qwt_plot_canvas.h>
#include <QObject>
#include <QTime>


class CpuPlot : public QwtPlot
{
Q_OBJECT
public:
CpuPlot(QWidget *parent = 0);
enum CpuData
{
Pressure,
Flow,
Temp,
Density,

NCpuData
};


void statistic(double &flow, double &pressure, double &temp, double &density);
QTime upTime() const;
private slots:
void showCurve(QwtPlotItem *, bool on);
protected:
void timerEvent(QTimerEvent *e);
private:
struct
{
QwtPlotCurve *curve;
double data[HISTORY];
} data[NCpuData];
int dataCount;
double timeData[HISTORY];
float Q;
float Ro;
float P;
float Te;
public slots:
void slotPoint(float Q1,float Ro1,float P1,float T1,QDateTime dt, quint8 table);
};

#endif // CPUPLOT_H



cpuplot.cpp
Раскрывающийся текст

#include "cpuplot.h"


class TimeScaleDraw: public QwtScaleDraw
{
public:
TimeScaleDraw(const QTime &base):
baseTime(base)
{
}
virtual QwtText label(double v) const
{
QTime upTime = baseTime.addSecs((int)v);
return upTime.toString();
}
private:
QTime baseTime;
};

class Background: public QwtPlotItem
{
public:
Background()
{
setZ(0.0);
}

virtual int rtti() const
{
return QwtPlotItem::Rtti_PlotUserItem;
}

virtual void draw(QPainter *painter,
const QwtScaleMap &, const QwtScaleMap &yMap,
const QRectF &rect) const
{
QColor c(Qt::white);
QRectF r = rect;

for ( int i = 25; i > 0; i -= 5 )
{
r.setBottom(yMap.transform(i - 5));
r.setTop(yMap.transform(i));
painter->fillRect(r, c);

c = c.dark(110);
}
}
};

class CpuCurve: public QwtPlotCurve
{
public:
CpuCurve(const QString &title):
QwtPlotCurve(title)
{
setRenderHint(QwtPlotItem::RenderAntialiased);
}

void setColor(const QColor &color)
{
QColor c = color;
c.setAlpha(150);
setPen©;
// setBrush©; //fill space under curve
}
};

CpuPlot::CpuPlot(QWidget *parent):
QwtPlot(parent),
dataCount(0)
{

setAutoReplot(false);

canvas()->setBorderRadius( 10 ); // skruglenije reqtangle

plotLayout()->setAlignCanvasToScales(true); // rastjagivaet seryj color do krajev reqt

QwtLegend *legend = new QwtLegend;
legend->setItemMode(QwtLegend::CheckableItem);
insertLegend(legend, QwtPlot::RightLegend);

setAxisTitle(QwtPlot::xBottom, " Time [h:m:s]");
setAxisScaleDraw(QwtPlot::xBottom,
new TimeScaleDraw(/*cpuStat.*/upTime()/*up*/)); // time on scale
setAxisScale(QwtPlot::xBottom, 0, HISTORY); // horizontal scale 60
setAxisLabelRotation(QwtPlot::xBottom, -50.0); // pod uglov scale
setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom); // ???????????????????

QwtScaleWidget *scaleWidget = axisWidget(QwtPlot::xBottom); //??
const int fmh = QFontMetrics(scaleWidget->font()).height();
scaleWidget->setMinBorderDist(0, fmh / 2);

setAxisTitle(QwtPlot::yLeft, "Parameters "); // vertical scale
setAxisScale(QwtPlot::yLeft, 0, 25);

Background *bg = new Background(); // grey background
bg->attach(this);

CpuCurve *curve;

curve = new CpuCurve("Pressure");
curve->setColor(Qt::red);
curve->attach(this);
curve->setStyle(QwtPlotCurve::Lines);
data[Pressure].curve = curve;

curve = new CpuCurve("Flow");
curve->setColor(Qt::blue);
curve->setZ(curve->z() - 1);
curve->attach(this);
data[Flow].curve = curve;

curve = new CpuCurve("Temp");
curve->setColor(Qt::black);
curve->setZ(curve->z() - 2);
curve->attach(this);
data[Temp].curve = curve;

curve = new CpuCurve("Density");
curve->setColor(Qt::darkGreen);
curve->setZ(curve->z() - 3);
curve->attach(this);
data[Density].curve = curve;

showCurve(data[Pressure].curve, true);
showCurve(data[Flow].curve, true);
showCurve(data[Temp].curve, true);
showCurve(data[Density].curve, true);

for ( int i = 0; i < HISTORY; i++ )
timeData[HISTORY - 1 - i] = i;

(void)startTimer(1000); // 1 second

connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)),
SLOT(showCurve(QwtPlotItem *, bool)));
}
void CpuPlot::timerEvent(QTimerEvent *)
{
for ( int i = dataCount; i > 0; i-- )
{
for ( int c = 0; c < NCpuData; c++ )
{
if ( i < HISTORY )
data[c].data[i] = data[c].data[i-1];
}
}

if ( dataCount < HISTORY )
dataCount++;

for ( int j = 0; j < HISTORY; j++ )
timeData[j]++;

setAxisScale(QwtPlot::xBottom,
timeData[HISTORY - 1], timeData[0]);

for ( int c = 0; c < NCpuData; c++ )
{
data[c].curve->setRawSamples(
timeData, data[c].data, dataCount);
}

replot();
}
void CpuPlot::showCurve(QwtPlotItem *item, bool on)
{
item->setVisible(on);
QWidget *w = legend()->find(item);
if ( w && w->inherits("QwtLegendItem") )
((QwtLegendItem *)w)->setChecked(on);

replot();
}

void CpuPlot::slotPoint(float Q1, float Ro1, float P1, float T1, QDateTime dt,quint8 table)
{
data[Flow] .data[0] = Q1;
data[Pressure].data[0] = P1;
data[Temp] .data[0] = T1;
data[Density] .data[0] = Ro1/100;

}
QTime CpuPlot::upTime() const
{
QTime t(QTime::currentTime().addSecs(-HISTORY));
//for ( int i = 0; i < NValues; i++ )
t = t.addSecs(1);

return t;

}

void CpuPlot::statistic(double &flow, double &pressure, double &temp,double &density)
{
flow = Q;
pressure = P;
temp = Te;
density = Ro/100;
}


Так он работает

часть main
Раскрывающийся текст

QWidget vBox;
vBox.setWindowTitle("Cpu Plot");
CpuPlot *plot = new CpuPlot(&vBox);
plot->setTitle("History");

const int margin = 5;
plot->setContentsMargins(margin, margin, margin, margin);

QObject::connect(&ct, SIGNAL(toGraph(float, float, float, float, QDateTime,quint8)),
plot, SLOT(slotPoint(float,float,float,float,QDateTime,quint8)));

QHBoxLayout *lay = new QHBoxLayout;
lay->addWidget(plot);
vBox.setLayout(lay);
vBox.show();


А так он написан в виде части mdiarea

Раскрывающийся текст

QMdiSubWindow *subWindow1 = new QMdiSubWindow;
subWindow1->setWindowTitle(tr(" График параметров Замерного узла"));

CpuPlot *plot = new CpuPlot(subWindow1);
plot->setTitle("History");

const int margin = 5;
plot->setContentsMargins(margin, margin, margin, margin);


QObject::connect(this, SIGNAL(toGraph(float, float, float, float, QDateTime,quint8)),
plot, SLOT(slotPoint(float,float,float,float,QDateTime,quint8)));

QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(plot);

subWindow1->setWidget(plot);
subWindow1->setAttribute(Qt::WA_DeleteOnClose);
ui->mdiarea->addSubWindow(subWindow1);
subWindow1->show();


Возможно я не знаю какой-то элементарной вещи.
Trisch
Цитата(gvenihvivar @ 22.8.2014, 10:41) *
QObject::connect(&ct, SIGNAL(toGraph(float, float, float, float, QDateTime,quint8)),
plot, SLOT(slotPoint(float,float,float,float,QDateTime,quint8)));


Что такое "ct"?
gvenihvivar
Цитата(Trisch @ 22.8.2014, 12:56) *
Цитата(gvenihvivar @ 22.8.2014, 10:41) *
QObject::connect(&ct, SIGNAL(toGraph(float, float, float, float, QDateTime,quint8)),
plot, SLOT(slotPoint(float,float,float,float,QDateTime,quint8)));


Что такое "ct"?


"ct" это класс сервера, который принимает данные. Находится он в другом потоке и через это соединение передает данные в основной поток, а потом и непосредственно в класс с графиком
Trisch
А когда виджет графика является частью mdiarea слот slotPoint отрабатывает?
gvenihvivar
да, отрабатывает. В массив данные собираются. И событие по таймеру тоже отрабатывает. Получается, что теоретически он перерисовывает и есть, что там перерисовывать
lanz
Не увидел вызова setLayout во втором варианте.
gvenihvivar
layout это не рабочий код, с ним тоже не работает, говорит, что у subwindow mdi уже есть layout и другого ему не нужно
Trisch
Цитата(gvenihvivar @ 22.8.2014, 21:02) *
layout это не рабочий код, с ним тоже не работает, говорит, что у subwindow mdi уже есть layout и другого ему не нужно


такая ошибка может быть из-за того что вы передаете объекту layout при инициализации не того "родителя", но, зачастую, программа все равно отрабатывает правильно.

В общем, можете скинуть весь проект в архиве?
gvenihvivar
Возможно. С началом рабочей недели во вторник выложу проект.
lanz
Цитата(gvenihvivar @ 22.8.2014, 22:02) *
layout это не рабочий код, с ним тоже не работает, говорит, что у subwindow mdi уже есть layout и другого ему не нужно

this->layout()->addWidget(...)
gvenihvivar
Совет с this->layout не помог. Так что выкладываю проект. Один график, который исправно работает, лежит в main. Второй в виде слота slotRealGraph() в mainwindow сразу после описания класса. Чтобы вызвать слот, необходимо нажать кнопку "График", которая находится в левой части экрана под черными прямоугольниками

тут лежит проект
gvenihvivar
Уважаемые специалисты, скажите мне хоть что-нибудь. Это возможно, но тяжело или вообще не возможно заставить работать так как надо? Или хотя бы в какую сторону копать? Я уже перепробовала настройки самого mdi area и subwindow, ничего не помогло.
lanz
Т.к. оси рисуются, к Layoutам эта проблема не имеет отношения.

Это возможно, просто вы не правильно используете QThread.
Когда переопределяете метод run, помните что как только вы выходите из этого метода QThread заканчивается.
Для того чтобы запустить Event Loop в этом потоке(а он нужен для таймеров и сигналов), вызывайте QThread::exec.
А лучше почитайте вот эту статью:
http://mayaposch.wordpress.com/2011/11/01/...ull-explanation

В main работает, потому что там уже есть Event Loop запущенный через a.exec()

В приложении рабочий пример того что вам нужно через QThread::exec.
gvenihvivar
спасибо за пример, я его обязательно изучу. Но график рисуется в основном потоке (только данные поступают из вспомогательного) и не только в main, а и в mainwindow, но как только я передаю его в mdi area через addsubwindow график перестает работать.
lanz
Сделайти минимальный проект на котором это проявляется. Ваш проект я не смог запустить у себя.
Попробуйте изменить мой пример так, чтобы он демонстрировал сходное поведение.

Сделайте печаталку в slotPoint чтобы убедится что слот вызывается.
gvenihvivar
 auto sub = new QMdiSubWindow( this->ui->mdiArea );

что означает auto. С ним не хотело работать.

А в целом заработало. Оказывается, проблема была в styleSheet. После создания главного окна в дизайнере, я там прописала его фон. Не знаю тонкостей, но после того, как я вытерла эту настройку, все прекрасно заработало.

Кстати, lanz, ты хорошо разбираешься в потоках?
Я делала перенос потока методом movetothread(). Этот поток начинает работать с открытием приложение, и заканчивает после закрытия. Так вот программа после закрытия утверждает QThread: Destroyed while thread is still running. Хотя я уже сигналы и так, и этак привязывала к закрытие приложение. Можешь что-нибудь подсказать?
ahalaj
Цитата(gvenihvivar @ 8.9.2014, 15:04) *
 auto sub = new QMdiSubWindow( this->ui->mdiArea );

что означает auto. С ним не хотело работать.

Это из C++11, чтобы не приходилось объявлять

QMdiSubWindow* sub = new QMdiSubWindow( this->ui->mdiArea );


компилятор сам присвоит переменной sub тип QMdiSubWindow*. По аналогии с объявлением переменных var в C#.
lanz
Цитата(gvenihvivar @ 8.9.2014, 15:04) *
Я делала перенос потока методом movetothread(). Этот поток начинает работать с открытием приложение, и заканчивает после закрытия. Так вот программа после закрытия утверждает QThread: Destroyed while thread is still running. Хотя я уже сигналы и так, и этак привязывала к закрытие приложение. Можешь что-нибудь подсказать?

Обычно в деструкторе основного окна я делаю thread->quit(), которое завершает Event loop, а потот thread->wait(), чтобы поток успел обработать это сообщение, тогда такого не будет.


moveToThread нужно делать не с наследником QThread, почитайте статью Майи, на которую я давал ссылку.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.