Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Гурман от Апрель 22, 2015, 12:18



Название: (РЕШЕНО) Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 12:18
У меня в приложении для хранения состояния окон используется пара saveGeometry() и restoreGeometry(). Для окон диалогов, наследующих от QDialog и QMainWindow всё превосходно давно работает. Никаких проблем не было.

Надо сделать сохранение положения виджетов контролов, размещаемых пользователем на QDialog. Они все тоже QWidget, и в этом отношении от окон не отличаются. Значит использую хорошо отлаженную функцию сохранения и восстановления, просто один-в-один. Но получаю какой-то бред. После исключения всего кода, где могли бы быть ошибки (хотя их нет, работает уже несколько лет без нареканий) осталось вот это:

Код:
    qDebug() << pos();
    restoreGeometry( saveGeometry() );
    qDebug() << pos();

На выходе
Цитировать
QPoint(0,0)
QPoint(0,68)
Что за????.... ???
Дальше замечаю еще более странное поведение - если перед вызовом saveGeometry() вертикальная координата виджета на диалоге была меньше 68, то saveGeometry() упорно возвращает 68. Если больше 68 - то возвращается правильная вертикальная координата, как есть. Горизонтальную координату saveGeometry() всегда возвращает правильную.

Проверил с несколькими виджетами - QPushButton (наследует QAbstractButton), QSlider (QAbstractSlider), QComboBox (наследует QWidget напрямую) - везде результат совершенно одинаковый.

Может я пропустил чего? В Интернете репортов про такой баг не видно. Может надо какие-то нетривиальные настройки делать? Перерыл еще раз описания - ничего подходящего.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Bepec от Апрель 22, 2015, 12:46
Ну т.к. вы не показали картинку с виджетами, можно только гадать, причем безрезультатно.

PS скорее всего вы не учитываете какой то виджет, который не сохраняется и/или настройки лайаутов и иже с ними.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 12:59
Не... вот этот код, который выше - это код в самом виджете, в его конструкторе. Никаких других виджетов нет, он на диалоге один единственный.

То, что код в конструкторе виджета, и выполняется до привязки виджета к виджету-родителю - значения не имеет. Код выполняется идентично как до, так и после этой привязки. Проверялись все случаи.



Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 13:56
Вот же шайтан... Во-первых, несмотря на то, что pos() виджета до привязки к родительскому виджету возвращает 0,0 - saveGeometry() почему-то считает совершенно иначе, и возвращает совершенно другую координату. Можно сказать, что случайную. То есть, у pos() одни координаты, а у saveGeometry() совершенно другие. Но дальше хуже - после привязки к родителю, виджет начинает считать координату, ранее записанную в геометрии, как нулевую на родителе. И если виджет перемещается по родителю, то move(x,y) визуально нормально перемещает (за это отвечает родитель), но в самой геометрии координаты выше-левее той, что была прописана при привязке - похоже не изменяются. Вместо них остается координата, которая была во время привязки.

То есть, после привязки виджета к родительскому виджету, чтобы избежать таких глюков, надо обязательно делать move(0,0), а только потом восстанавливать его координаты с помощью restoreGeometry().

И опять же - это нигде не описано, и хрен догадаешься.

PS Не, нифига! Даже перемещение после привязки не помогает - координата на родителе, которая прошита в geometry при привязке, не изменяется.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 15:47
saveGeometry() похоже правильно работает, но restoreGeometry() похоже что нет


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Igors от Апрель 22, 2015, 15:53
Пока все не нарисовано на экране - размеры и позиция могут быть !филькина грамота", недавно было подобное


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 17:31
В данном случае от нарисованности не зависит. Тут я пристегиваю тестовый проект, в котором баг вылазит во всей своей красе. Просьба тем, кто работает на Qt новее 4.7 - проверить, что выдаст в консоль. У меня с Qt 4.7 выдаёт

Цитировать
Запускается ..........\Integrator.exe...
QPoint(0,0)
QPoint(0,68)
..........\Integrator.exe завершился с кодом 0

