I have a problem using smart pointers with Qt. I can´t figure out what is the reason for that strange behaviour.
Simple Setup:
I created a new Qt Widgets Application and dragged a QGraphicsView into the main window and only added the following Code to paint a circle:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QGraphicsScene"
#include "QGraphicsEllipseItem"
#include "boost/shared_ptr.hpp"
#include "QSharedPointer"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene* scene = new QGraphicsScene(ui->graphicsView);
ui->graphicsView->setScene(scene);
/* 1. raw pointer */
QGraphicsEllipseItem* ell = new QGraphicsEllipseItem(100,100,50,50);
scene->addItem(ell);
/* 2. boost shared pointer
boost::shared_ptr<QGraphicsEllipseItem> eSP(new QGraphicsEllipseItem(100,100,50,50));
scene->addItem(eSP.get());*/
/* 3. Qt shared pointer
QSharedPointer<QGraphicsEllipseItem> eSP(new QGraphicsEllipseItem(100,100,50,50));
scene->addItem(eSP.data());*/
/* 4a. raw pointer as init parameter for shared pointer
QGraphicsEllipseItem* ell = new QGraphicsEllipseItem(100,100,50,50);
boost::shared_ptr<QGraphicsEllipseItem> eSP(ell);
scene->addItem(eSP.get()); // using shared pointer */
/* 4b. raw pointer as init parameter for shared pointer
QGraphicsEllipseItem* ell = new QGraphicsEllipseItem(100,100,50,50);
boost::shared_ptr<QGraphicsEllipseItem> eSP(ell);
scene->addItem(ell); // using raw pointer */
}
MainWindow::~MainWindow()
{
delete ui;
}
As you can see I tried some variants. The first one ist the only one that works. It paints a circle in the center of the QGraphicsView. But for my project I need a smart pointer implementation. But all the smart pointer implementations do not paint the circle.
Am I making any mistake???
Especially 4b confuses me most. The only difference to 1 is that I am putting the raw pointer additionally into a shared pointer and that won´t work
Please help me!
My environment:
- Linux Mint 17.1
- qt-sdk 2ubuntu3
- boost 1.54.0.1
Related
I've installed VTK 8.2.0 with CMake for use with QT but when trying to run some VTK examples I have some issues shown below:
Note: The colour banding issues in the image is from the gif compression and is not part of the issue
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkCubeSource.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
int main(int, char *[])
{
// Create a cube.
vtkSmartPointer<vtkCubeSource> cubeSource =
vtkSmartPointer<vtkCubeSource>::New();
// Create a mapper and actor.
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(cubeSource->GetOutputPort());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
// Create a renderer, render window, and interactor
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
// Add the actors to the scene
renderer->AddActor(actor);
renderer->SetBackground(.3, .2, .1);
// Render and interact
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
https://vtk.org/Wiki/VTK/Examples/Cxx/GeometricObjects/Cube
For all of the examples, it appears that the previous frame is not being cleared and the background is not being shown over it.
I don't appear to get any error messages when compiling or running the program. Might it be a driver issue?
Any help would be much appreciated!
Our company is in need to capture the rendering of a Qt3d scene. For this I created a small example application, that illustrates the usage of our capturing.
On the left-hand side you will find the 3D scene and on the right-hand side there is a QLabel with a QPixmap showing the captured screen.
Now, for some reason I really don't understand the captured screenshot really looks different compared to the 3D scene on the left hand side. Even more confusing the saved PNG images looks different compared to QLabel on the right hand side, but actually I'm more interested in the PNG for my use case.
It saves me the following PNG file:
I already tried to insert the QRenderCapture in different place of the frame graph, but none of the places gave reasonable results.
This is my frameGraph->dumpObjectTree output:
Qt3DExtras::QForwardRenderer::
Qt3DRender::QRenderSurfaceSelector::
Qt3DRender::QViewport::
Qt3DRender::QCameraSelector::
Qt3DRender::QClearBuffers::
Qt3DRender::QFrustumCulling::
Qt3DRender::QCamera::
Qt3DRender::QCameraLens::
Qt3DCore::QTransform::
Qt3DRender::QRenderCapture:: // Insertion of QRenderCapture
Qt3DRender::QFilterKey::
It seems, that I capture the 3d scene somewhere during the rendering, so that there might be some timing issues. (Maybe the usage of QEventLoop is not admissible in this use case, but I really don't know why.)
The documentation of QRenderCapture implies, that QRenderCapture should be the last leafnode of the frame graph, but this is what I did.
From QRenderCapture documentation:
The QRenderCapture is used to capture rendering into an image at any render stage. Capturing must be initiated by the user and one
image is returned per capture request. User can issue multiple render
capture requests simultaneously, but only one request is served per
QRenderCapture instance per frame.
And also:
Used to request render capture. Only one render capture result is
produced per requestCapture call even if the frame graph has multiple
leaf nodes. The function returns a QRenderCaptureReply object, which
receives the captured image when it is done. The user is responsible
for deallocating the returned object.
Can someone here help me out?
#include <QApplication>
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <Qt3DRender/QRenderCapture>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QSphereMesh>
#include <Qt3DExtras/QDiffuseSpecularMaterial>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/Qt3DWindow>
Qt3DCore::QEntity* transparentSphereEntity() {
auto entity = new Qt3DCore::QEntity;
auto meshMaterial = new Qt3DExtras::QDiffuseSpecularMaterial();
meshMaterial->setAlphaBlendingEnabled(true);
meshMaterial->setDiffuse(QColor(255, 0, 0, 50));
auto mesh = new Qt3DExtras::QSphereMesh();
mesh->setRadius(1.0);
entity->addComponent(mesh);
entity->addComponent(meshMaterial);
return entity;
}
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
auto frame = new QFrame;
auto view = new Qt3DExtras::Qt3DWindow();
auto camera = new Qt3DRender::QCamera;
camera->lens()->setPerspectiveProjection(45.0f, 1., 0.1f, 10000.0f);
camera->setPosition(QVector3D(0, 0, 10));
camera->setUpVector(QVector3D(0, 1, 0));
camera->setViewCenter(QVector3D(0, 0, 0));
view->defaultFrameGraph()->setCamera(camera);
auto frameGraph = view->defaultFrameGraph();
frameGraph->dumpObjectTree();
auto camSelector = frameGraph->findChild<Qt3DRender::QCamera*>();
auto renderCapture = new Qt3DRender::QRenderCapture(camSelector);
frameGraph->dumpObjectTree();
auto rootEntity = new Qt3DCore::QEntity();
view->setRootEntity(rootEntity);
auto sphere = transparentSphereEntity();
sphere->setParent(rootEntity);
auto btnScreenshot = new QPushButton("Take Screenshot");
auto labelPixmap = new QLabel;
frame->setLayout(new QHBoxLayout);
frame->layout()->addWidget(QWidget::createWindowContainer(view));
frame->layout()->addWidget(btnScreenshot);
frame->layout()->addWidget(labelPixmap);
frame->setMinimumSize(1000, 1000 / 3);
frame->show();
QObject::connect(btnScreenshot, &QPushButton::clicked, [&]() {
QEventLoop loop;
auto reply = renderCapture->requestCapture();
QObject::connect(reply, &Qt3DRender::QRenderCaptureReply::completed, [&] {
reply->image().save("./data/test.png");
labelPixmap->setPixmap(QPixmap::fromImage(reply->image()));
loop.quit();
});
loop.exec();
});
return a.exec();
}
I am working on a project using C++ and QT. Part of the project involves a structure which keeps track of methods to update widgets. I have included a sample program below which highlights the issue, which is the problem distilled.
In the program, I have a list of 'relations', which contains lambdas to change widgets, based on data obtained elsewhere. This works fine (and may be dumped), but the problem is when one lambda is calling another.
An example is below. This program only has a combobox with the three strings, which calls 'slot1()' when changed. Slot one then calls the function pushed into the vector with the row, and calls that function with the parameter.
The Vector is
QVector<std::function<void(int)>> func;
When func.pushback takes setProductIndex as a parameter, the program works (I understand this is essentially a no op). The function is called. When it takes setProductIndex2, the program segfaults when the combobox is changed.
I have verified that the functions are indeed being called, but I'm unsure why it would segfault with setProductIndex2. All that is doing, is calling setProductIndex with the passed value which DOES work.
I can work around this, but I would like to know where I'm going wrong for better understanding.
I'm using GCC v4.8.3 and qt 5.3.2 on Fedora Linux.
Thanks.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
qDebug() << "1";
ui->setupUi(this);
QStringList model;
model.append("Test1");
model.append("Test2");
model.append("Test3");
ui->comboBox->addItems(model);
qDebug() << "2";
std::function<void(int)> setProductIndex = [&] (int x) ->void { ui->comboBox->setCurrentIndex(x);
ui->comboBox->setCurrentIndex(x); return;} ;
std::function<void(int)> setProductIndex2 = [&] (int x) ->void {setProductIndex(x);};
func.push_back(setProductIndex2);
qDebug() << "Func size " << func.size();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slot1(int xx)
{
//ui->comboBox->setCurrentIndex(--xx);
func[0](xx);
}
My problem is that I have two QTreeWidgets and I would like to do drag and drop from one to an other (and vice-versa). I am able of drag and dropping QTreeWidgetItems, but, when I drop a QTreeWidgetItem that has children, I lose them and only the parent is dropped.
I don't really see how to do it. The only way I have found is reimplementing dropEvent and destroying all teh dropped objects and reconsructing them .. but I don't like that solution because it's slow and the objets are not the same, so it complicates very much the implementation of a Undo/redo feature...
Well, this is what I have:
#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QWidget>
#include <QString>
#include <QTextStream>
#include <QIODevice>
#include <QMainWindow>
#include <QVBoxLayout>
#include "KTreeWidget.h"
#include "KAbstractItem.h"
#include "KItem.h"
#include "KItemGroup.h"
int main(int argc, char* argv[]){
QApplication app(argc, argv);
QMainWindow *window = new QMainWindow();
QWidget* central = new QWidget(window);
QVBoxLayout *layout = new QVBoxLayout();
KTreeWidget* kv = new KTreeWidget(window);
KTreeWidget* trash = new KTreeWidget(window);
layout->addWidget(kv);
layout->addWidget(trash);
central->setLayout(layout);
KItem* kiarr[5];
for (int i = 0 ; i < 5 ; i++){
kiarr[i] = new KItem(kv);
kiarr[i]->setText(0,QString("Item %1").arg(i));
}
KItemGroup* kgarr[5];
for (int i = 0 ; i < 5 ; i++){
kgarr[i] = new KItemGroup(trash);
kgarr[i]->setText(0,QString("Group %1").arg(i));
}
window->setCentralWidget(central);
window->show();
return app.exec();
}
My QTreeWidget:
KtreeWidget.h
#ifndef _KTW_H_
#define _KTW_H_
#include <QTreeWidget>
class KTreeWidget: public QTreeWidget{
Q_OBJECT
private:
QTreeWidgetItem* _header;
public:
KTreeWidget(QWidget* w = NULL);
};
#endif
and KTreeWidget.cc:
#include "KTreeWidget.h"
KTreeWidget::KTreeWidget(QWidget* w):QTreeWidget(w){
setColumnCount(3);
_header = new QTreeWidgetItem(NULL);
_header->setText(0,"Title");
_header->setText(1,"Edit");
_header->setText(2,"Open");
this->setDefaultDropAction(Qt::MoveAction);
setHeaderItem(_header);
setDragEnabled(true);
setAcceptDrops(true);
}
And the items (3 classes, in order to distinguish groups and leafs):
KAbstractItem.h
#ifndef _KABSI_H_
#define _KABSI_H_
#include <QObject>
#include <QTreeWidgetItem>
#include <QTreeWidget>
class KAbstractItem : public QObject, public QTreeWidgetItem{
Q_OBJECT
public:
KAbstractItem(QTreeWidget* p = NULL);
};
#endif
and KAbstractItem.cc
#include "KAbstractItem.h"
KAbstractItem::KAbstractItem(QTreeWidget* p):QTreeWidgetItem(p){}
KItem.h
#ifndef _KI_H_
#define _KI_H_
#include "KAbstractItem.h"
class KItem : public KAbstractItem{
Q_OBJECT
public:
KItem(QTreeWidget* p);
};
#endif
and KItem.cc
#include "KItem.h"
KItem::KItem(QTreeWidget* p):KAbstractItem(p){
setFlags(Qt::ItemIsSelectable
| Qt::ItemIsEditable
| Qt::ItemIsDragEnabled
| Qt::ItemIsUserCheckable
| Qt::ItemIsEnabled);
}
and KItemGroup.h
#ifndef _KIG_H_
#define _KIG_H_
#include "KAbstractItem.h"
class KItemGroup : public KAbstractItem{
Q_OBJECT
public:
KItemGroup(QTreeWidget* p);
};
#endif
and KItemGroup.h
#include "KItemGroup.h"
KItemGroup::KItemGroup(QTreeWidget* p):KAbstractItem(p){
setFlags(Qt::ItemIsSelectable
| Qt::ItemIsEditable
| Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled
| Qt::ItemIsUserCheckable
| Qt::ItemIsEnabled);
}
Whenever I do a drop of one of the Items in the first WTreeWifget inside one of the groups of the second one, it works, but it then I move a group to the top QTreeWidget, I lose all the children...
Could you tell me what I am doing wrong?
Thanks in advance!
So, i checked it and it isnt working as required, you are not doing any wrong.
I seems the problem is that QAbstractItemModel (in wich QTreeWidget relies to encode the dragged data internally) mimeData() method is not considering nested items (se that it just encode row + column, but not parent.
It could be even that view is only passing the QModelIndex of the dragged item, to mimeData, thought, it could be better so, cause of not considering parent info...
The only solution i see is that of reimplementing the dropevent. But you dont have to destroy the items.
Use
QTreeWidgetItem * QTreeWidgetItem::takeChild ( int index )
QTreeWidgetItem * QTreeWidget::takeTopLevelItem ( int index )
to take the dragged item
and
void QTreeWidgetItem::insertChild ( int index, QTreeWidgetItem * child )
to drop it
I've checked that this way children are moved right. (See this gist)
This is how I solved it:
When you drag and drop, At creates a new object, differen than yours with the same values for the texts, but it is an other object and yours is simply removed but memory is not freed.
The first thing to do is override removeChild since it is based in indexes and not in addresses so it won't work well with what we are going to do latter. (http://sourceforge.net/p/ckmapper/code/4/tree/trunk/src/KViewer/KAbstractItem.cc#l39)
Then what we need to do is to override the dropEvent of the QTreeWidget. The startegy is the following:
get all the selected items that should be dragged but are not but Qt.
allow Qt to do its dropping.
Find the items on the target that might contain the new objects created by Qt. this can be done with itemAt(event->pos).
Find among the childrne of those items which ones are the dropped ones: this can be done with a dynamic_cast<> because the ones created by Qt are ATreeWidgetItems and ours inherit from this class.
Get its index.
Remove the "parasite" item, and delete it.
insert the selected items at the index from the parasite.
We nedded to override the removeChild because WE are removing children by hand (the selected items) and Qt is removing items (also the selected items) that it should drop latter (but it doesn't). So, if you check the Qt code you will see that it is based in indexes and this is not secure, whereas removing items based on their address is more secure.
I'll post my code latter here, I forgot to commit it ;)
Anyway, Trompa's solution is also valid and seems simpler to me. I just wanted to share my solution too ;)
Is there any way to get lists of all timezones IST, ET etc.
I have to use them in my application.
The ICU Library is portable and can be used in a Qt application. (It has a C/C++ API.) Among its many other features, is has a TimeZone class that can enumerate the time zones known by the system.
TimeZone Class
It might be overkill if all you need is a simple list, but if you expect to use these time zones and interact with other metadata (locales, etc.), this would be a good solution.
There is a another example using the new QTimeZone class in qt5.2 described here.
They create a custom Widget which lists all known timezones plus their special settings like daylight saving times and such.
The basic code posted there is:
#include <QDebug>
#include <QByteArray>
#include <QDateTime>
#include <QList>
#include <QTimeZone>
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
// Fill in combo box.
QList<QByteArray> ids = QTimeZone::availableTimeZoneIds();
foreach (QByteArray id, ids) {
ui->timeZoneComboBox->addItem(id);
}
// Connect combo box to slot to update fields.
connect(ui->timeZoneComboBox, SIGNAL(currentIndexChanged(int)),
SLOT(UpdateFields()));
// Update fields for initial value.
UpdateFields();
}
void Widget::UpdateFields() {
QByteArray id = ui->timeZoneComboBox->currentText().toLatin1();
QTimeZone zone = QTimeZone(id);
// Fill in fields for current time zone.
if (zone.isValid()) {
ui->descriptionLabel->setText(tr("<b>Description:</b> ") + id);
ui->countryLabel->setText(tr("<b>Country:</b> ") +
QLocale::countryToString(zone.country()));
ui->hasDaylightTimeCheckBox->setChecked(zone.hasDaylightTime());
ui->isDaylightTimeCheckBox->setChecked(
zone.isDaylightTime(QDateTime::currentDateTime()));
ui->hasTransitionsCheckBox->setChecked(zone.hasTransitions());
QDateTime zoneTime = QDateTime(
QDate::currentDate(), QTime::currentTime(), zone).toLocalTime();
ui->dateEdit->setDate(zoneTime.date());
ui->timeEdit->setTime(zoneTime.time());
QTimeZone::OffsetData offset = zone.nextTransition(
QDateTime::currentDateTime());
if (offset.atUtc != QDateTime()) {
ui->nextTransitionLabel->setEnabled(true);
ui->nextTransitionLabel->setText(
tr("<b>Next transition:</b> %1").arg(offset.atUtc.toString()));
} else {
ui->nextTransitionLabel->setEnabled(false);
ui->nextTransitionLabel->setText(
tr("<b>Next transition:</b> none"));
}
}
}
Do you need to somehow find it during runtime, or for your source code? If the second case, you can use this list.
Yes try this example
http://www.developer.nokia.com/Community/Wiki/How_to_get_list_of_Time_Zones_in_Qt_Maemo_application