automatic resize using qgraphicsview with qgraphicsscene and qopenglwidget - qt

I'm trying to use QGraphicsView with QOpenGLWidget in a MainWindow:
Exactly:
My QMainWindow contains a few layouts and widget. Also a QGraphicsView (class graphicsView inherits from QGraphicsView).
In a "second" step i create a QGraphicsScene and add a openglwidget (class OpenGLControl inherits from QOpenGLWidget). In OpenGLControl I only set the backround for testing my application (glClearColor ...).
Now my request, when I change the size of mainWindow, i want to change the size of QGraphicsView, QGraphicsScene and QOpenGLWidget, too. I try a resizeEvent in graphicsView, but it didn't work.
Implementation of mainwindow (.cpp):
#include "mainwindow.h"
#include "openglcontrol.h"
#include "graphicsview.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
createLayout();
createScene();
}
void MainWindow::createLayout()
{
view = new graphicsView;
kosGrid = new QGridLayout;
xKoord = new QLineEdit;
yKoord = new QLineEdit;
zKoord = new QLineEdit;
drawButton = new QPushButton("Draw Point");
clearButton = new QPushButton("Clear");
KoordLabel = new QLabel("Koordinaten");
xLabel = new QLabel("X:");
yLabel = new QLabel("Y: ");
zLabel = new QLabel("Z: ");
controlBox = new QVBoxLayout;
controlBox->addStretch(1);
controlBox->addWidget(KoordLabel);
xhBox = new QHBoxLayout;
xhBox->addWidget(xLabel);
xhBox->addWidget(xKoord);
controlBox->addLayout(xhBox);
yhBox = new QHBoxLayout;
yhBox->addWidget(yLabel);
yhBox->addWidget(yKoord);
controlBox->addLayout(yhBox);
zhBox = new QHBoxLayout;
zhBox->addWidget(zLabel);
zhBox->addWidget(zKoord);
controlBox->addLayout(zhBox);
controlBox->addWidget(drawButton);
controlBox->addWidget(clearButton);
xKoord->setFixedWidth(50);
yKoord->setFixedWidth(50);
zKoord->setFixedWidth(50);
drawButton->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
xKoord->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
yKoord->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
zKoord->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
hBox = new QHBoxLayout;
hBox->addLayout(controlBox);
hBox->addWidget(view);
mainLayout = new QWidget;
mainLayout->setLayout(hBox);
setCentralWidget(mainLayout);
}
void MainWindow::createScene()
{
scene = new QGraphicsScene(this);
qsurface = new QSurfaceFormat;
qsurface->setRenderableType(QSurfaceFormat::OpenGL);
qsurface->setProfile(QSurfaceFormat::CoreProfile);
qsurface->setVersion(3,3);
oglwidget = new OpenGLControl;
oglwidget->setFormat(*qsurface);
oglwidget->
//oglwidget->resize(10,10);
scene->addWidget(oglwidget);
view->setScene(scene);
}
and my attempt for the resizeEvent:
void graphicsView::resizeEvent(QResizeEvent *event)
{
if(scene())
scene()->setSceneRect(QRect(QPoint(0,0), event->size()));
QGraphicsView::resizeEvent(event);
}
at last a screenshot of the (resized) mainWindow (the QOpenGLWidget (blue background) is smaller than the QGraphicsView)
mainWindow with QOpenGLWidget
Is there a SIGNAL I can use ? Or can anybody help me on another way ?
Thank You

Related

How to avoid hidden QWidget height included in QStackedLayout?

