0

问题

我想开始动态地将 TCanvas 从程序的“模型”部分动态传递到“视图”部分。我考虑这样做的方式是在启动时在 View 上创建我的 TCanvas,然后在填充图表后使用 View 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
4

1 回答 1

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#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示例中所示。

这有帮助吗?

于 2014-10-10T20:05:21.040 回答