(several qdockWidget) QWidget::repaint: Recursive repaint detected kernel\qwidget.cpp: 5557 - c++

I need your help please!
I have 8 dockwidget in my Qmainwindow without a centralwidget, when I try to move, float, and undock dockwidget that contains a 3D view, the program crash with segmentation fault!
I remain at your disposal for more information, thanks a lot!
SUB_WIN_3D_VIEW.cpp
/* -----------------------
* ----------------------- */
#include "sub_win_3dview.h"
#include <QtWidgets/QAction>
#include <iostream>
#include <QDesktopServices>
SUB_WIN_3D_VIEW::SUB_WIN_3D_VIEW(Mainwindow const& p) : QDockWidget(),mainwindow_ins(p)
{
ui.setupUi(this);
this->setWindowTitle("3D view");
// Initiate the 3D scene
view.defaultFrameGraph()->setClearColor(QColor("#FFC0CBD9")); // light blue
widget = QWidget::createWindowContainer(&view);
view.renderSettings()->pickingSettings()->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
// Initiate the root entity (all the other entities of the scene should
// inherit it to be part of the 3D scene
rootEntity = new Qt3DCore::QEntity;
input = new Qt3DInput::QInputAspect;
view.setRootEntity(rootEntity);
view.registerAspect(input);
// Get the default camera entity from view
cameraEntity = view.camera();
// Set Z the be the vertical axis
cameraEntity->setUpVector(QVector3D(0, 0, 1));
// Initiate the camera controller
MyOrbitCameraController *camController = new MyOrbitCameraController(rootEntity);
camController->setCamera(cameraEntity);
camController->setLookSpeed(-300);
camController->setLinearSpeed(12);
// Initiate the light entity with its components below
lightEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QPointLight *lightPoint = new Qt3DRender::QPointLight(lightEntity);
lightPoint->setColor("white");
lightPoint->setIntensity(1);
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(QVector3D(20, 20, 20));
lightEntity->addComponent(lightPoint);
lightEntity->addComponent(lightTransform);
// Initiate the modifier of the scene
modifier = new SceneModifier(rootEntity, cameraEntity);
modifier->pb_sl_reset();
view3d->widget->setMinimumSize(QSize(200, 100));
QSizePolicy view3d_siz(QSizePolicy::Expanding, QSizePolicy::Expanding);
widget->setSizePolicy(view3d_siz);
// Add the widget to a layout attached to the UI
ui.verticalLayout_2->addWidget(widget);
modifier->pb_sl_loadModel("simple");
connect(ui.Reload, SIGNAL(clicked(bool)),this, SLOT(reload_clicked()));
connect(ui.btn_CubeMiddle, SIGNAL(clicked(bool)),this, SLOT(cubeMiddle_clicked()));
connect(ui.btn_ObjUp, SIGNAL(clicked(bool)),this, SLOT(objUp_clicked()));
connect(ui.btn_ObjLeft, SIGNAL(clicked(bool)),this, SLOT(objLeft_clicked()));
connect(ui.btn_ObjRight, SIGNAL(clicked(bool)),this, SLOT(objRight_clicked()));
connect(ui.btn_ShowAxis, SIGNAL(clicked(bool)),this, SLOT(showAxis_clicked()));}
SUB_WIN_3D_VIEW::~SUB_WIN_3D_VIEW()
{
}
void SUB_WIN_3D_VIEW::reload_clicked()
{
// Reload's button simply load the same model again
modifier->pb_sl_loadModel("simple");
}
void SUB_WIN_3D_VIEW::cubeMiddle_clicked()
{
modifier->pb_sl_cameraMiddle();
}
void SUB_WIN_3D_VIEW::objUp_clicked()
{
modifier->pb_sl_cameraUp();
}
void SUB_WIN_3D_VIEW::objLeft_clicked()
{
modifier->pb_sl_cameraLeft();
}
void SUB_WIN_3D_VIEW::objRight_clicked()
{
modifier->pb_sl_cameraRight();
}
void SUB_WIN_3D_VIEW::showAxis_clicked()
{
modifier->pb_sl_enableRef(ui.btn_ShowAxis->isChecked());
}
#include "moc_sub_win_3dview.cpp"
Errors:
In file ....\include/QtCore/../../src/corelib/global/qglobal.h, line
770: Out of memory Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function. QWidget::repaint:
Recursive repaint detected
createDIB: CreateDIBSection failed. Invalid parameter passed to C
runtime function. Invalid parameter passed to C runtime function.
QWaitCondition: Destroyed while threads are still waiting