I have this scenario with which I have been struggling for few hours:
I have a main widget, whose layout is set to main_layout, before which 3 layouts are added to the main_layout:
A QVBoxLayout (header_app_layout)
A second QVBoxLayout (header_loader_layout)
A QStackBoxLayout (content_layout)
The QStackBoxLayout (content_layout) has 2 child widgets added to it, of which only 1 is shown:
m_content1_widget (shown widget)
m_content2_widget
My problem is that, content_layout is taking into consideration the heights of the hidden child widgets in the widget: m_content1_widget, because of which the main_widget height is overflowing.
If I change content_layout from QStackedLayout to QVBoxLayout type, it all starts working fine.
So it seems to me that, QStackedLayout is respecting the height of the hidden widgets, which I don't want it to. Any ideas to overcome this ?
Here is the code:
main.cpp
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
main_widget w;
w.setFixedSize(400, 400);
w.show();
return app.exec();
}
main_widget.h
#include <QWidget>
#include <QLabel>
#include <QStackedLayout>
#include <QVBoxLayout>
#include <QPushButton>
class main_widget : public QWidget
{
Q_OBJECT
public:
main_widget();
};
main_widget.cpp
#include "main_widget.h"
main_widget::main_widget()
: QWidget(nullptr)
{
QVBoxLayout *header_app_layout = new QVBoxLayout();
QLabel *header_app_label = new QLabel();
header_app_label->setText(tr("Header"));
header_app_layout->addWidget(header_app_label);
QVBoxLayout* header_loader_layout = new QVBoxLayout();
QLabel* header_loader_label = new QLabel();
header_loader_label->setText(tr("Header Loader"));
header_loader_layout->addWidget(header_loader_label);
QWidget *m_content1_widget = new QWidget();
QVBoxLayout* content1_layout = new QVBoxLayout(m_content1_widget);
QPushButton* content1_button1 = new QPushButton(tr("content1_button1"));
content1_layout->addWidget(content1_button1);
QPushButton* content1_button2 = new QPushButton(tr("content1_button2"));
content1_layout->addWidget(content1_button2);
QPushButton* content1_button3 = new QPushButton(tr("content1_button3"));
content1_layout->addWidget(content1_button3);
content1_button2->hide(); //Hidden for now. But it's height is being included
content1_button3->hide();
QWidget* m_content2_widget = new QWidget();
QVBoxLayout* content2_layout = new QVBoxLayout(m_content2_widget);
QPushButton* content2_button1 = new QPushButton(tr("content2_button1"));
content2_layout->addWidget(content2_button1);
QPushButton* content2_button2 = new QPushButton(tr("content2_button2"));
content2_layout->addWidget(content2_button2);
QPushButton* content2_button3 = new QPushButton(tr("content2_button3"));
content2_layout->addWidget(content2_button3);
content2_button2->hide();
content2_button3->hide();
QStackedLayout* content_layout = new QStackedLayout(); //Doesn't work
//QVBoxLayout *content_layout = new QVBoxLayout(); //Works, but I need it to be of type `QStackedLayout` to show the 2 child widgets conditionally
content_layout->addWidget(m_content1_widget);
content_layout->addWidget(m_content2_widget);
content_layout->setStackingMode(QStackedLayout::StackingMode::StackOne);
content_layout->setCurrentIndex(0);
QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addLayout(header_app_layout); //Adding a QVBoxLayout
main_layout->addLayout(header_loader_layout); //Adding another QVBoxLayout
main_layout->addSpacing(32);
main_layout->addLayout(content_layout); //Adding the QStackedLayout
this->setLayout(main_layout);
}
I was able to resolve the issue by calling adjustSize on m_content2_widget, which removed the space occupied by the hidden controls inside m_content2_widget.
m_content2_widget->adjustSize();

How to extract widgets from QHBoxLayout in Qt

I have a TableWidget into which I add Widgets like this:
QLabel *l = new QLabel("TEST");
QWidget *widget = new QWidget();
QHBoxLayout *hbox = new QHBoxLayout();
hbox->addWidget(l);
hbox->setAlignment(Qt::AlignCenter);
hbox->setContentsMargins(0,0,0,0);
widget->setLayout(hbox);
ui->tableWidget->setCellWidget(0, 0, widget);
When a cell gets double clicked I capture the event and would like to figure out what QLabel it is.
But how do I extract it again or do I even have to?
auto widget = ui->tableWidget->cellWidget(ui->tableWidget->currentRow(), ui->tableWidget->currentColumn()); // if mode is SingleSelection
auto hbox = widget->layout();
auto label = qobject_cast<QLabel *>(hbox->itemAt(0)->widget());

Recursive repaint detected in popup window

I have a QPushButton that will open new window on clicked.
void showNewWindow()
{
PopupWindow *popup = new PopupWindow();
popup->show();
}
And PopupWindow is declared as following:
class PopupWindow : public QWidget {
Q_OBJECT
public:
PopupWindow(QWidget* parent);
void setContent(QString content) { this->content = content; }
QString getContent() { return content; }
private:
QString content;
private slots:
void handleContinue();
void handleRunToEnd();
};
Then I implement a its constructor:
PopupWindow::PopupWindow(QWidget *parent):QWidget(parent)
{
QHBoxLayout *hlayout = new QHBoxLayout();
QWidget *buttonWidget = new QWidget();
QPushButton *btnContinue = new QPushButton();
btnContinue->setText("Continue");
QPushButton *btnRunEnd = new QPushButton();
btnRunEnd->setText("Run till completion");
buttonWidget->setLayout(hlayout);
hlayout->addWidget(btnContinue);
hlayout->addWidget(btnRunEnd);
connect(btnContinue,SIGNAL(clicked()), this, SLOT(handleContinue()));
connect(btnRunEnd,SIGNAL(clicked()), this, SLOT(handleRunToEnd()));
QTextEdit *html = new QTextEdit();
html->setReadOnly(true);
html->setText("AAAA");
QVBoxLayout *layout = new QVBoxLayout();
this->setLayout(layout);
layout->addWidget(html);
layout->addWidget(buttonWidget);
}
My problem: whenever I click on the "Continue" or "Run till completion" buttons on Popup Window. The app crashed. I could see the error as following:
QApplication: Object event filter cannot be in a different thread.
QApplication: Object event filter cannot be in a different thread.
QApplication: Object event filter cannot be in a different thread.
QWidget::repaint: Recursive repaint detected
Please, help me to resolve this.

