问题
我想开始将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();
}
}
这是此方法的输出:
我目前看到的唯一错误是我收到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
上显示两个直方图。例。这有帮助吗?
关于c++ - 如果我将 vector 传递给另一个类,为什么只有ROOT允许我将TCanvas vector 的最终元素设置为另一个TCanvas vector ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26255470/