0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
1

Закрытие QTabWidget

21.09.2023, 10:03. Показов 1052. Ответов 18
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день. При закрытии виджета QTabWidget (через крестик), у него вызывается событие, которое удаляет мой класс из виджета. Я хотел бы избежать этого. Попробовал переопределить clossEvent, но даже туда не попадал.

создание виджета
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void WindowConfig::getWindow(quint8 childRow, quint8 rootRow, QString rootName, QList<QString> listNameMdl)
{
    if (widgetMap.contains(rootRow))
    {
        widgetMap.value(rootRow)->setFocus();
        widgetMap.value(rootRow)->setCurrentIndex(childRow);
    }
    else
    {
        QTabWidget *tabWidget = new QTabWidget;
 
        widgetMap.insert(rootRow, tabWidget);
 
        for (const QString &element : listNameMdl) {
            QWidget *tabContent = new QWidget(tabWidget);
 
 
            QVBoxLayout *layout = new QVBoxLayout();
            QMap <quint8, AbstractBord*> mapBrd = pManProj->getMapBrd();
 
            if(mapBrd.contains(vecBoards.at(rootRow).place))
            {
                QMap <QString, QWidget*> mapWidget = mapBrd.value(vecBoards.at(rootRow).place)->getMapCfgWidget();
                if(mapWidget.contains(element))
                {
                    layout->addWidget(mapWidget.value(element));
                }
            }
            tabContent->setLayout(layout);
            tabWidget->addTab(tabContent, element);
        }
 
        QSize desiredSize(700, 300);
        tabWidget->setMinimumSize(desiredSize);
        ui->mdiAreaWindow->addSubWindow(tabWidget);
 
        tabWidget->setWindowTitle(rootName);
        tabWidget->activateWindow();
        tabWidget->show();
 
        connect(tabWidget, &QObject::destroyed, this, [=]() {
            widgetMap.remove(rootRow);
        });
    }
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.09.2023, 10:03
Ответы с готовыми решениями:

QTabWidget
#include &lt;QtGui&gt; int main(int argc, char *argv) { QApplication app(argc, argv); ...

QT QTabWidget
Используйте теги для вставки кода в свои сообщения! #include &lt;QApplication&gt; #include...

QtabWidget C++
Добрый день!Как сделать так чтобы при нажатии,на строку виджета 2 таже строка отоброжалась в первом...

QTabWidget :)
Добрый день , уважаемые форумчанины , недавно я начал изучать библиотеку Qt, и сегодня уже -...

QTabWidget
На виджет, у которого фон задан градиентом, я размещаю элементы, в числе которых QTabWidget. Как...

18
1458 / 692 / 307
Регистрация: 02.05.2020
Сообщений: 1,569
21.09.2023, 21:06 2
Какой нибудь минимальный запускабельный пример, воспроизводящий проблему, можете предоставить? Сложно понять, что вы хотите сделать.
0
0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
22.09.2023, 06:44  [ТС] 3
С запускаемым примером проблемно будет, могу объяснить чуть лучше. У меня есть QTreeView и QMdiArea. Когда я нажимаю на элемент в QTreeView, в QMdiArea создается QTabWidget, внутри которого находится мой собственный класс. Этот QTabWidget также сохраняется в widgetMap. Однако, если я нажимаю на крестик в правом верхнем углу QTabWidget, это вызывает событие, которое в свою очередь вызывает деструктор моего класса, который находится внутри QTabWidget. Я хочу переопределить это событие, чтобы мой класс не уничтожался(тк он не создается в этом месте больше и при попытке снова нажать на уже закрытый элемент в QTreeView программа падает).
0
400 / 300 / 60
Регистрация: 29.05.2018
Сообщений: 946
22.09.2023, 07:55 4
Цитата Сообщение от diray11 Посмотреть сообщение
в QMdiArea создается QTabWidget
Целый виджет? М.б., всё-таки таб?
Цитата Сообщение от diray11 Посмотреть сообщение
Однако, если я нажимаю на крестик в правом верхнем углу QTabWidget, это вызывает событие, которое в свою очередь вызывает деструктор моего класса, который находится внутри QTabWidget.
Опять же, внутри таба или табвиджета? Слишком много непонятностей пока.