I solved the problem by modifying the qml code, before it was like that :
file.h
QQuickWidget *m_quickWidget_gauge_2;
QObject *object_gauge_2 ;
QQuickWidget *m_quickWidget_gauge_3;
QObject *object_gauge_3 ;
QQuickWidget *m_quickWidget_gauge_4;
QObject *object_gauge_4 ;
file.cpp
//QQuickWidget : actuator number 1
m_quickWidget_gauge_1 = new QQuickWidget(this) ;
m_quickWidget_gauge_1->setSource(QUrl("qrc:/Resources/res/gauge.qml"));
m_quickWidget_gauge_1->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_quickWidget_gauge_1->setMinimumHeight(30);
m_quickWidget_gauge_1->setMinimumWidth(150);
m_quickWidget_gauge_1->setAttribute(Qt::WA_AlwaysStackOnTop);
m_quickWidget_gauge_1->setClearColor(Qt::transparent);
ui.horizontalLayout_al_1->addWidget(m_quickWidget_gauge_1, 1, Qt::AlignTop);
//QQuickWidget : actuator number 2
m_quickWidget_gauge_2 = new QQuickWidget(this) ;
m_quickWidget_gauge_2->setSource(QUrl("qrc:/Resources/res/gauge.qml"));
m_quickWidget_gauge_2->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_quickWidget_gauge_2->setMinimumHeight(30);
m_quickWidget_gauge_2->setMinimumWidth(150);
m_quickWidget_gauge_2->setAttribute(Qt::WA_AlwaysStackOnTop);
m_quickWidget_gauge_2->setClearColor(Qt::transparent);
ui.horizontalLayout_al_2->addWidget(m_quickWidget_gauge_2, 1, Qt::AlignTop);
//QQuickWidget : actuator number 3
[....]
I made these changes and it works!!
file.h
QQuickView *m_qmlview_gauge_1;
QQuickView *m_qmlview_gauge_2;
QQuickView *m_qmlview_gauge_3;
file.cpp
m_qmlview_gauge_1 = new QQuickView(QUrl("qrc:/Resources/res/qml/actuator_gauge.qml"));
m_qmlview_gauge_1->setColor(QColor(Qt::white));
QWidget *container = QWidget::createWindowContainer(m_qmlview_gauge_1);
container->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding);
ui.verticalLayout_11->addWidget(container);
m_qmlview_gauge_2 = new QQuickView(QUrl("qrc:/Resources/res/qml/actuator_gauge.qml"));
m_qmlview_gauge_2->setColor(QColor(Qt::white));
QWidget *container_1 = QWidget::createWindowContainer(m_qmlview_gauge_2);
container_1->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding);
ui.verticalLayout_12->addWidget(container_1);
m_qmlview_gauge_3 = new QQuickView(QUrl("qrc:/Resources/res/qml/actuator_gauge.qml"));
m_qmlview_gauge_3->setColor(QColor(Qt::white));
QWidget *container_2 = QWidget::createWindowContainer(m_qmlview_gauge_3);
container_2->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding);
ui.verticalLayout_13->addWidget(container_2);
i still not understand why the old code cause this crash, it worked well before !!

Related

Qt3D SceneLoader entity is not rendered

