Работа с динамическими компонентами
Помогите разобраться в чем проблема.
Идея такая:
Есть layout под именем btnLayout в который динамически добавляются кнопки при выполнении пользователем определенных действий.
При клике пользователем на кнопку должно отработаться определенное действие закрепленное за кнопкой и все последующие кнопки (созданные после данной кнопки) необходимо удалить. (текущая остается и созданные до нее)
В дизайнере создан btnLayout (горизонтальный) в который динамически добавляются кнопки (изначально он пустой). Этот btnLayout вместе с кнопкой (someButton) и спейсером между ними помещен в горизонтальный layout.В низу фрагмент моего кода для реализации этого:
// В хедере void addButton(); QPushButton *btn[20]; qint64 btnCount = 0; // Реализация void MainWindow::addButton() { btnCount++; btn[btnCount] = new QPushButton(this); // Стиль кнопки btn[btnCount]->setStyleSheet(StyleHelper::getButtonStyleSheet()); // Настройка свойств кнопки btn[btnCount]->setCheckable(true); btn[btnCount]->setChecked(true); btn[btnCount]->setText("Текст"); ui->btnLayout->addWidget(btn[btnCount]); QString s = "..."; qint64 num = btnCount; connect(btn[btnCount], &QPushButton::clicked, [this, s, num] { nTString(s); // Удалить все последующие кнопки for(int i = num+1; i <= btnCount; i++) { disconnect(btn[i]); delete btn[i]; // Уменьшить счетчик btnCount--; } }); // Снять выделение с предыдущей кнопки if(btnCount > 0) btn[btnCount-1]->setChecked(false); }
Компиляция проходит успешно и работает.
Самое интересное начинается если для кнопки someButton добавить обработчик onClick. Тогда при запуске программа аварийно завершает работу.
При отладке выяснил, что вылет происходит на строке:
if(btnCount > 0) btn[btnCount-1]->setChecked(false);
При отладке появляется окно с текстом о том, что программа завершила свою работу получив соответствующее сообщение от ОС.
Если строку закоментировать, то все работает, только выделение с кнопок не снимается и все работает. Также работает если удалить обработчик onClick.
Но если количество динамически созданных кнопок более 5-ти, то удаляются все кнопки после текущей за исключением самой последней (ее тоже нужно удалять).
Не могу понять чем обработчик события onClick и строка
if(btnCount > 0) btn[btnCount-1]->setChecked(false);не понравились друг другу :).
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.Вам це подобається? Поділіться в соціальних мережах!
- Akiv Doros
- 12 листопада 2024 р. 01:58
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:50бали,
- Рейтинг балів-4
- molni99
- 26 жовтня 2024 р. 11:37
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:80бали,
- Рейтинг балів4
- molni99
- 26 жовтня 2024 р. 11:29
C++ - Тест 004. Указатели, Массивы и Циклы
- Результат:20бали,
- Рейтинг балів-10
Здесь снимается выделение всё-таки не с предыдущей кнопки, а с текущей. Если количество кнопок btnCount = 20, то номер текущей кнопки будет равен 19. Счёт у программистов начинается с 0. ;-)
Что это за nTString ? - это какой-то метод класса?
Насколько помню объекты объявленные в стеке лучше захватывать лямбдой через ссылку:
Учитывая, что QPushButton - это объект, который наследован от QObject, то попробуйте удалять его соответствующим методом, а не через оператор delete . Это снимает некоторые проблемы, если объект где-то ещё используется.
Но самой главной проблемой я считаю использование btnCount и num . Скорее всего, в какой-то момент происходит OutOfRange . Для num память выделяется в стеке локально в методе, и когда метод заканчивает работу, то память для num очищается, поэтому лямбда функция захватывает протухшую память. Если бы было выделение памяти в куче через указатель, то тогда всё работало бы правильно, а тут Undefined Behaviour получается.
Совет такой: Избавьтесь от использования btnCount и num . Замените строго заданный массив указателей на QPushButton на QVector. В нём всегда можно узнать количество элементов с помощью метода length() и номер текущего элемента с помощью метода indexOf() . А доводить до ума текущий код не стоит - это решение, которое в будущем создаст больше проблем.
Спасибо!
Я как-то о проблемах с памятью не подумал.
Про счет с нуля знаю :), но пишу btnCount++ - и начинаю счет с 1. :)
С векторами в Qt никогда не работал - по документации получилось, что-то такое:
Если писать так:
программа вылетает с аварийным сообщением.
Все работает корректно, только после клика на кнопке выполнить действие для добавления еще одной - вылетает с надписью: Поток 0 остановлен по причине: Exception at 0x51f01fd4, read access violation.
Вылет на строке:
Если выполнить действие для удаления кнопки, то с тем же сообщением на строке:
Так понимаю, что это ошибка доступа к памяти - ссылку на кнопку теряет?
И вопрос попутно как в отладчике в Qt Creator посмотреть значения переменных, например s из кода выше (кроме qDebug << s;). Я имею ввиду, что-то похожее на то как в отладчике MSVS.
Теперь я догадываюсь, где ошибка.
В этом коде скорее всего происходит обращение к элементу с нулевым индексом в массиве. В результате программа вылетает, поскольку там находится мусор.
Подумайте сами. btnCount равен 1, когда Вы добавили одну кнопку. И тогда Вы пытаетесь снять выделение с предыдущей кнопки, btnCount - 1, и получается 0. обращаетесь к элементу с индексом 0, к мусору. Естественно, что программа вылетала. Вы сами себе накидали граблей.
В ниже следующем куске кода явно ошибка, это вы так скопипастили из Креатора?
Правильно, что ошибку выдаёт, у вас же b - это указатель, объект сохранён в куче. Для него память выделена через new. Его нельзя по ссылке захватить.
Может наоборот?
Понятно, больше так писать. не буду.
Да и к сожалению что не так не знаю.
Такая конструкция работать отказывается - ошибка:
Работает так:
Да.
Я имел ввиду то, что написано неправильно:
Правильное написание:
Qt Creator разве не подсвечивал этот кусок?
Туплю, скобки не заметил, в креаторе все правильно написано.
И все таки, что может быть не так в коде?
И как просматривать значения переменных в отладчике в Qt Creator?
Так, а что с объявлением QVector? Это просто здесь так написали?
Или в коде это выглядит как положено?
В коде второй вариант. В первом случае почему-то скопировал не все.
Кажется знаю. Объект удалить-то удалили через deleteLater, но в самом QVector указатель-то остался. Нужно добавить ещё и удаление элемента из QVector
То есть будет так:
Еще один вопрос немного не по теме - как обновить отображаемые в QListView данные? repain и update - не выолняют нужного действия.
repaint и update только перерисовывают сам QListView с содержимым. Чтобы их обновить, необходимо обновить сами данные. Если данные не обновлялись, то выше приведённые методы не окажут видимого эффекта.
И что касается значений переменных в отладчике, во время отладки обычно открывается справа панелька с таблицей, где можно посмотреть какие в данный момент переменные активны и их содержимое.
Да работает, только все равно если кнопок больше двух последнюю кнопку не удаляет.
Цикл выглядит так:
Спасибо с обновлением данных в QListView понятно куда копать.
В отладчике таблицы нет, панель есть, но пустая.
Это уже проблема самого цикла. Когда удаляется элемент из вектора, то уменьшается его длина. Поэтому нужно сам цикл реструктурировать.
Переменные в отладчике будут отображаться, когда будете проходить код пошагово. Для этого поставьте точку останова. Нужно кликнуть в редакторе кода слева от номера строки, тогда появится большая красная точка.
Спасибо! Работает.
Спасибо, понял. Плюс нужно было поставить выбрать пункт - показывать локальные переменные.
Все равно, отладчик не всегда показывает переменные. Приходится постоянно добавлять вычисляемые значения
Ну это уже издержки производства.
Согласен :)
Еще вопросик. Решил стилизировать меню через QSS и написал такое:
В се выглядит как задумал, картинка отображается при выбранном и не выбранном пункте меню. Только появился при невыбранном виде пункта кроме картинки прямоугольник похожий на оттиск, а в нем сама картинка.
Как можно убрать этот прямоугольник?
Спасибо за помощь!
Если читателям форума понадобится, вот отредактированный рабочий код:
Что-то не совсем представляю, как выглядит этот оттиск. Можете приложить скриншот в прикрепление к сообщению?
И ещё. Делайте лучше отдельные темы по отдельным вопросам.
Буду в другой раз создавать тему.
Скриншот меню не вышел :), сделал похожий. Круг - это "моя картинка", а рамка - не мое творение.
Скриншот приложить не выходит - форум выбивает ошибку.
0
Получилось :)
Не уверен, но возможно стоит применить настройку border для QMenu::indicator:non-exclusive:checked
Не помогло. Сделал фото как это выглядит на экране.
Как вариант, наследовать QMenu и переопределить метод paintEvent и там уже отрисовывать, как хочется. Этот путь конечно посложнее, но гарантирует результат. А насчёт QSS у меня пока мыслей нет.
Немного помудрил с кодом и выяснил, что если убрать следующие строки, то и проблема исчезает, только вместе с картинками :)
Наследование это хорошо, но проблема насколько я понимаю в назначении картинки.Вообще если в коде затрагивать indicator, например так:
возникает эта проблема.
Ну а если применить border к indicator?
"Не действует."
Рабочий вариант:
Добавил следующий код:
Понял, что у меня нигде не настраивается сам элемент меню в обычном состоянии и из-за этого как оказалось и были проблемы.
Спасибо за помощь, Ваш код с "border: none;" натолкнул на правильную мысль :)