Хоть скрин приложения можете показать?
0
0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
22.09.2023, 08:09  [ТС] 5
Цитата Сообщение от Ender Che Посмотреть сообщение
Целый виджет? М.б., всё-таки таб?
Создается целый виджет
Цитата Сообщение от Ender Che Посмотреть сообщение
Опять же, внутри таба или табвиджета? Слишком много непонятностей пока.
нажимаю крестик относящийся именно к QTabWidget(не к табу)

Цитата Сообщение от Ender Che Посмотреть сообщение
Хоть скрин приложения можете показать?
Привожу пример виджета(в данном случае табов нет)
Миниатюры
Закрытие QTabWidget  
0
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
22.09.2023, 14:36 6
Цитата Сообщение от diray11 Посмотреть сообщение
При закрытии виджета QTabWidget (через крестик), у него вызывается событие, которое удаляет мой класс из виджета.
Цитата Сообщение от diray11 Посмотреть сообщение
ui->mdiAreaWindow->addSubWindow(tabWidget);
Какой класс? tabWidget? (не класс вообще-то, а обьект класса)
По идее, удалять не должно, если у окна (виджета или QMdiSubWindow) не включен атрибут Qt_WA_DeleteOnClose.
Как вы поняли, что обьект удален? Скорее всего, вы сами удаляете его (или удаляете из списка, в котором смотрите) в своем коде. Для проверки можете создать свой кастомный класс от QWidget или QTabWidget, и в конструкторе выводить в консоль дебага сообщение о создании, а в деструкторе - о уничтожении-что бы проверить, где это все происходит у вас.

Идея прикольная, вроде что-то похожее сделал:
Закрытие QTabWidget
0
0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
22.09.2023, 15:03  [ТС] 7
Цитата Сообщение от sdf45 Посмотреть сообщение
Как вы поняли, что обьект удален?
Тут очень просто, поставил точку на деструктор и после закрытия виджета попал туда.
Цитата Сообщение от sdf45 Посмотреть сообщение
Какой класс?
Вот класс AbstractBord, который наследуется от QWidget.
QMap <quint8, AbstractBord*> mapBrd = pManProj->getMapBrd();

Добавлено через 10 минут
Цитата Сообщение от sdf45 Посмотреть сообщение
Идея прикольная, вроде что-то похожее сделал:
Там главная фишка в том, чтобы при нажатии на элемент в дереве виджет поднимался
Кликните здесь для просмотра всего текста
C++ (Qt)
1
2
3
4
5
    if (widgetMap.contains(rootRow))
    {
        widgetMap.value(rootRow)->setFocus();
        widgetMap.value(rootRow)->setCurrentIndex(childRow);
    }
0
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
22.09.2023, 15:27 8
diray11, если просто закрываете окно, обьект этого окна по дефолту продолжает существовать, если для него не был установлен атрибут Qt::WA_DeleteOnClose. Что происходит в вашем коде- знаете только вы, а мне разбираться будет лень, даже если покажете его весь. Гадать можно бесконечно: может вы грохате весь виджет MDIArea, может где-то в коде происходит удаление, и тд и тп. По кускам кода понять сложно, а весь его проверять - напряжно (мне, ну мб кто-нить захочит промониторить, я хз).

Могу только посоветовать удалять виджет при закрытии окна, а для временного скрытия есть минимизация окна - вы можете видеть на гифке, я добавил три кнопки в ячейку QTreeView: минимайз, максимайз, закрытие. Вот скрытие/ показ окна -кнопками максимайза/минимайза, а при закрытии окна -оно и весь его контент удаляется, что по логике вроде.

