Я хочу начать динамическую передачу TCanvas, по сути, из части «Модель» моей программы в часть «Вид». То, как я думал об этом, состояло в том, чтобы просто создать свой TCanvas в представлении при запуске, а затем обновить этот TCanvas представлением TCanvas после заполнения графиков. Я создал тестовый стенд, чтобы посмотреть, будет ли он работать.
Я показал рабочий метод и сломанный метод.
Я использую QT-ROOT, TQtWidget это пользовательский виджет, который по сути является возвращением к TCanvas.
void DataTestTab::setupCanvas(int cNCbc) //I pass "2" to this for now to generate the below loop twice
{
for (int i=0; i<cNCbc; i++)
{
m_vectorCanvas.push_back(new TQtWidget(this));
//m_vectorCanvas[i]->GetCanvas()->SetFillColor(i);
QHBoxLayout *loH = new QHBoxLayout(this);
loH->addWidget(m_vectorCanvas[i]);
m_vectorLayout.push_back(loH);
QGroupBox *gbCanvas = new QGroupBox(this);
QString title = QString("CBC %1").arg(i);
gbCanvas->setTitle(title);
gbCanvas->setLayout(m_vectorLayout[i]);
m_vectorGroupBox.push_back(gbCanvas);
ui->loCbcBox->addWidget(m_vectorGroupBox[i]); //adding the panels to the main layout
}
}
void DataTestTab::drawTest()
{
static Int_t HistoID = 1;
qDebug() << "in Testing env ";
std::vector<TH1D*> graphs;
std::vector<TCanvas*> vCanvas;
TString name("h1_");
Bool_t build = false;for (int i = 0; i <m_vectorCanvas.size() ; i++)
{
TCanvas *cCanvas = new TCanvas(build);
name += HistoID++;
vCanvas.push_back(cCanvas);
vCanvas.at(i)->cd();TH1D *h1 = new TH1D(name.Data(),name.Data(),10,0, 10);
graphs.push_back(h1);
graphs.at(i)->Fill(i);
graphs.at(i)->Draw();
//graphs.at(i)->DrawCopy();
m_vectorCanvas.at(i)->GetCanvas()->SetFillColor(i+5);
m_vectorCanvas.at(i)->cd();
qDebug() << i;
m_vectorCanvas.at(i)->GetCanvas()->SetCanvas(vCanvas.at(i));
m_vectorCanvas.at(i)->Refresh();
}
}
Соответствующий вывод:
Хотя графики в неправильном порядке.
Я передаю этот метод другому классу и передаю TCanvas обратно через сигнал / слоты.
void DataTestWorker::doWork()
{
static Int_t HistoID = 1;
qDebug() << "in Testing env ";
std::vector<TH1D*> graphs;
std::vector<TCanvas*> vCanvas;
TString name("h1_");
Bool_t build = false;
for (int i = 0; i <2 ; i++)
{
TCanvas *cCanvas = new TCanvas(build);
name += HistoID++;
vCanvas.push_back(cCanvas);
vCanvas.at(i)->cd();
TH1D *h1 = new TH1D(name.Data(),name.Data(),10,0, 10);
graphs.push_back(h1);
graphs.at(i)->Fill(i);
graphs.at(i)->Draw();
}
emit sendGraphData(vCanvas); //void sendGraphData(const std::vector<TCanvas*> &canvas);
Данные графика затем отправляются сюда:
void DataTestTab::drawGraph(const std::vector<TCanvas*> &canvas)
{
for (int i=0; i<m_vectorCanvas.size(); i++)
{
canvas.at(i)->cd();
m_vectorCanvas.at(i)->cd();
m_vectorCanvas.at(i)->GetCanvas()->SetCanvas(canvas.at(i));
m_vectorCanvas.at(i)->Refresh();
//m_vectorCanvas.at(i)->GetCanvas()->Update();
}
}
Это результат этого метода:
Единственная ошибка, которую я вижу в данный момент, это то, что я получаю это для SetupTab:
QLayout: Attempting to add QLayout "" to GUI::DataTestTab "DataTestTab", which already has a layout
QLayout: Attempting to add QLayout "" to GUI::DataTestTab "DataTestTab", which already has a layout
Я пытаюсь заняться чем-то по одному. Ваше сообщение об ошибке QLayout: Attempting to add QLayout "" to GUI::DataTestTab "DataTestTab", which already has a layout
проистекает из того факта, что вы вызываете этот конструктор для вашего QHBoxLayout:
QHBoxLayout *loH = new QHBoxLayout(this);
Если вы посмотрите на документацию для QLayout
(например. http://qt-project.org/doc/qt-4.8/qlayout.html#QLayout) тогда вы вызываете конструктор с родителем (в вашем случае this
) и документация гласит:
QLayout::QLayout ( QWidget * parent )
Constructs a new top-level QLayout, with parent parent. parent may not be 0.
There can be only one top-level layout for a widget.
Так что, даже если вы явно не установите эти макеты в качестве основного макета вашего DataTestTab
Qt пытается сделать это, потому что так написан конструктор, и это приводит к сообщению, которое вы видите.
Очевидное лекарство от этой проблемы — изменить
QHBoxLayout *loH = new QHBoxLayout(this);
в
QHBoxLayout *loH = new QHBoxLayout;
который затем вызывает этот конструктор:
QLayout::QLayout ()
Constructs a new child QLayout.
This layout has to be inserted into another layout before geometry management will work.
то есть QLayout
это может быть добавлено к другому (и должно для того, чтобы работать).
РЕДАКТИРОВАТЬ:
Я думаю, что вы можете упростить способ передачи предметов. Нет причин строить TCanvas
для каждой гистограммы и передать ее, особенно с TCanvas
не будет владеть вашей гистограммой, и я считаю, что когда вы выпускаете TH1::Draw()
даже имея cd()
Введенный в полотно вы хотите, это не достигает того, что вы пытаетесь сделать.
Я играл с вашим кодом, и я мог бы добиться того, чего вы хотите, просто имея:
void DataTestWorker::doWork()
{
static Int_t HistoID = 1;
std::vector<TH1D*> graphs;
TString name("h1_");
for (int i = 0; i <2 ; i++)
{
name += HistoID++;
TH1D *h1 = new TH1D(name.Data(),name.Data(),10,0, 10);
graphs.push_back(h1);
graphs.at(i)->Fill(i);
}
emit sendGraphData(graphs); //void sendGraphData(std::vector<TH1D*>);
}
а также
void DataTestTab::drawGraph(std::vector<TH1D*> hists)
{
for (size_t i=0; i<m_vectorCanvas.size(); i++)
{
TH1D *h = hists.at(i);
m_vectorCanvas.at(i)->cd();
h->Draw();
m_vectorCanvas.at(i)->Refresh();
}
}
Я, очевидно, не выполняю никаких проверок, чтобы убедиться, что std::vector<TH1D*>
а также std::vector<TQtWidget*>
имеют одинаковую длину и т. д., но с помощью этого кода я смог отобразить две гистограммы на двух TCanvas
как вы показали в своем This Works
пример.
Это помогает?