Convert QStackedLayout to QHBoxLayout dynamically

I would like to change my widget layout from QStackedLayout to QHBoxLayout to QVBoxLayout dynamically by clicking on push buttons. I am able to switch from QVBoxLayout to QHBoxLayout and vice versa, but my approach does not work for QStackedLayout. I've exhausted all options I can think of. A sample code is attached. Does anyone know how I can achieve my objective?
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QStackedLayout>
#include <QGridLayout>
#include <QLabel>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
QPushButton *button1_;
QPushButton *button2_;
QPushButton *button3_;
QHBoxLayout *hLayout_;
QVBoxLayout *vLayout_;
QStackedLayout *sLayout_;
QVBoxLayout *gLayout_;
public slots:
void layoutHorizontal();
void layoutVertical();
void layoutStacked();
private:
bool isStackedLayout_;
QLabel *bar_;
};
#endif // WIDGET_H
#include "widget.h"
#include <QtAlgorithms>
#include <QDebug>
Widget::Widget(QWidget *parent) : QWidget(parent){
bar_ = new QLabel(tr("TEST!"));
button1_ = new QPushButton(tr("to Horizontal Layout"),(bar_));
button2_ = new QPushButton(tr("to Vertical Layout"),(bar_));
button3_ = new QPushButton(tr("to Stacked Layout"),(bar_));
button1_->setStyleSheet("background: rgba(255,255,0,255);");
button2_->setStyleSheet("background: rgba(255,0,255,255);");
button3_->setStyleSheet("background: rgba(0,255,255,255);");
connect(button1_,SIGNAL(clicked()),this,SLOT(layoutHorizontal()));
connect(button2_,SIGNAL(clicked()),this,SLOT(layoutVertical()));
connect(button3_,SIGNAL(clicked()),this,SLOT(layoutStacked()));
gLayout_ = new QVBoxLayout;
setLayout(gLayout_);
hLayout_ = new QHBoxLayout(bar_);
hLayout_->setObjectName(tr("currentLayout"));
gLayout_->addWidget(bar_);
hLayout_->addWidget(button1_);
hLayout_->addWidget(button2_);
hLayout_->addWidget(button3_);
isStackedLayout_ = false;
resize(480,200);
}
Widget::~Widget() { }
void Widget::layoutHorizontal(){
QLayout *layout = bar_->findChild<QLayout *>(tr("currentLayout"));
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
delete layout;
QHBoxLayout *hLayout_ = new QHBoxLayout(bar_);
hLayout_->setObjectName(tr("currentLayout"));
hLayout_->addWidget(button1_);
hLayout_->addWidget(button2_);
hLayout_->addWidget(button3_);
isStackedLayout_ = false;
}
void Widget::layoutVertical(){
QLayout *layout = bar_->findChild<QLayout *>(tr("currentLayout"));
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
delete layout;
QVBoxLayout *vLayout_ = new QVBoxLayout(bar_);
vLayout_->setObjectName(tr("currentLayout"));
vLayout_->addWidget(button1_);
vLayout_->addWidget(button2_);
vLayout_->addWidget(button3_);
isStackedLayout_ = false;
}
void Widget::layoutStacked(){
QLayout *layout = bar_->findChild<QLayout *>(tr("currentLayout"));
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
delete layout;
QStackedLayout *sLayout_ = new QStackedLayout(bar_);
sLayout_->setObjectName(tr("currentLayout"));
sLayout_->addWidget(button1_);
sLayout_->addWidget(button2_);
sLayout_->addWidget(button3_);
isStackedLayout_ = true;
}
The visibility property on your buttons gets set to "invisible" after pulling widgets out of the QStackedLayout (likely because the QStackedLayout relies on this property to emulate stacking). As such, I was able to get your code to work by adding the following:
void Widget::layoutHorizontal() {
...
button1_->setVisible(true);
button2_->setVisible(true);
button3_->setVisible(true);
isStackedLayout_ = false;
}
It's also worth noting that removing the widgets from the layout prior to deleting it is not necessary. The layout doesn't take ownership of the widgets in it. As such you can delete the following:
layout->removeWidget(button1_);
layout->removeWidget(button2_);
layout->removeWidget(button3_);
Create another widget with only widgets and one layout inside. Then use setLayout for your widget. Sorry for my bad C++ knowledge :)
class ChangeableWidget: public QWidget {
private QVBoxLayout vbox;
private QHBoxLayout hbox;
private QStackedLayout stacked;
private QPushButton button1;
private QPushButton button2;
ChangeableWidget()
{
button1 = new QPushButton("1");
button2 = new QPushButton("2");
vbox = new QVBoxLayout();
vbox.addWidget(button1);
vbox.addWidget(button2);
hbox = new QHBoxLayout();
hbox.addWidget(button1);
hbox.addWidget(button2);
stacked = new QStackedLayout();
stacked.addWidget(button1);
stacked.addWidget(button2);
setLayout(vbox);
}
void ChangeableWidget::layoutVertical()
{
setLayout(vbox);
}
void ChangeableWidget::layoutHorizontal()
{
setLayout(hbox);
}
}