Особенно интересует версия 4.8 - она от 4.7 не сильно отличается, если в ней бага нет, то можно переползти на неё.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Igors от Апрель 22, 2015, 18:52
Qt 5.4 OSX, вывод
Цитировать
QPoint(0,0)
QPoint(0,22)


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 19:05
ППЦ...  :(

Причем если до вызова restoreGeometry(), вызовом move(x,y) переместить кнопку ниже 68 у меня, или ниже 22 в OSX - то вертикальная координата восстановится нормально. Впрочем 68 и 22 - это случайные числа.

Что характерно - с полными окнами, типа QDialog или QMainWindow это не проявляется, они восстанавливаются нормально, специально проверял, загоняя их в разные места десктопа.

Кто-нибудь еще на Qt 5.x в Виндах, Линухе? Для основательности багрепорта...


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Bepec от Апрель 22, 2015, 20:07
А ты добавь restoreGeometry в слот, который вызови таймером через секунду )

Что получится? :D


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 20:15
Через секунду после чего? Завершения инициализации приложения? Да тоже самое получится - у меня в реальном приложении всё это далеко после всяких инициализаций происходит с таким же результатом.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Bepec от Апрель 22, 2015, 20:34
После загрузки всех ваших конструкций и прорисовки :)


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 20:36
ДА ПОХЕРН ГДЕ!

ААА!!! Я нашел дырку! Это в Qt даже не локальная дырка - это системная дырка. Igors, ваши 22 - это высота тулбара на вашем рабочем столе, причем он у вас наверху экрана находится. Так? ;)

Они в restoreGeometry() вообще не считают, что у виджета может быть родителем другой виджет. Работает так, как будто виджет всегда лежит строго на десктопе. ЗАБЫЛИ ПРО ИЕРАРХИЮ ВИДЖЕТОВ...

Как я это нашел? Выдернул исходник restoreGeometry(), удалил там некоторый явно не нужный в моем случае код, пришил к тестовому проекту, и пошел отладчиком. И набрел на вызов, где появляется число 68:

Код:
    restoredFrameGeometry.moveTop(qMax(restoredFrameGeometry.top(), availableGeometry.top()));

- и это не в условном выполнении, а на основном уровне функции, то есть ВСЕГДА

Так вот availableGeometry.top() - это допустимая геометрия всего десктопа. В моем случае там x1 = 0, x2 = 1919, y1 = 68, y2 = 1199. Потому что 68 - это у меня ширина двойного таскбара наверху рабочего стола, МАТЬ ЕГО!!!....  >:(


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 20:48
Но самое приятное - это то, что баг легко обходится. Эта функция restoreGeometry() вообще мне не нужна. В ней более 70 строк замудренного (с использованием QDataStream) кода - сплошные проверки допустимости восстановления. И всё сводится к двум вызовам:

Код:
        move(restoredFrameGeometry.topLeft() + offset);
        resize(restoredNormalGeometry.size());

Которые я и сам сделаю для восстановления 4-х целых чисел, описывающих геометрию встроенных виджетов.

Даже не знаю - писать баг-репорт, или нет... Наверно надо, хотя есть сомнения, что будут исправлять. Наверняка начнут отнекиваться, типа того что restoreGeometry для встроенных виджетов не предназначено (в доках про это ни слова!). Хотя зря, вполне может работать.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Bepec от Апрель 22, 2015, 21:27
Ну т.к. вы не показали картинку с виджетами, можно только гадать, причем безрезультатно.

PS скорее всего вы не учитываете какой то виджет, который не сохраняется и/или настройки лайаутов и иже с ними.

На мой взгляд не баг, а фича :) Ну или ваш недосмотр :D


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 22:25
На самом деле, и то, и другое, но и ни то, ни другое. Поскольку в описании restoreGeometry() всё-таки есть слова Restores the geometry and state top-level widgets stored in the byte array geometry. Но это всё. Больше нигде ничего про то, что это только для виджетов "верхнего уровня", то есть, десктопных. Даже в развернутом описании "Restoring a Window's Geometry" не упоминается, что это не работает для дочерних виджетов. В результате - не только я этого не заметил, но также и все, кто читал эту ветку. Иначе указали бы - я в самом первом сообщении спросил, "может я чего-то пропустил?".

