I'm trying to use a QStackedWidget with a custom QWidget subclass. I'm working on a simple kiosk for my house that shows one of a set of widgets when the screen is tapped. This works very well IFF I create all the stacked widgets in the class that contains the QStackedWidget. When I try to add a subclassed QWidget (lots of labels, need a container), then it displays correctly, but whenever setCurrentIndex() == 0, the subclassed QWidget's showEvent() is called. This means that the first showing has two widgets visible (see image below). Because no hideEvent is ever called for my subclassed widget, it remains visible forever. Below though, you can see that hideEvent is called when the index moves away from this widget, though it immediately gets a showEvent again.
I can hide the subclassed QWidget, but it's complicated if I can't tell that the showEvent I'm getting is the one for me, so skipping it is hard.
I see a showEvent in my subclass whenever QStackedWidget's index == 0.
I have included a short example. This example is a subset but will show the issue, as I stripped out some of the extra functions that don't impact the example (MQTT, setters/getters). I'm running KUbuntu 20.04, Qt5.12.1. I have not found a bug report related to this behavior, but I am hoping I just missed it.
Edited to udpate code examples and debug output
HomeInfo.h
#ifndef HOMEINFO_H
#define HOMEINFO_H
#include <QtCore/QtCore>
#include <QtGui/QtGui>
#include <QtWidgets/QtWidgets>
#include <QtQmqtt/QtQmqtt>
#include "resizelabel.h"
#include "trafficlightwidget.h"
#include "weatherwidget.h"
class HomeInfo : public QMainWindow
{
Q_OBJECT
public:
explicit HomeInfo(QWidget *parent = nullptr);
~HomeInfo() override;
protected:
bool event(QEvent *e) override;
private:
QLabel *m_wallClockLabel;
QLabel *m_dateLabel;
QLabel *m_officeHumidityLabel;
QLabel *m_officeTempLabel;
QLabel *m_atmosphericPressureLabel;
QLabel *m_basementHumidityLabel;
QLabel *m_basementHumidityLabelName;
QLabel *m_basementTemperatureLabel;
QLabel *m_basementTemperatureLabelName;
QWidget *m_trafficLight;
QStackedWidget *m_stack;
QWidget *m_clockGridWidget;
QGridLayout *m_clockWidgetLayout;
QWidget *m_houseGridWidget;
QGridLayout *m_houseGridLayout;
WeatherWidget *m_weatherWidget;
};
#endif // HOMEINFO_H
main application HomeInfo.cpp
#include "homeinfo.h"
HomeInfo::HomeInfo(QWidget *parent) : QMainWindow(parent)
{
QPalette pal(QColor(0,0,0));
setBackgroundRole(QPalette::Window);
pal.setColor(QPalette::Window, Qt::black);
setAutoFillBackground(true);
setPalette(pal);
QFont c("Roboto-Regular", 84);
c.setBold(true);
QFont d("Roboto-Regular", 32);
QFont t("Roboto-Regular", 24);
QFont n("Roboto-Regular", 18);
m_stack = new QStackedWidget(this);
m_clockGridWidget = new QWidget();
m_clockWidgetLayout = new QGridLayout(m_clockGridWidget);
m_wallClockLabel = new QLabel();
m_wallClockLabel->setScaledContents(true);
m_wallClockLabel->setFont(c);
m_wallClockLabel->setAlignment(Qt::AlignCenter);
m_dateLabel = new QLabel();
m_dateLabel->setScaledContents(true);
m_dateLabel->setFont(d);
m_dateLabel->setAlignment(Qt::AlignCenter);
m_officeHumidityLabel = new QLabel();
m_officeHumidityLabel->setScaledContents(true);
m_officeHumidityLabel->setFont(t);
m_officeHumidityLabel->setAlignment(Qt::AlignCenter);
m_officeTempLabel = new QLabel();
m_officeTempLabel->setScaledContents(true);
m_officeTempLabel->setFont(t);
m_officeTempLabel->setAlignment(Qt::AlignCenter);
m_trafficLight = new QWidget();
m_clockWidgetLayout->setHorizontalSpacing(20);
m_clockWidgetLayout->addWidget(m_wallClockLabel, 0, 0, 3, 6);
m_clockWidgetLayout->addWidget(m_officeTempLabel, 3, 0, 1, 3);
m_clockWidgetLayout->addWidget(m_officeHumidityLabel, 3, 3, 1, 3);
m_clockWidgetLayout->addWidget(m_trafficLight, 3, 5, 3, 1);
m_clockWidgetLayout->addWidget(m_dateLabel, 4, 0, 2, 5);
m_basementHumidityLabel = new QLabel();
m_basementHumidityLabel->setScaledContents(true);
m_basementHumidityLabel->setAlignment(Qt::AlignCenter);
m_basementHumidityLabel->setFont(t);
m_basementTemperatureLabel = new QLabel();
m_basementTemperatureLabel->setScaledContents(true);
m_basementTemperatureLabel->setAlignment(Qt::AlignCenter);
m_basementTemperatureLabel->setFont(t);
m_basementTemperatureLabelName = new QLabel("Basement Temp");
m_basementTemperatureLabelName->setFont(n);
m_basementHumidityLabelName = new QLabel("Basement Humidity");
m_basementHumidityLabelName->setFont(n);
m_houseGridWidget = new QWidget();
m_houseGridLayout = new QGridLayout(m_houseGridWidget);
m_houseGridLayout->addWidget(m_basementTemperatureLabelName, 0, 0);
m_houseGridLayout->addWidget(m_basementHumidityLabelName, 0, 1);
m_houseGridLayout->addWidget(m_basementTemperatureLabel, 1, 0);
m_houseGridLayout->addWidget(m_basementHumidityLabel, 1, 1);
connect(m_stack, &QStackedWidget::currentChanged, this, &HomeInfo::stackWidgetChanged);
m_weatherWidget = new WeatherWidget();
m_weatherWidget->setVisible(false);
m_stack->addWidget(m_clockGridWidget);
m_stack->addWidget(m_houseGridWidget);
m_stack->addWidget(m_weatherWidget);
setCentralWidget(m_stack);
}
HomeInfo::~HomeInfo() = default;
void HomeInfo::stackWidgetChanged(int index)
{
qDebug() << __PRETTY_FUNCTION__;
Q_UNUSED(index)
}
bool HomeInfo::event(QEvent *e)
{
if (e->type() == QEvent::MouseButtonRelease) {
qDebug() << __PRETTY_FUNCTION__;
if (m_stack->currentIndex() == (m_stack->count() - 1)) {
m_stack->setCurrentIndex(0);
}
else {
m_stack->setCurrentIndex(m_stack->currentIndex() + 1);
}
return true;
}
return QMainWindow::event(e);
}
WeatherWidget.h
#ifndef WEATHERWIDGET_H
#define WEATHERWIDGET_H
#include <QtCore/QtCore>
#include <QtWidgets/QtWidgets>
class WeatherWidget : public QWidget
{
Q_OBJECT
public:
WeatherWidget(QWidget *parent = nullptr);
~WeatherWidget() override;
protected:
void hideEvent(QHideEvent *event) override;
void showEvent(QShowEvent *event) override;
private:
QLabel *m_outdoorTemperatureLabel;
QLabel *m_outdoorTemperatureTextLabel;
QLabel *m_outdoorHumidityLabel;
QLabel *m_outdoorHumidityTextLabel;
QLabel *m_luxLabel;
QLabel *m_luxTextLabel;
QLabel *m_uvRawLabel;
QLabel *m_uvRawTextLabel;
QLabel *m_uvIndexLabel;
QLabel *m_uvIndexTextLabel;
QLabel *m_rainTodayLabel;
QLabel *m_rainTodayTextLabel;
QLabel *m_totalRainLabel;
QLabel *m_totalRainTextLabel;
QLabel *m_airPressureMercuryLabel;
QLabel *m_airPressureMercuryTextLabel;
QLabel *m_airPressureTrendLabel;
QLabel *m_airPressureTrendTextLabel;
QGridLayout *m_layout;
};
#endif // WEATHERWIDGET_H
WeatherWidget.cpp
#include "weatherwidget.h"
WeatherWidget::WeatherWidget(QWidget *parent) : QWidget(parent)
{
QDate now = QDate::currentDate();
QFont text("Roboto-Sans", 14);
QFont content("Roboto-Sans", 20);
m_outdoorTemperatureLabel = new QLabel();
m_outdoorTemperatureLabel->setFont(content);
m_outdoorTemperatureLabel->setAlignment(Qt::AlignCenter);
m_outdoorHumidityLabel = new QLabel();
m_outdoorHumidityLabel->setFont(content);
m_outdoorHumidityLabel->setAlignment(Qt::AlignCenter);
m_luxLabel = new QLabel();
m_luxLabel->setFont(content);
m_luxLabel->setAlignment(Qt::AlignCenter);
m_uvIndexLabel = new QLabel();
m_uvIndexLabel->setFont(content);
m_uvIndexLabel->setAlignment(Qt::AlignCenter);
m_rainTodayLabel = new QLabel();
m_rainTodayLabel->setFont(content);
m_rainTodayLabel->setAlignment(Qt::AlignCenter);
m_totalRainLabel = new QLabel();
m_totalRainLabel->setFont(content);
m_totalRainLabel->setAlignment(Qt::AlignCenter);
m_airPressureMercuryLabel = new QLabel();
m_airPressureMercuryLabel->setFont(content);
m_airPressureMercuryLabel->setAlignment(Qt::AlignCenter);
m_airPressureTrendLabel = new QLabel();
m_airPressureTrendLabel->setFont(content);
m_airPressureTrendLabel->setAlignment(Qt::AlignCenter);
m_outdoorTemperatureTextLabel = new QLabel("Temperature");
m_outdoorTemperatureTextLabel->setFont(text);
m_outdoorTemperatureTextLabel->setAlignment(Qt::AlignCenter);
m_outdoorHumidityTextLabel = new QLabel("Humidity");
m_outdoorHumidityTextLabel->setFont(text);
m_outdoorHumidityTextLabel->setAlignment(Qt::AlignCenter);
m_luxTextLabel = new QLabel("Brightness");
m_luxTextLabel->setFont(text);
m_luxTextLabel->setAlignment(Qt::AlignCenter);
m_uvIndexTextLabel = new QLabel("UV Index");
m_uvIndexTextLabel->setFont(text);
m_uvIndexTextLabel->setAlignment(Qt::AlignCenter);
m_rainTodayTextLabel = new QLabel("Rainfall Today");
m_rainTodayTextLabel->setFont(text);
m_rainTodayTextLabel->setAlignment(Qt::AlignCenter);
m_totalRainTextLabel = new QLabel();
m_totalRainTextLabel->setFont(text);
m_totalRainTextLabel->setAlignment(Qt::AlignCenter);
m_airPressureMercuryTextLabel = new QLabel("Air Pressure");
m_airPressureMercuryTextLabel->setFont(text);
m_airPressureMercuryTextLabel->setAlignment(Qt::AlignCenter);
m_airPressureTrendTextLabel = new QLabel("Air Pressure Trend");
m_airPressureTrendTextLabel->setFont(text);
m_airPressureTrendTextLabel->setAlignment(Qt::AlignCenter);
m_layout = new QGridLayout(this);
m_layout->addWidget(m_outdoorTemperatureTextLabel, 0, 0);
m_layout->addWidget(m_outdoorTemperatureLabel, 1, 0);
m_layout->addWidget(m_outdoorHumidityTextLabel, 0, 1);
m_layout->addWidget(m_outdoorHumidityLabel, 1, 1);
m_layout->addWidget(m_airPressureMercuryTextLabel, 0, 2);
m_layout->addWidget(m_airPressureMercuryLabel, 1, 2);
m_layout->addWidget(m_luxTextLabel, 2, 0);
m_layout->addWidget(m_luxLabel, 3, 0);
m_layout->addWidget(m_uvIndexTextLabel, 2, 1);
m_layout->addWidget(m_uvIndexLabel, 3, 1);
m_layout->addWidget(m_airPressureTrendTextLabel, 2, 2);
m_layout->addWidget(m_airPressureTrendLabel, 3, 2);
m_layout->addWidget(m_rainTodayTextLabel, 4, 0);
m_layout->addWidget(m_rainTodayLabel, 5, 0);
m_layout->addWidget(m_totalRainTextLabel, 4, 1);
m_layout->addWidget(m_rainTodayLabel, 5, 1);
setLayout(m_layout);
m_totalRainTextLabel->setText(QString("%1 Rainfall").arg(now.year()));
}
WeatherWidget::~WeatherWidget()
{
}
void WeatherWidget::showEvent(QShowEvent* event)
{
qDebug() << __PRETTY_FUNCTION__;
}
void WeatherWidget::hideEvent(QHideEvent* event)
{
qDebug() << __PRETTY_FUNCTION__;
}
main.cpp
#include "homeinfo.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
HomeInfo w;
app.setOverrideCursor(QCursor(Qt::BlankCursor));
w.setGeometry(0, 0, 800, 480);
w.show();
return app.exec();
}
Debug output
void HomeInfo::stackWidgetChanged(int) : Index 0 // constructor
virtual void WeatherWidget::showEvent(QShowEvent*) // constructor
virtual bool HomeInfo::event(QEvent*) // touchevent
void HomeInfo::stackWidgetChanged(int) : Index 1
virtual bool HomeInfo::event(QEvent*) //touchevent
void HomeInfo::stackWidgetChanged(int) : Index 2
virtual bool HomeInfo::event(QEvent*) // touchevent
virtual void WeatherWidget::hideEvent(QHideEvent*) //WeatherWidget gets hidden
void HomeInfo::stackWidgetChanged(int) : Index 0 // signal that index changed to HomeInfo
virtual void WeatherWidget::showEvent(QShowEvent*) // WeatherWidget gets another showEvent
virtual void WeatherWidget::hideEvent(QHideEvent*) // after X closes window
virtual void WeatherWidget::hideEvent(QHideEvent*) // after X closes window
*** Exited normally ***```
No, this was just a dumb mistake. I used autocomplete when I attempted to type setLux() in HomeInfo.cpp (not visible, I removed the MQTT functions), and what I got was setVisible(). This meant that every time I got a new value for how bright it is outside, it was setVisible(true) on the widget when the double was implicitly cast to true. I would have expected a warning from gcc, but either warnings are turned off, or it wasn't generated. Ah well, this was not a QT bug or odd unexpected behavior, it was a mistake in my code.
Related
Following my previous post I have been trying to solve a positioning problem withing a QGraphicsView.
After a widget is dragged from a QListWidget and dropped inside a QGraphicsView, it jumps everywhere.
The problem I have been trying to solve with also the help of another user is the following:
As soon as the widget is dragged inside the QGraphicsView and dropped. It just goes in random locations and have to pay attention to retrieve it. This behavior is not user friendly and sometimes it takes a bit to locate the widget.
Below the code:
scene.h
#ifndef SCENE_H
#define SCENE_H
#include <QGraphicsScene>
class Scene : public QGraphicsScene
{
public:
Scene(QObject *parent = nullptr);
protected:
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
void dragMoveEvent(QGraphicsSceneDragDropEvent *event);
void dropEvent(QGraphicsSceneDragDropEvent *event);
};
#endif // SCENE_H
scene.cpp
void Scene::dropEvent(QGraphicsSceneDragDropEvent *event)
{
QByteArray encoded =
event->mimeData()->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
QStringList rosTables;
QString newString;
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
rosTables << roleDataMap[Qt::DisplayRole].toString();
}
for (const QString &tableType : rosTables) {
if (tableType == "Images") {
QPoint initPos(0, 0);
auto *wgt = new CustomTableWidget;
auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
QBrush(Qt::darkGreen));
auto *sizeGrip = new QSizeGrip(wgt);
auto *layout = new QHBoxLayout(wgt);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(sizeGrip, 0, Qt::AlignRight | Qt::AlignBottom);
connect(wgt, &CustomTableWidget::sizeChanged, [wgt, proxyControl](){
proxyControl->setRect(wgt->geometry().adjusted(-10, -10, 10, 10));
});
wgt->setColumnCount(2);
wgt->setRowCount(2);
for (int ridx = 0; ridx < wgt->rowCount(); ridx++) {
for (int cidx = 0; cidx < wgt->columnCount(); cidx++) {
auto *item = new QTableWidgetItem();
item->setText(QString("%1").arg(ridx));
wgt->setItem(ridx,cidx,item);
}
}
auto *const proxy = addWidget(wgt);
proxy->setPos(initPos.x(), initPos.y()
+ proxyControl->rect().height());
proxy->setParentItem(proxyControl);
proxyControl->setPos(initPos.x(), initPos.y());
proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);
proxyControl->setRect(wgt->geometry().adjusted(-10, -10, 10, 10));
}
}
}
What it was tried so far to solve the problem:
Now the QGraphicsScene have been subclassed to re-write the mouse events, in particular and in this case attention was given to the dropEvent(QGraphicsSceneDragDropEvent *event) as that is the responsible function to "see the widget"
Several trials and errors were conducted and in the same function it was tried to add the following part:
for (const QString &tableType : rosTables) {
if (tableType == "Images") {
QPoint initPos(event->scenePos()); // <-- Tried this but no change
auto *wgt = new CustomTableWidget;
auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
QBrush(Qt::darkGreen));
auto *sizeGrip = new QSizeGrip(wgt);
auto *layout = new QHBoxLayout(wgt);
}
An additional thing tried was to provide the QPoint the event->scenePos().toPoint() as deemed proper for the goal, but unfortunately that didn't solve the problem either:
for (const QString &tableType : rosTables) {
if (tableType == "Images") {
QPoint initPos(event->scenePos().toPoint()); // <-- Tried this too but no change
auto *wgt = new CustomTableWidget;
auto *proxyControl = addRect(0, 0, 0, 0, QPen(Qt::black),
QBrush(Qt::darkGreen));
auto *sizeGrip = new QSizeGrip(wgt);
auto *layout = new QHBoxLayout(wgt);
}
If anyone has an idea of what the problem might be please provide guidance on how to solve it.
Change proxy->setPos(initPos.x(), initPos.y() + proxyControl->rect().height()); to proxy->setPos(10, 10);.
Set scene rect:
Scene::Scene(QObject *parent) :
QGraphicsScene(parent)
{
setBackgroundBrush(Qt::lightGray);
setSceneRect(0, 0, 1000, 1000);
}
Set view alignment, e.g. in MainWindow.cpp:
ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
I created a widget class. This class will be maintaining child_1 of type QFrame(which is of type QWidget) and also a child_2 of type QGridLayout . child_2 will be adding child_1 to itself. The child_1 will be having a child of type QGridLayout and ultimately QGridLayout will be having some push buttons.
*I am unable to adjust the size of QFrame child(child_1)as per the adjustment of parent widget.
Also, I am trying to set the size of QFrame child that of parent. Even this isn't happening.
I have tried using methods setFrameRect(), setGeometry() and resize().
I have implemented evenhandler resizeEvent(QResizeEvent event). But while application is running, I am trying to resize the widget and I see that log isn't printing.
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
QGridLayout* p_mPanelLayout; // Instance of QGridLayout.
FrameDemo* framePtr;
};
widget.cpp
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
p_mPanelLayout = new QGridLayout(this);
framePtr = new FrameDemo(this);
framePtr->createPushButtonUtility();
p_mPanelLayout->addWidget(framePtr, 0, 0, Qt::AlignCenter);
}
Widget::~Widget()
{
delete ui;
}
framedemo.h
#define LOG(message){\
qDebug()<< __LINE__<<__FUNCTION__<<message<<"\n";\
}
class FrameDemo : public QFrame
{
Q_OBJECT
public:
FrameDemo(QWidget *parent = 0);
void createPushButtonUtility();
private:
QGridLayout* m_pLayout;
protected:
void resizeEvent(QResizeEvent * event);
};
framedemo.cpp
FrameDemo::FrameDemo(QWidget *parent):QFrame(parent)
{
m_pLayout = new QGridLayout(this);
// m_pLayout->setRowStretch(0, parent->width());
QRect defaultRect = rect();
QSize currentSize = size();
LOG(currentSize.height())
LOG(currentSize.width())
int xP1 = 0;
int yP1 = 0;
int xP2 = 0;
int yP2 = 0;
defaultRect.getCoords(&xP1, &yP1, &xP2, &yP2);
LOG(xP1)
LOG(yP1)
LOG(xP2)
LOG(yP2)
LOG(parent->width())
LOG(defaultRect.height())
// QRect newRect = QRect(xP1,yP1,parent->width(),defaultRect.height());
// QRect newRect = QRect(0, 0, 0, defaultRect.height());
// setFrameRect(newRect);
resize(QSize(400, currentSize.height()));
setFrameShape(QFrame::Box);
// setGeometry(0, 0, parent->width(), defaultRect.height());
}
void FrameDemo::createPushButtonUtility()
{
QPushButton *readButton = new QPushButton("Read", this);
m_pLayout->addWidget(readButton, 0, 0, Qt::AlignCenter);
QPushButton *writeButton = new QPushButton("Write", this);
m_pLayout->addWidget(writeButton, 0, 1, Qt::AlignCenter);
QPushButton *updateButton = new QPushButton("Update", this);
m_pLayout->addWidget(updateButton, 0, 2, Qt::AlignCenter);
}
void FrameDemo::resizeEvent(QResizeEvent *event)
{
LOG("resize")
}
I managed to fix the problem.
I missed to implement the event handler resizeEvent(QResizeEvent *event) in parent widget.
I implemented the same and called the resizeEvent of FrameDemo. Inside this event handler, I called setGeometry().
My purpose is to use a class called overlay.h to add a rectangular box and text on top of a Widget (MarbleWidget). Here below is my code for the GUI. I tried to remove all unnecessary parts:
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setupUi(this);
}
MainWindow::~MainWindow()
{
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
overlay->resize(event->size()); //////////////// CAUSES SIGSEGV!!!!!!!!!!!!!
event->accept();
}
void MainWindow::setupUi(QMainWindow *MainWindow)
{
MainWindow->showMaximized();
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(MainWindow->sizePolicy().hasHeightForWidth());
MainWindow->setSizePolicy(sizePolicy);
MainWindow->setTabShape(QTabWidget::Rounded);
QWidget *centralwidget = new QWidget(MainWindow);
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
sizePolicy.setHeightForWidth(centralwidget->sizePolicy().hasHeightForWidth());
centralwidget->setSizePolicy(sizePolicy);
centralwidget->setLayoutDirection(Qt::LeftToRight);
QGridLayout *gridLayout_4 = new QGridLayout(centralwidget);
gridLayout_4->setObjectName(QString::fromUtf8("gridLayout_4"));
QSplitter *splitter_4 = new QSplitter(centralwidget);
splitter_4->setObjectName(QString::fromUtf8("splitter_4"));
splitter_4->setOrientation(Qt::Horizontal);
QTabWidget *tabWidget_2 = new QTabWidget(splitter_4);
tabWidget_2->setObjectName(QString::fromUtf8("tabWidget_2"));
sizePolicy.setHeightForWidth(tabWidget_2->sizePolicy().hasHeightForWidth());
tabWidget_2->setSizePolicy(sizePolicy);
tabWidget_2->setMaximumSize(QSize(443, 16777));
tabWidget_2->setAutoFillBackground(true);
tabWidget_2->setTabPosition(QTabWidget::West);
tabWidget_2->setTabShape(QTabWidget::Rounded);
tabWidget_2->setIconSize(QSize(30, 16));
QWidget *tab_10 = new QWidget();
tab_10->setObjectName(QString::fromUtf8("tab_10"));
QGridLayout *gridLayout = new QGridLayout(tab_10);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
QVBoxLayout *verticalLayout_4 = new QVBoxLayout();
verticalLayout_4->setObjectName(QString::fromUtf8("verticalLayout_4"));
QHBoxLayout *horizontalLayout_7 = new QHBoxLayout();
horizontalLayout_7->setObjectName(QString::fromUtf8("horizontalLayout_7"));
QLabel *label_3 = new QLabel(tab_10);
label_3->setObjectName(QString::fromUtf8("label_3"));
horizontalLayout_7->addWidget(label_3);
verticalLayout_4->addLayout(horizontalLayout_7);
QTreeView *treeView_4 = new QTreeView(tab_10);
treeView_4->setObjectName(QString::fromUtf8("treeView_4"));
QStandardItemModel *standardModel = new QStandardItemModel ;
QStandardItem *rootNode = standardModel->invisibleRootItem();
treeView_4->setModel(standardModel);
verticalLayout_4->addWidget(treeView_4);
gridLayout->addLayout(verticalLayout_4, 0, 0, 1, 1);
tabWidget_2->addTab(tab_10, QString());
treeView_4->raise();
Marble::MarbleWidget* MarbleWidget = new Marble::MarbleWidget(splitter_4);
splitter_4->addWidget(MarbleWidget);
splitter_4->setStretchFactor(0,0);
splitter_4->setStretchFactor(1,6);
gridLayout_4->addWidget(splitter_4, 0, 0, 1, 1);
MainWindow->setCentralWidget(centralwidget);
MarbleWidget->raise();
tabWidget_2->raise();
overlay = new Overlay(MarbleWidget);
overlay->raise();
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
overlay.h
#include <QWidget>
#include <QPainter>
class Overlay : public QWidget
{
public:
Overlay(QWidget *parent);
protected:
void paintEvent(QPaintEvent *event);
};
overlay.cpp
#include "overlay.h"
Overlay::Overlay(QWidget *parent)
: QWidget(parent)
{
setPalette(Qt::transparent);
setAttribute(Qt::WA_TransparentForMouseEvents);
}
void Overlay::paintEvent(QPaintEvent *event)
{
QFont font;
font.setStyleHint(QFont::Helvetica, QFont::PreferAntialias);
font.setPointSize(10);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QColor(10, 10, 10, 255));
painter.fillRect(QRect(50, 50, 100, 100), QColor(100, 100, 100, 120));
painter.setFont(font);
painter.drawText(20, 20, "hi..............................");
}
The problem is that overlay->resize(event->size()); causes SIGSEGV when the core runs that line.
What is wrong with the code, how can I fix it?
The problem is solved by Thiago from freenode.
He pointed that MainWindow->showMaximized(); causes resize() event to be occurred before overlay is initialized. Removing that line or moving it to after the initialization solves the problem.
Take a look at official documentation: QWidget, Qt5 at resize method. Here you can read
Warning: Calling resize() or setGeometry() inside resizeEvent() can lead to infinite recursion.
You are doing exactly the same. To avoid infinite recursion and respectively your SIGSEGV you can (descending order of difficulty, descending order of true-way):
overwrite your resizeEvent() in Overlay and comment that line in MainWindow's resizeEvent;
in MainWindow's resizeEvent emit signal like mainWindowSizeChanged(QSize) and connect it to your Overlay's slot;
do QTimer::singleShot(...) in MainWindow's resizeEvent, so it will call a given slot after a given time interval.
My problem is to get the QAction of custom widget from the outside and insert in menu of mainwindow. There is QActionWidget but it inserts custom widget in menu.
class QDESIGNER_WIDGET_EXPORT Photo_list: public QWidget
{
Q_OBJECT
public:
Photo_list(QWidget* parent = 0);
~Photo_list();
int count();
QString returnImagePath(const int i);
void sendSignalImageLoaded();
public slots:
void addImagePath();
void deleteImagePath();
signals:
void imageLoaded(int count);
//private:
public:
Ui::Photo_list *m_photo_list_ui;
QStringList m_image_path_list;
};
class Ui_Photo_list
{
public:
QAction *addImageAction;
QAction *deleteImageAction;
QGridLayout *gridLayout;
QListWidget *listWidget;
void setupUi(QWidget *Photo_list)
{
if (Photo_list->objectName().isEmpty())
Photo_list->setObjectName(QString::fromUtf8("Photo_list"));
Photo_list->resize(274, 210);
addImageAction = new QAction(Photo_list);
addImageAction->setObjectName(QString::fromUtf8("addImageAction"));
deleteImageAction = new QAction(Photo_list);
deleteImageAction->setObjectName(QString::fromUtf8("deleteImageAction"));
gridLayout = new QGridLayout(Photo_list);
gridLayout->setContentsMargins(0, 0, 0, 0);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
gridLayout->setHorizontalSpacing(0);
listWidget = new QListWidget(Photo_list);
listWidget->setObjectName(QString::fromUtf8("listWidget"));
listWidget->setTextElideMode(Qt::ElideMiddle);
listWidget->setMovement(QListView::Static);
listWidget->setResizeMode(QListView::Adjust);
listWidget->setViewMode(QListView::IconMode);
gridLayout->addWidget(listWidget, 0, 0, 1, 1);
retranslateUi(Photo_list);
QMetaObject::connectSlotsByName(Photo_list);
} ...
How to add QAction *addImageAction in ( * )? (see comment below)
class Ui_Cpdfa
{
public:
QAction *createPdfAction;
QWidget *centralwidget;
QGridLayout *gridLayout_2;
QGridLayout *gridLayout;
QLineEdit *pdfPathLineEdit;
QPushButton *findPdfPathButton;
Photo_list *photo_list;
QToolBar *toolBar;
QMenuBar *menuBar;
QMenu *menu;
QMenu *menu_2;
void setupUi(QMainWindow *Cpdfa)
{
if (Cpdfa->objectName().isEmpty())
Cpdfa->setObjectName(QString::fromUtf8("Cpdfa"));
Cpdfa->resize(386, 303);
createPdfAction = new QAction(Cpdfa);
createPdfAction->setObjectName(QString::fromUtf8("createPdfAction"));
centralwidget = new QWidget(Cpdfa);
centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
gridLayout_2 = new QGridLayout(centralwidget);
gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2"));
gridLayout = new QGridLayout();
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
pdfPathLineEdit = new QLineEdit(centralwidget);
pdfPathLineEdit->setObjectName(QString::fromUtf8("pdfPathLineEdit"));
gridLayout->addWidget(pdfPathLineEdit, 0, 0, 1, 1);
findPdfPathButton = new QPushButton(centralwidget);
findPdfPathButton->setObjectName(QString::fromUtf8("findPdfPathButton"));
gridLayout->addWidget(findPdfPathButton, 0, 1, 1, 1);
photo_list = new Photo_list(centralwidget);
photo_list->setObjectName(QString::fromUtf8("photo_list"));
gridLayout->addWidget(photo_list, 1, 0, 1, 2);
gridLayout_2->addLayout(gridLayout, 0, 0, 1, 1);
Cpdfa->setCentralWidget(centralwidget);
toolBar = new QToolBar(Cpdfa);
toolBar->setObjectName(QString::fromUtf8("toolBar"));
Cpdfa->addToolBar(Qt::TopToolBarArea, toolBar);
menuBar = new QMenuBar(Cpdfa);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 386, 21));
menu = new QMenu(menuBar);
menu->setObjectName(QString::fromUtf8("menu"));
menu_2 = new QMenu(menuBar);
menu_2->setObjectName(QString::fromUtf8("menu_2"));
Cpdfa->setMenuBar(menuBar);
toolBar->addAction(createPdfAction); //!!(*)
toolBar->addSeparator();
menuBar->addAction(menu->menuAction());
menuBar->addAction(menu_2->menuAction());
menu->addSeparator();
menu_2->addAction(createPdfAction); //!!(*)
retranslateUi(Cpdfa);
QMetaObject::connectSlotsByName(Cpdfa);
} // setupUi
I guess you are using Qt creator and designing forms separately with the form editor.
Your problem is acutally that you want the class A(a "larger" widget which comprises the subobjects) to access members in the namespace of its subobject B(your photo_list widget).
To do this,
Move the inclusion "ui_B.h" from B.cpp to B.h
Inside B.h make the private memeber Ui::B *ui; public (or you can have A and B become friends)
After including "B.h" and having a subobject pointer *B, you can call B->ui->actionXXX in A to access all memebers of B, since B->ui points to the namespace that includes all memebers created from B.ui file (which turn out to be inside "ui_B.h")
Say I have a QHBoxLayout where there are 2 QTextEdits and between them a button with an arrow to the right. When you click on the button, the right-side QTextEdit gradually closes by moving the left border until it meets the right one. Simultaneously, the right border of the left QTextEdit takes the place which the right QTextEdit released. And after pressing on the button, the state of the system is coming to the former one.
EDIT: In order to organize this I have done the following:
1) In header file:
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
int m_deltaX;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
2) In the source file:
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1);
m_layout->addWidget(m_pushButton);
m_layout->addWidget(m_textEditor2);
setLayout(m_layout);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "geometry");
QPropertyAnimation *animation2 = new QPropertyAnimation(m_pushButton, "geometry");
QPropertyAnimation *animation3 = new QPropertyAnimation(m_textEditor1, "geometry");
if(isClosing) //close the second textEdit
{
m_pushButton->setText("<");
QRect te2_1 = m_textEditor2->geometry();
m_deltaX = te2_1.width()-3;
QRect te2_2(te2_1.x()+m_deltaX, te2_1.y(), 3 ,te2_1.height());
QRect pb_1 = m_pushButton->geometry();
QRect pb_2(pb_1.x()+m_deltaX, pb_1.y(), pb_1.width() ,pb_1.height());
QRect te1_1 = m_textEditor1->geometry();
QRect te1_2(te1_1.x(), te1_1.y(), te1_1.width()+m_deltaX, te1_1.height());
//animation->setDuration(10000);
animation1->setStartValue(te2_1);
animation1->setEndValue(te2_2);
animation2->setStartValue(pb_1);
animation2->setEndValue(pb_2);
animation3->setStartValue(te1_1);
animation3->setEndValue(te1_2);
}
else //open
{
m_pushButton->setText(">");
QRect te2_1 = m_textEditor2->geometry();
QRect te2_2(te2_1.x()-m_deltaX, te2_1.y(), 3+m_deltaX ,te2_1.height());
QRect pb_1 = m_pushButton->geometry();
QRect pb_2(pb_1.x()-m_deltaX, pb_1.y(), pb_1.width() ,pb_1.height());
QRect te1_1 = m_textEditor1->geometry();
QRect te1_2(te1_1.x(), te1_1.y(), te1_1.width()-m_deltaX, te1_1.height());
//animation->setDuration(10000);
animation1->setStartValue(te2_1);
animation1->setEndValue(te2_2);
animation2->setStartValue(pb_1);
animation2->setEndValue(pb_2);
animation3->setStartValue(te1_1);
animation3->setEndValue(te1_2);
}
animation1->start();
animation2->start();
animation3->start();
}
EDIT:
And I have the following problem:
When I close the second QTextEdit (by clicking on the button) and resize the MyWidget, then the QTextEdit restores its state (but it should stay closed of course). How can I solve this problem?
Please provide me with a code snippet.
Qt's Animation framework sounds like a good place to start. You could just try to follow their tutorials, adapting for you use case. I have used it already, and it seemed quite straight forward.
1) You could replace your button with a vertical layout, place the button inside this layout and finally add a vertical spacer below the button (in same the layout).
...
QVBoxLayout* m_buttonLayout = new QVBoxLayout();
m_layout = new QHBoxLayout();
m_layout->addWidget(m_textEditor1);
m_layout->addLayout(m_buttonLayout);
m_layout->addWidget(m_textEditor2);
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
2) I guess you could (and should) animate widget's maximumSize (or just maximumWidth) property and let the layout take care of calculating actual geometries. This would also simplify your calculations. E.g.
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
QPropertyAnimation *animation2 = new QPropertyAnimation(m_textEditor, "maximumWidth");
if (isClosing)
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = 0;
int textEdit_start = m_textEditor->maximumWidth();
int textEdit_end = textEdit_start + textEdit2_start;
animation1->setStartValue(textEdit2_start);
...
}
Also, now you don't have to animate buttons geometry at all (assuming that you have set fixed size to it).
PS. I didn't compile codes so there might be minor errors but you should get the idea.
Here what I wanted:
Header file
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
QVBoxLayout *m_buttonLayout;
int m_deltaX;
bool m_isClosed;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
void resizeEvent( QResizeEvent * event );
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
Source file
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
m_pushButton->setFixedSize(16,16);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_buttonLayout = new QVBoxLayout();
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1, 10);
m_layout->addSpacing(15);
m_layout->addLayout(m_buttonLayout);
m_layout->setSpacing(0);
m_layout->addWidget(m_textEditor2, 4);
setLayout(m_layout);
resize(800,500);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
m_isClosed = isClosing;
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
if(isClosing) //close the second textEdit
{
m_textEditor2->setMaximumWidth(m_textEditor2->width());
int textEdit2_start = m_textEditor2->maximumWidth();
m_deltaX = textEdit2_start;
int textEdit2_end = 3;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText("<");
}
else //open
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = m_deltaX;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText(">");
}
animation1->start();
}
void MyWidget::resizeEvent( QResizeEvent * event )
{
if(!m_isClosed)
m_textEditor2->setMaximumWidth( QWIDGETSIZE_MAX );
}