I'm trying to create a Qt3D prototype which is able to render an obj which contains transparent objects. Therefor I need to somehow incorporate QSortPolicy with a custom frame graph. I put together a few examples which I found on the internet (unfortunately there aren't many Qt3D C++ examples). The source of the protoype is shown below. The problem is that I add a QTorusMesh and the content of the QSceneLoader to the root entity, but when rendered only the torus will be shown, the obj (in this case the monkey) is not rendered and I don't know why and also not how to debug it. I dumped all the trees (scene graph and frame graph) and couldn't find any inconsistency. Only thing I can think of that the loaded object somehow needs a different renderer (QGeometryRenderer) which needs to be added to the frame graph? Does someone know what I'm doing wrong?
Examples: Custom frame graph, Scene walker
#include <QGuiApplication>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DCore/QAspectEngine>
#include <Qt3DInput/QInputAspect>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DExtras/QTorusMesh>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QRenderAspect>
#include <Qt3DRender/QSceneLoader>
#include <Qt3DRender/QRenderSurfaceSelector>
#include <Qt3DRender/QClearBuffers>
#include <Qt3DRender/QLayerFilter>
#include <Qt3DRender/QViewport>
#include <Qt3DRender/QCameraSelector>
#include <Qt3DRender/QLayer>
#include <Qt3DRender/QRenderSettings>
class SceneWalker : public QObject
{
public:
SceneWalker(Qt3DRender::QSceneLoader* loader):
m_loader(loader)
{}
void onStatusChanged();
private:
void walkEntity(Qt3DCore::QEntity* e, int depth = 0);
Qt3DRender::QSceneLoader* m_loader;
};
void SceneWalker::onStatusChanged()
{
qDebug() << "Status changed:" << m_loader->status();
if (m_loader->status() != Qt3DRender::QSceneLoader::Ready)
return;
// The QSceneLoader instance is a component of an entity. The loaded scene
// tree is added under this entity.
QVector<Qt3DCore::QEntity*> entities = m_loader->entities();
// Technically there could be multiple entities referencing the scene loader
// but sharing is discouraged, and in our case there will be one anyhow.
if (entities.isEmpty())
return;
Qt3DCore::QEntity* root = entities[0];
// Print the tree.
walkEntity(root);
// To access a given node (like a named mesh in the scene), use QObject::findChild().
// The scene structure and names always depend on the asset.
Qt3DCore::QEntity* e = root->findChild<Qt3DCore::QEntity*>(QStringLiteral("PlanePropeller_mesh")); // toyplane.obj
if (e)
qDebug() << "Found propeller node" << e << "with components" << e->components();
}
void SceneWalker::walkEntity(Qt3DCore::QEntity* e, int depth)
{
Qt3DCore::QNodeVector nodes = e->childNodes();
for (int i = 0; i < nodes.count(); ++i)
{
Qt3DCore::QNode* node = nodes[i];
Qt3DCore::QEntity* entity = qobject_cast<Qt3DCore::QEntity*>(node);
if (entity)
{
QString indent;
indent.fill(' ', depth * 2);
qDebug().noquote() << indent << "Entity:" << entity << "Components:" << entity->components();
walkEntity(entity, depth + 1);
}
}
}
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
Qt3DExtras::Qt3DWindow* window = new Qt3DExtras::Qt3DWindow();
// Root
Qt3DCore::QEntity* rootEntity = new Qt3DCore::QEntity();
window->setRootEntity(rootEntity);
Qt3DRender::QRenderSurfaceSelector *renderSurfaceSelector = new Qt3DRender::QRenderSurfaceSelector();
renderSurfaceSelector->setSurface(window);
// clearing the buffers
Qt3DRender::QClearBuffers* clearBuffers = new Qt3DRender::QClearBuffers(renderSurfaceSelector);
clearBuffers->setBuffers(Qt3DRender::QClearBuffers::ColorDepthBuffer);
// Framegraph for objects
Qt3DRender::QLayerFilter* objectsLayerFilter = new Qt3DRender::QLayerFilter(renderSurfaceSelector);
Qt3DRender::QLayer* objectsLayer = new Qt3DRender::QLayer(objectsLayerFilter);
objectsLayerFilter->addLayer(objectsLayer);
Qt3DRender::QViewport* viewport = new Qt3DRender::QViewport(objectsLayer);
Qt3DRender::QCameraSelector* objectsCameraSelector = new Qt3DRender::QCameraSelector(viewport);
Qt3DRender::QCamera* objectsCamera = new Qt3DRender::QCamera(objectsCameraSelector);
objectsCamera->lens()->setPerspectiveProjection(45.f, 16.0f/9.0f, 0.01f, 1000.f);
objectsCamera->setPosition(QVector3D(0, 0, -10));
objectsCamera->setViewCenter(QVector3D(0, 0, 0));
objectsCamera->setUpVector(QVector3D(0, 1, 0));
objectsCameraSelector->setCamera(objectsCamera);
// Set the new framegraph
window->setActiveFrameGraph(renderSurfaceSelector);
window->renderSettings()->setRenderPolicy(Qt3DRender::QRenderSettings::Always);
// camera controls
Qt3DExtras::QOrbitCameraController* camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
camController->setLinearSpeed(50.0f);
camController->setLookSpeed(180.0f);
camController->setCamera(objectsCamera);
// Torus
Qt3DCore::QEntity* torusEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QTorusMesh* torusMesh = new Qt3DExtras::QTorusMesh(torusEntity);
torusMesh->setSlices(50.0f);
torusMesh->setRings(50.0f);
torusMesh->setRadius(2.0f);
Qt3DExtras::QPhongMaterial* torusMaterial = new Qt3DExtras::QPhongMaterial(torusEntity);
torusMaterial->setAmbient(Qt::gray);
Qt3DCore::QTransform* torusTransform = new Qt3DCore::QTransform(torusEntity);
torusTransform->setTranslation(QVector3D(0.0f, 0.0f, 10.0f));
torusTransform->setRotationY(50.0f);
torusTransform->setScale(2.0f);
torusEntity->addComponent(torusTransform);
torusEntity->addComponent(torusMesh);
torusEntity->addComponent(torusMaterial);
torusEntity->addComponent(objectsLayer);
// Scene loader
Qt3DCore::QEntity* sceneLoaderEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QSceneLoader* sceneLoader = new Qt3DRender::QSceneLoader(sceneLoaderEntity);
sceneLoader->setSource(QUrl::fromLocalFile("monkey.obj"));
// Transform
Qt3DCore::QTransform* sceneLoaderTransform = new Qt3DCore::QTransform(sceneLoaderEntity);
sceneLoaderTransform->setScale(2.0f);
sceneLoaderTransform->setTranslation(QVector3D(0.0f, 0.0f, 10.0f));
SceneWalker sceneWalker(sceneLoader);
QObject::connect(sceneLoader, &Qt3DRender::QSceneLoader::statusChanged, &sceneWalker, &SceneWalker::onStatusChanged);
sceneLoaderEntity->addComponent(sceneLoader);
sceneLoaderEntity->addComponent(sceneLoaderTransform);
sceneLoaderEntity->addComponent(objectsLayer);
window->show();
return app.exec();
}
The problem is that you are not actually adding the monkey to the objects layer. QSceneLoader creates its own scene subtree, even when the OBJ file contains a single object. So you are just adding the root entity of the subtree to the objects layer.
The SceneWalker object traverses the QSceneLoader subtree and provides information about its structure. You can just look at the console output, find the names of the entities you want to render, and attach them to the desired layer.
This has to be done asynchronously, using signals and slots. Do this right after creating the QSceneLoader object (assuming your mesh is named "monkey"):
QObject::connect(sceneLoader, &Qt3DRender::QSceneLoader::statusChanged, &app,
[sceneLoader, objectsLayer](Qt3DRender::QSceneLoader::Status s) {
if (s == Qt3DRender::QSceneLoader::Status::Ready)
sceneLoader->entity("monkey")->addComponent(objectsLayer);
});
Since you are using an OBJ file, you can even ditch the SceneWalker entirely. OBJ files are text-based, so you can find the name of the mesh by just opening it with a text editor.
If you succeed with layer filters, you don't need to use QSortPolicy (check out this answer).

