Почему ROOT только позволит мне установить последний элемент вектора TCanvas на другой вектор TCanvas, если я передам вектор другому классу?

Эта проблема

Я хочу начать динамическую передачу 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();

    }
}

Это результат этого метода:

Попытка 2

Единственная ошибка, которую я вижу в данный момент, это то, что я получаю это для 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

1 ответ

Решение

Я пытаюсь заняться чем-то по одному. Ваше сообщение об ошибке 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), тогда вы вызываете конструктор с родителем (в вашем случае 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.

Так что, даже если вы явно не установите эти макеты в качестве основного макета вашего DataTestTabQt пытается сделать это, потому что так написан конструктор, и это приводит к сообщению, которое вы видите.

Очевидное лекарство от этой проблемы - изменить

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 пример.

Это помогает?

Другие вопросы по тегам