Display video using QImage in the same window?

I am trying to display the video taken by a simulator. I am implementing the QT code in ROS by including its header file. My code is running.
PROBLEM:: Everytime the new window is opened to display the frame. I have kept cvWaitKey(10000) so that new windows will come after a time delay. But the updated frames should come inside the same window. Pls suggest how can i do it?? My code is following:
void imageCallback( const sensor_msgs::ImageConstPtr& msg) //const sensor_msgs::ImageConstPtr&
{
imagePublisher.publish (cv_ptr->toImageMsg());
QImage temp(&(msg->data[0]), msg->width, msg->height, QImage::Format_RGB888);
QImage image;
image=temp;
// QT Layout with button and image
static QWidget *window = new QWidget;
static QLabel *imageLabel= new QLabel;
static QPushButton* quitButton= new QPushButton("Quit");
static QPushButton* exitButton= new QPushButton("Exit Image");
QVBoxLayout* layout= new QVBoxLayout;
imageLabel->setPixmap(QPixmap::fromImage(image));
layout->addWidget(imageLabel);
layout->addWidget(exitButton);
layout->addWidget(quitButton);
window->setLayout(layout);
QObject::connect(quitButton, SIGNAL(clicked()),window, SLOT(close())); // Adding Buttons
QObject::connect(exitButton, SIGNAL(clicked()),imageLabel, SLOT(close()));
window->show();
cvWaitKey(1);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "imageSelectNode");
ros::NodeHandle n("~");
image_transport::ImageTransport it(n);
image_transport::Subscriber sub = it.subscribe("/camera/image_raw",1, imageCallback);
imagePublisher = it.advertise("imagePublisherTopic", 1); //Publish the image in 'imagePublisherTopic' node
QApplication a(argc, argv);
ros::spin();
return 0;
}
A new window is opened, because you create a new QLabel on each frame. What you need is - one QLabel, which pixmap you should change. The simplest way to do that is to make your imageLabel static:
static QLabel *imageLabel = new QLabel;
Update:
If you want to do some manipulations to this label once (like adding it to a layout), you could do something like this:
QLabel * createLabel()
{
QLabel *l = new QLabel;
layout->addWidget(l);
return l;
}
...
static QLabel *imageLabel = createLabel();
Update 4:
QLabel * createLabel()
{
QWidget *window = new QWidget;
QLabel *imageLabel= new QLabel;
QPushButton* quitButton= new QPushButton("Quit");
QPushButton* exitButton= new QPushButton("Exit Image");
QVBoxLayout* layout= new QVBoxLayout;
layout->addWidget(imageLabel);
layout->addWidget(exitButton);
layout->addWidget(quitButton);
window->setLayout(layout);
QObject::connect(quitButton, SIGNAL(clicked()),window, SLOT(close()));
QObject::connect(exitButton, SIGNAL(clicked()),imageLabel, SLOT(close()));
window->show();
return imageLabel;
}
void imageCallback( const sensor_msgs::ImageConstPtr& msg)
{
imagePublisher.publish (cv_ptr->toImageMsg());
QImage temp(&(msg->data[0]), msg->width, msg->height, QImage::Format_RGB888);
QImage image;
image = temp;
static QLabel *imageLabel = createLabel();
imageLabel->setPixmap(QPixmap::fromImage(image));
cvWaitKey(1);
}

Resources