Если бы хотя бы было написано "Restores the geometry and state of only top-level widgets stored in the byte array geometry" - совсем другое дело. Я бы такое не пропустил.


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: m_ax от Апрель 22, 2015, 22:30

Кто-нибудь еще на Qt 5.x в Виндах, Линухе? Для основательности багрепорта...

У меня выводит
QPoint(0,0)
QPoint(0,0)

Qt 5.2.1 (linux)


Название: Re: Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 22:50

Кто-нибудь еще на Qt 5.x в Виндах, Линухе? Для основательности багрепорта...

У меня выводит
QPoint(0,0)
QPoint(0,0)

Qt 5.2.1 (linux)

У Linux менеджер десктопа иначе рабочее пространство вычисляет. Впрочем, уже не актуально, проблема решена.


Название: Re: (РЕШЕНО) Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Bepec от Апрель 22, 2015, 23:18
QPoint(0,0)
QPoint(0,0)
W7 x64 ну да написано всё у меня :D

QPoint(0,0)
QPoint(0,40)
c панелью задач вверху :)

PS в принципе логика то понятна - сохраняет геометрию по отношению к экрану)  а не положение на форме :)


Название: Re: (РЕШЕНО) Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 22, 2015, 23:44
QPoint(0,0)
QPoint(0,0)
W7 x64 ну да написано всё у меня :D

QPoint(0,0)
QPoint(0,40)
c панелью задач вверху :)

PS в принципе логика то понятна - сохраняет геометрию по отношению к экрану)  а не положение на форме :)

Да, так и должно быть для виджетов, у которых нет родителей - поэтому у меня все окна давно с этим работали. Но у виджетов, у которых есть виджеты-родители, функции move() и pos() работают уже в системе координат родителя, а не экрана. Соответственно, saveGeometry() тоже генерирует байтовый массив с координатами в системе родителя - я проверял, это именно так. Но restoreGeometry() при восстановлении на это чихает, и восстанавливает в координатах экрана. Хотя ничего не стоило бы загнать в байтовый массив geometry признак наличия родителя - и восстанавливать в его координатах, и выдавать true. Или выдавать false, если производится попытка восстановить такой виджет без привязки к родителю (но тем не менее, восстанавливать, мало ли...). И описать всё это в доке.

Представляю себе, как бы потом-потом было бы весело, если бы я сейчас разрабатывал на компьютере с тулбаром... внизу. Я бы глюк не словил, а потом на машинах с тулбаром вверху он был полез.  :(


Название: Re: (РЕШЕНО) Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Igors от Апрель 23, 2015, 08:22
Igors, ваши 22 - это высота тулбара на вашем рабочем столе, причем он у вас наверху экрана находится. Так? ;)
Почти. Это высота меню бара который на Мac всегда вверху и 1 для всех приложений

В любом случае юзать save/restore для чайлд виджетов - неудачная затея, они для этого явно не предназначены. Сохранить просто geometry() и восстановить через setGeometry(). И то по-хорошему не нужно, должны быть лайауты


Название: Re: (РЕШЕНО) Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: Гурман от Апрель 23, 2015, 16:16
В том то и дело, что недостаточно явно. Одного слова в руководстве для явности недостаточно. Теперь то да, когда посмотрел в исходник restoreGeometry() я просто geometry сохраняю.

Лэйауты в моём случае - это из пушки по воробьям. Может когда-нибудь и будет иметь смысл. Но нельзя всё делать сразу, потом будет не за что деньги брать.  ;D

Баг в том, что saveGeometry() не учитывает параметры десктопа, а restoreGeometry() учитывает. Несимметрично работают. Напишу репорт...


Название: Re: (РЕШЕНО) Какая-то хрень при saveGeometry() у QWidget на QDialog
Отправлено: PKEv от Октябрь 07, 2015, 14:31
Похоже такая же ерунда:
https://github.com/tux3/qTox/issues/2349