Getting the wrong position from QMainWindow geometry()

I am using a class inheriting QMainWindow in a Qt GUI, and another class that handles game logic.
The purpose of the code is to place a UI element at a specific position in the window (as well as move them around as needed.) But, I am having issues. If I increase the size of the window, the Y axis gets larger than the window and places the object below the fold.
game.h
#ifndef GAME_H
#define GAME_H
#include "util.h"
#include "myrect.h"
class Game: public QObject
{
Q_OBJECT
TheColony * TC;
public:
Game(TheColony * ThC);
QRect getBoard(){ return QRect(0,0,TC->geometry().width(),TC->geometry().height()); }
private slots:
virtual void periodic();
protected:
QGraphicsScene * scene;
QGraphicsView * view;
MyRect * player;
QTimer * periodic_timer;
};
#endif // GAME_H
game.cpp
#include "game.h"
Game::Game(TheColony * ThC)
: TC(ThC){
//prepare the scene and view
scene = new QGraphicsScene(getBoard(),TC);
view = new QGraphicsView(scene);
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setGeometry(getBoard());
view->show();
TC->setCentralWidget(view);
//setup the player's position and size
player = new MyRect(QRect((view->width()/2) - 50,view->height() - 100,100,100));
player->setFlag(QGraphicsItem::ItemIsFocusable);
scene->addItem(player);
player->setFocus();
//timer used to trigger periodic checks.
periodic_timer = new QTimer();
connect(periodic_timer,SIGNAL(timeout()),this,SLOT(periodic()));
periodic_timer->start(500);
}
void Game::periodic(){
static int tcHeight = getBoard().height();
if(tcHeight != getBoard().height()){
view->setGeometry(getBoard());
player->setRect(player->rect().x(), getBoard().height() - 100,100,100);
tcHeight = getBoard().height();
}
}
On load, square is positioned as expected.
After resizing the window larger than the original, the square falls below the fold.
Was solved by freqlabs on discord (Who does not have a stack overflow account.)
I was failing to update QGraphicsScene's rect;
scene->setSceneRect(getBoard());
This left the coordinate space for the scene incorrect and caused the object to be translated wrong. I misunderstood how exactly Qt was using coordinates, I did not realize it used actual coordinate spaces with matrix translations.