Добавлено через 3 минуты
Цитата Сообщение от diray11 Посмотреть сообщение
главная фишка в том, чтобы при нажатии на элемент в дереве виджет поднимался
Как я уже написал, можете добавить отдельные кнопки в ячейку дерева, а так же обработать выделение строки в дереве и выделение субокна мышкой, что бы засинхронить их выделение/фокус. Я так сделал.

Добавлено через 12 минут
Зы можно немного упростить работу с сабокнами, если связать их с ячейками дерева:
C++ (Qt)
1
    QMap<QMdiSubWindow*, QStandardItem*> subWindowList;
Так можно по указателю на окно выцепить ячейку дерева,и наоборот
0
1458 / 692 / 307
Регистрация: 02.05.2020
Сообщений: 1,569
22.09.2023, 20:49 9
Цитата Сообщение от diray11 Посмотреть сообщение
Когда я нажимаю на элемент в QTreeView, в QMdiArea создается QTabWidget, внутри которого находится мой собственный класс.
ОК, а где это класс (хотя будет правильнее экземпляр класса) был до создания QTabWidget? Объект гдето существовал, вы его перенесли на вкладку, и по закрытии вкладки хотите его вернуть кудато, а вернуть нельзя, так как он грохнут, верно?
0
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
22.09.2023, 23:48 10
Цитата Сообщение от sdf45 Посмотреть сообщение
если просто закрываете окно, обьект этого окна по дефолту продолжает существовать, если для него не был установлен атрибут Qt::WA_DeleteOnClose
Похоже, что в этом случае нет...

Убрал Qt::WA_DeleteOnClose и попробовал
Цитата Сообщение от sdf45 Посмотреть сообщение
создать свой кастомный класс от QWidget или QTabWidget, и в конструкторе выводить в консоль дебага сообщение о создании, а в деструкторе - о уничтожении
Что странно, у виджета, который добавлен в QMdiSubWindow, срабатывает таки деструктор при закрытии QMdiSubWindow, даже если атрибут WA_DeleteOnClose не был для него установлен.

Почему так-я хз...
Кликните здесь для просмотра всего текста
В доке написано:
-Once the subwindow has been added, its parent will be the viewport widget of the QMdiArea.
То есть по идее оно должно быть, пока есть QMdiArea.
-The widget can be either a QMdiSubWindow or another QWidget (in which case the MDI area will create a subwindow and set the widget as the internal widget).
Виджет становится внутренним виджетом сабокна и получает его флаги, и по идее должен быть, пока есть сабокно.
Про то, что внутренний виджет полюбому чпокается, если сабокно закрывается, я инфы вроде не увидел...


Так то оно мне лично никак не мешает, я всегда устанавливаю WA_DeleteOnClose для окна в таких случаях, но ради интереса -это реализация такая специфическая или баг?
0
0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
23.09.2023, 12:48  [ТС] 11
Ну почти все так, для каждой владыки есть свой класс, при закрытии QTabWidget(не вкладки), QMdiSubWindow посылает сигнал который вычищает все мои классы. Мб из за того что классы унаследованы от qwidget и он честно очищает все виджеты. А эти классы больше не создаются и поэтому программа падает на этом месте
Кликните здесь для просмотра всего текста
C++ (Qt)
1
layout->addWidget(mapWidget.value(element));


Добавлено через 18 минут
Цитата Сообщение от sdf45 Посмотреть сообщение
это реализация такая специфическая или баг
Не совсем понял вопрос
0
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
23.09.2023, 13:28 12
Цитата Сообщение от diray11 Посмотреть сообщение
Не совсем понял вопрос
Это не к вашему коду вопрос, а скорее риторический, он врятли кому-то интересен на этом форуме
Вы были правы, -как уже выше написал,- внутренний виджет окна QMdiSubWindow уничтожается при закрытии этого самого окна... Почему так сделано разработчиками-мне не понятно:
Кликните здесь для просмотра всего текста
в документации рекомендуют программисту самому устанавливать атрибут WA:: DeleteOnClose на окно QMdiSubWindow при его создании, при том что внутренний виджет уничтожается при закрытии окна в любом случае... По логике тогда можно было сделать установку WA:: DeleteOnClose внутри реализации QMdiSubWindow, либо, если предусмотрено продление его существования, то же должно быть и с внутренним виджетом.
Вполне возможно, что я чего-то недопонял или доку недочитал. Честно говоря, ответ на этот вопрос меня не особо то и волнует, так как не вижу смысла продлевать существование обьекта окна в данном случае.


По сабжу, видимо вы, как сказал уважаемый kapbepucm, обращаетесь к обьектам, когда они уже не существуют. Я бы посоветовал заворачивать такие обьекты в смартпоинтеры и проверять их валидность перед обращением.
И пересмотреть логику кода.
0
0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
23.09.2023, 13:40  [ТС] 13
Цитата Сообщение от sdf45 Посмотреть сообщение
И пересмотреть логику кода.
Ну, из за этой фишки логику точно пересмотреть надо, а по факту элемента в дереве не будет если не будет объекта, так что я считаю что это проверка излишняя(Так как эти объекты не должны удаляться)
0
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
23.09.2023, 15:12 14
В качестве бреда, получилось (вроде, но не уверен на 100%) предотвратить удаление виджета, который засовывается в QMdiSubWindow (окно прячется при нажатии на [x], через 3 сек появляется снова, не смотря даже на то, что атрибут deleteOnClose установлен, - короче, у меня уже когнитивный диссонанс от всей этой фигни - и я больше не стану спекулировать на эту тему)

Эта хрень, скорее всего, чревата UB,- показываю ради прикола, - не делайте так, разве что для развлечения.
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//в сабклассе виджета, который станет внутренним для QMdiSubWindow 
protected:
    void closeEvent(QCloseEvent *e)override{
        QWidget::closeEvent(e);
        e->ignore();
        if(parent()){
            QWidget *w=dynamic_cast<QWidget*>(parent());
            if(w){
                w->hide();
                QTimer::singleShot(3000, w, &QWidget::show);
            }
        }
    }
};
0
1458 / 692 / 307
Регистрация: 02.05.2020
Сообщений: 1,569
23.09.2023, 20:15 15
Лучший ответ Сообщение было отмечено sdf45 как решение

Решение

Цитата Сообщение от sdf45 Посмотреть сообщение
Что странно, у виджета, который добавлен в QMdiSubWindow, срабатывает таки деструктор при закрытии QMdiSubWindow, даже если атрибут WA_DeleteOnClose не был для него установлен.
Вы просто не умеете их готовить просто не на том виджете устанавливаете этот флаг Надо не на сам виджет, а на уровень выше, т.е. на объект класса QMdiSubWindow устанавливать флаг. Привожу пример, где после закрытия на крестик не вызывается деструктор:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QPushButton>
#include <QTabWidget>
 
class Window: public QWidget
{
public:
  Window(): QWidget()
  {
    auto area = new QMdiArea;
    auto tabWidget = new QTabWidget;
    auto subWindow = new QMdiSubWindow;
    subWindow->setWidget(tabWidget);
    subWindow->setAttribute(Qt::WA_DeleteOnClose, false);
    area->addSubWindow(subWindow);
    auto button = new QPushButton("tabWidget->show");
    connect(button, &QPushButton::clicked, tabWidget, &QWidget::show);
    QVBoxLayout* l = new QVBoxLayout();
    l->addWidget(area);
    l->addWidget(button);
    setLayout(l);
  }
};
 
int main(int argc, char** argv)
{
  QApplication app(argc, argv);
  Window window;
  window.show();
  return app.exec();
}
Ну а по теме вопроса тут уже вроде дан ответ- коли у Вас стоит установка прибивать объект со всем содержимым по его закрытию- ловите это событие, отвязывайте нужный дочерний объект от родителя и тогда родитель пусть уже самовыпиливается дальше в одиночку. Или не прибивать окна по их закрытию а просто скрывать их, как я пример выше привёл.
2
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
23.09.2023, 21:20 16
Цитата Сообщение от kapbepucm Посмотреть сообщение
не на том виджете устанавливаете этот флаг
Нет, на QMdiSubWindow я его и устанавливал.