Scrollable view as TabWidget

Here is my problem, I display Buttons and Labels manually with setGeometry() method.
MyClass which inherits from QWidget
Here is my code :
void MyClass::function() {
QLabel *imgP;
QLabel *name;
QPushButton *newConv;
QPixmap *profilPic;
std::stringstream ss;
int j = 0;
int i = 0;
for (int tmp = 0; tmp < 15; tmp++)
{
if (i % 7 == 0 && i != 0)
{
i = 0;
j++;
}
ss << "Username " << tmp;
name = new QLabel(tr(ss.str().c_str()), this);
name->setAlignment(Qt::AlignCenter);
name->setGeometry((30 * (i + 1) + 240 * i), (30 + 390 * j),
240, 60);
profilPic = new QPixmap("./gui/img/avatar1.png");
imgP = new QLabel(this);
imgP->setPixmap(profilPic->scaled(240, 240));
imgP->setGeometry((30 * (i + 1) + 240 * i), (90 + 390 * j),
240, 240);
newConv = new QPushButton(tr("Chat"), this);
newConv->setGeometry((30 * (i + 1) + 240 * i), (330 + 390 * j),
240, 60);
newConv->setFocusPolicy(Qt::NoFocus);
connect(newConv, SIGNAL(released()), this, SLOT(addTab()));
ss.str("");
ss.clear();
i++;
}
}
It may be a bit more complicated than it should, but it works just the way I wanted ..
it looks like this :
As you can see, the result is good, I have my contacts displayed, but the 15th element is hidden because the window is too small. So my question is :
How can I make a ScrollView when this happens ?
I already know QScrollArea, but I would have to work with QBoxLayout, and I don't think this will do the job.
Thanks for your help !
EDIT
This is my MainWidget class which displays the window :
class QTabBar;
MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
setFixedSize(1920, 1200);
setWindowTitle(tr("Babel"));
QVBoxLayout *mainLayout = new QVBoxLayout;
QTabBar *tb;
UiContact *contact = new UiContact(this);
QScrollArea *contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(contact);
_tabWidget = new QTabWidget;
tb = _tabWidget->tabBar();
_tabWidget->addTab(new Home(), tr("Home"));
_tabWidget->addTab(contactScrollArea, tr("Contact"));
std::ostringstream oss;
_tabWidget->setTabsClosable(true);
connect(_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
tb->tabButton(0, QTabBar::RightSide)->hide();
tb->tabButton(1, QTabBar::RightSide)->hide();
_tabWidget->setFocusPolicy(Qt::NoFocus);
mainLayout->addWidget(_tabWidget);
setLayout(mainLayout);
}
QScrollArea is certainly the way to go. It is not necessary to use a layout, it's only necessary to force the widget to be the size it needs to be. A QScrollArea can handle any QWidget derived class, and it will display its scrollbars as needed.
Practically: if you can calculate how much space you need (which I think you can do), and set the size constraints of the containing widget accordingly, the QScrollArea will show the scrollbars automatically. You can use QWidget::setMinimumSize for that purpose, a simple setMinimumSize(itemWidth*7,itemHeight*(count%7)) should suffice.
This method does allow the widget to grow as large as to fill the QScrollArea. Also, it's possible to disable the frame around the QScrollArea if preferred.
edit:
You probably have something like this:
MyClass *myClass = new MyClass();
...
tabs->insertTab(1,myClass,"Contact");
An example implementation in that situation would be:
MyClass *myClass = new MyClass();
...
QScrollArea* contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(myClass);
tabs->insertTab(1,contactScrollArea,"Contact");
It will place a scroll area inside the tab widget and put the instance of MyClass inside it
A QScrollArea is used as a relatively high container class. Think of a QScrollArea as a widget which can embed another widget inside it. By default it creates an empty widget, which can get a layout. But by using setWidget, you can literally place anything you want in it. A possible "combination" is a QLabel with a large licence text or any other widget that can potentially grow too large (like your widget).
Now, just some extra information:
When you draw stuff yourself (not creating several widgets and code your own layout stuff), you may use QAbstractScrollArea. It would give you full control. It gives scrollbars and a separate middle widget to which you can draw during paintEvent. But I think that's beyond the scope of this.
Now, for sake of clean coding. I would actually suggest you create a separate class ContactItem. It would consist of that label, image and pushbutton, held together with a QVBoxLayout (which makes them neatly packed above eachother). This "item" can be put inside a QGridLayout. This way, you don't need to concern yourself with arranging the items. If you set a minimum size on the picture, it will make sure the items are your preferred width/height. The label size constraints make sure that font differences don't affect the presentation (same goes for the buttons). Last but not least, your list is suddenly resizable. (By using setRowStretch and setColumnStretch you can make sure your list is centered, or top aligned, in case the window is larger than your list takes up.
Functional interpretation
Here I have a possible implementation (it isn't my best code) from what I got from the screenshot and given code.
It consists of a 'Widget' which is responsible for the tab layout:
mainwidget.h
#include <QWidget>
#include "uicontact.h"
class QTabWidget;
class MainWidget : public QWidget
{
Q_OBJECT
QTabWidget *_tabWidget;
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
public slots:
void addChatTab();
};
mainwidget.cpp
#include "mainwidget.h"
#include <QScrollArea>
#include <QTabWidget>
#include <QTabBar>
#include <QVBoxLayout>
#include "home.h"
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
setFixedSize(1920,1200);
setWindowTitle(tr("Babel"));
QVBoxLayout *mainLayout = new QVBoxLayout;
QTabBar *tb;
UiContact *contact = new UiContact(this);
QScrollArea *contactScrollArea = new QScrollArea();
contactScrollArea->setWidget(contact);
_tabWidget = new QTabWidget;
tb = _tabWidget->tabBar();
_tabWidget->addTab(new Home(), tr("Home"));
_tabWidget->addTab(contactScrollArea, tr("Contact"));
_tabWidget->setTabsClosable(true);
connect(_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
tb->tabButton(0, QTabBar::RightSide)->hide();
tb->tabButton(1, QTabBar::RightSide)->hide();
_tabWidget->setFocusPolicy(Qt::NoFocus);
mainLayout->addWidget(_tabWidget);
setLayout(mainLayout);
}
MainWidget::~MainWidget()
{
}
void MainWidget::addChatTab()
{
_tabWidget->addTab(new QWidget, tr("Number %1").arg(_tabWidget->count()-2));
}
The class MyClass is responsible for creating the 'contact' tab:
uicontact.cpp
#include "uicontact.h"
#include "mainwidget.h"
#include <QLabel>
#include <QPushButton>
UiContact::UiContact(MainWidget *owner,QWidget *parent) : QWidget(parent)
{
QLabel *imgP;
QLabel *name;
QPushButton *newConv;
QPixmap *profilPic;
int j = 0;
int i = 0;
for (int tmp = 0; tmp < 15; tmp++)
{
if (i % 7 == 0 && i != 0)
{
i = 0;
j++;
}
name = new QLabel(tr("Username %1").arg(tmp), this);
name->setAlignment(Qt::AlignCenter);
name->setGeometry((30 * (i + 1) + 240 * i), (30 + 390 * j),
240, 60);
profilPic = new QPixmap("./gui/img/avatar1.png");
imgP = new QLabel(this);
imgP->setPixmap(profilPic->scaled(240, 240));
imgP->setGeometry((30 * (i + 1) + 240 * i), (90 + 390 * j),
240, 240);
newConv = new QPushButton(tr("Chat"), this);
newConv->setGeometry((30 * (i + 1) + 240 * i), (330 + 390 * j),
240, 60);
newConv->setFocusPolicy(Qt::NoFocus);
connect(newConv, SIGNAL(clicked(bool)), owner, SLOT(addChatTab()));
i++;
}
setMinimumSize(270*7,420*(15/7+1));
}
The uicontact.h file is very trivial so omitted.
A few things to note: MyClass receives an 'owner' pointer, this allows it to talk directly to the top level widget responsible for adding tabs. Probably you want to look at QSignalMapper to be able to map the individual QPushButtons to a more known value. With QSignalMapper, you can map the button to an integer, string, QWidget* or QObject*.
Also note the tr("Contact %1").arg(tmp) which is the correct way to make your program locale aware.

Expected type-specifier before 'QwtLog10ScaleEngine'?

Version: qwt 6.0.1
I've tried to develop logarithmic scaling for Spectrum.
I've used simple line to enable scaling plotspectrum->setAxisScaleEngine(QwtPlot::yLeft, new QwtLog10ScaleEngine);
Problems: the data are not drawn, so the plot is empty and the compiler returns following error:"expected type-specifier before 'QwtLog10ScaleEngine'"
Any help woulb be appreciated
Here is my code:
class SpectrumPlot : public QWidget
{
Q_OBJECT
public:
PlotSpektrum();
private:
QHBoxLayout* m_SpectrumLayout;
QwtPlot* m_SpectrumPlot;
QwtPlotCurve* m_SpectrumCurve;
QwtPlotMarker* m_Marker;
};
SpectrumPlot::SpectrumPlot()
{
m_SpectrumLayout = new QHBoxLayout();
m_SpectrumPlot = new QwtPlot();
m_SpectrumCurve = new QwtPlotCurve();
QwPlotGrid* pGrid = new QwtPlotGrid();
QPen GridPen;
GridPen.setColor(Qt::green);
GridPen.setWidthF(0.7);
GridPen.setStyle(Qt::DashLine);
QPen SpectrumPen;
SpectrumPen.setColor(Qt::white);
pGrid->setRenderHint(QwtPlotItem::RenderAntialiased);
pGrid->setPen(GridPen);
pGrid->enableXMin(true);
pGrid->attach(m_SpectrumPlot);
m_SpectrumPlot->setTitle("Spectrum");
m_SpectrumPlot->setCanvasBackground(QBrush(Qt::black));
m_SpectrumPlot->setAutoDelete(true);
m_SpectrumPlot->setAxisTitle(QwtPlot::xBottom, "Frequency Hz");
m_SpectrumPlot->setAxisScale(QwtPlot::xBottom, 100, nNyquistFrequency);
m_SpectrumPlot->setAxisScale(QwtPlot::yLeft, 0, 150);
m_SpectrumPlot->setAxisScaleEngine(QwtPlot::xBottom, new QwtLog10ScaleEngine());
m_SpectrumLayout->addWidget(m_SpectrumPlot);
this->setLayout(m_SpectrumLayout);
}
I think you should be using:
new QwtLogScaleEngine(10)
The manual for QwtScaleEngine doesn't show any classes called QwtLog10ScaleEngine.

Qt State Machine Transition in a Layout

Well, I am developing a Qt application and I want use the Qt State Framework to make some animations.
First:
How I can animate a group of buttons contained in a horizontal layout, into another vertical layout, by using state a transition?
Second:
How I can show a widget when in a state? For example a menu: When the user clicks a button in the menu, the widget (that previously has been hidden with widget->hide()) is shown...???
This is a code example:
boxInsert = new BoxInsert(this);
boxInsert->hide ();
btn1 = new QPushButton("Introducir", this);
btn2 = new QPushButton("Informe", this);
btn3 = new QPushButton("Salir", this);
QStateMachine *machine = new QStateMachine(this);
QState *st1 = new QState(machine);
st1->setObjectName ("menuMode");
st1->assignProperty (btn1, "pos", QPointF(center - btn1->width () / 2, 20));
st1->assignProperty (btn2, "pos", QPointF(center - btn1->width () / 2, 40));
st1->assignProperty (btn3, "pos", QPointF(center - btn1->width () / 2, 60));
st1->assignProperty (boxInsert, "visible", QVariant(false));
QState *st2 = new QState(machine);
st2->setObjectName ("barMode");
st2->assignProperty (btn1, "pos", QPointF(40, 0));
st2->assignProperty (btn2, "pos", QPointF(40, 0));
st2->assignProperty (btn3, "pos", QPointF(40, 0));
st1->assignProperty (boxInsert, "visible", QVariant(true));
machine->setInitialState (st1);
QAbstractTransition *t1 = st1->addTransition (btn1, SIGNAL(clicked()), st2);
//QSequentialAnimationGroup *sq1 = new QSequentialAnimationGroup;
//sq1->addPause (250);
t1->addAnimation (new QPropertyAnimation(btn1, "pos"));
t1->addAnimation (new QPropertyAnimation(btn2, "pos"));
t1->addAnimation (new QPropertyAnimation(btn3, "pos"));
t1->addAnimation (new QPropertyAnimation(boxInsert, "visible"));
machine->start ();
It is something like when you will start machine it will change color of a button that may indicate this is clicked then perform something that is linked with your signal so its linked slot will be executed.
s0->addTransition(s1);
s1->assignProperty(ui->pushButton,"styleSheet","background-color:rgb(255,0,0);");
s1->addTransition(s2);
s2->addTransition(ui->pushButton,SIGNAL(clicked()),s0);
QStateMachine m;
m.addState(s0);
m.addState(s1);
m.addState(s2);
m.setInitialState(s0);
To make visible a widget add an state transition like this:
s1->assignProperty(MyWid,"visible", true);
and add transition in s0 for state s1.
First: Move widgets from horizontal layout to vertical using stateMachine? Don't know how to do it, really.
Second: You can implement widget with your own transparency property, that works with QGraphicsEffect:
class myWidget
{
//your methods
Q_PROPERTY(double alpha READ alpha WRITE setAlpha)
double mAlpha;
double alpha() {return mAlpha;}
void setAlpha(double a);
QGraphicsOpacityEffect* eff;
}
make QGraphicsEffect working in setAlpha() method:
void myWidget::setAlpha(double a)
{
mAlpha = a;
if(mAlpha < 0.0)
mAlpha = 0.0;
if(mAlpha > 1.0)
mAlpha = 1.0;
if(mAlpha == 0)
{
this->hide();
}
else
{
this->show();
eff->setOpacity(mAlpha);
}
this->update();
}
And, of course, set QGraphicsOpacityEffect to your widget in constructor:
eff = new QGraphicsOpacityEffect(this);
eff->setOpacity(mAlpha);
this->setGraphicsEffect(eff);
Then you can work with your alpha property in QState:
QState* s1 = new QState(mainState);
s1->assignProperty(mywidget, "alpha", 1.0);
//and so on...