Но, если я не хотел его использовать, просто комментировал
C++ (Qt)
1
subWindow->setAttribute(Qt::WA_DeleteOnClose);
полагая, что там по умолчанию false... (если там по умолчанию true, зачем тогда в доке советуют устанавливать еще самому?)
Сделал принудительно установку в false, как у вас - и да, это работает...
Тогда получается, я где-то не понял доку...
В любом случае, спасибо за ваш ответ, я считаю его решением проблемы.

Добавлено через 11 минут
Вот цитата из доки на всякий, как я понял, флаги внутреннего виджета перекрываются флагами QMdiSubWindow.
И надо включить WA_DeleteOnClose если бла бла бла. Я думал, этот флаг по умолчанию false.
Adds widget as a new subwindow to the MDI area. If windowFlags are non-zero, they will override the flags set on the widget.

When you create your own subwindow, you must set the Qt::WA_DeleteOnClose widget attribute if you want the window to be deleted when closed in the MDI area. If not, the window will be hidden and the MDI area will not activate the next subwindow
Но сейчас глянул, он по умолчанию true! Я просто такого не ожидал, видимо сделал неверные выводы из описания в доке

Добавлено через 18 минут
зы: И кстати, интересный факт, я попробовал установить атрибут в true, а в качестве виджета такой класс
C++ (Qt)
1
2
3
4
5
6
class W: public QWidget
{
public:
    W(QWidget *parent=nullptr): QWidget(parent){qDebug()<<"create";}
    ~W(){qDebug()<<"delete";}
};
Он создается, и когда закрываю QMdiSubWindow - разрушается (во всяком случае появляется сообщение из деструктора),
но по нажатии кнопки все равно выводится. Почему так? Там типа deleteLater() и он еще не успел отлететь?
0
1458 / 692 / 307
Регистрация: 02.05.2020
Сообщений: 1,569
23.09.2023, 21:54 17
Цитата Сообщение от sdf45 Посмотреть сообщение
Почему так?
Примерчик бы глянуть
0
947 / 568 / 166
Регистрация: 30.03.2021
Сообщений: 1,902
23.09.2023, 22:26 18
kapbepucm, я извиняюсь, -сейчас попробовал запустить, но сделал очистку проекта, -и поведение изменилось на ожидаемое-обьект удаляется при закрытии окна и по нажатию на кнопку уже не выводится. Видимо глюк был. Еще раз сорри
0
0 / 0 / 0
Регистрация: 01.08.2023
Сообщений: 13
25.09.2023, 07:21  [ТС] 19
Всем спасибо, ошибка была в этом
Цитата Сообщение от diray11 Посмотреть сообщение
ui->mdiAreaWindow->addSubWindow(tabWidget);
и вполне логично почему он его вычищал даже без использования атрибута
0
25.09.2023, 07:21
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.09.2023, 07:21
Помогаю со студенческими работами здесь

Выравнивание в QTabWidget
Здравствуйте. Как можно выровнять по центру содержимое табов, которое выводится по нажатию вкладки....

QTabWidget и вкладки
Добрый вечер! Я создал три вкладки QPainter, QChart и QChartView, прекрасно. Но как мне отдельно...

Работа с QTabWidget
Добрый день,Господа. Хотелось бы разобраться в следующих проблемах. 1. Имеется QTabWidget в...

QOpenGLWidget+QTabWidget
Здраствуйте, у меня возникла проблема c памятью. Создаю виджеты, наследники QOpenGLWidget и...

QTabWidget Tabs size
Проблема собственно говоря в задании размеров вкладок. Мне необходимо что бы вкладки, создаваемые в...

Подчёркнутый текст в QTabWidget
Здравствуйте, форумчане. Есть QTabWidget. При выборе одного из элементов виджета, необходимо...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru