Вычисление точной необходимой высоты для QTableWidget (обновление Qt 6)

При расчете высоты, необходимой для QTableWidget, чтобы все строки были видны и не добавлялась полоса прокрутки, недостаточно взять количество строк, умножить их на высоту строки и добавить высоту заголовка. Нужно добавить еще несколько пикселей, которые, похоже, зависят от используемого стиля.

Несколько лет назад я попросил решение этой самой проблемы, и подсказки, данные в соответствующем посте, работали для Qt 5: дополнительные пиксели можно вычислить, взяв высоту виджета и вычитая высоту области просмотра и высоту заголовка.

При использовании Qt 6 и Plasma 6 это больше не работает для всех стилей.

Это все еще работает для Fusion, где, например. высота виджета — 480 пикселей, высота области просмотра — 456, а заголовок — 22, в результате чего мне нужны 2 пикселя:

Но при использовании Breeze высоты другие: 480 пикселей для виджета, 450 для области просмотра и 30 для заголовка, в результате получается 0 (а нам понадобится 4 пикселя). Таким образом, при использовании Breeze я снова получаю полосы прокрутки:

Итак, вопрос тот же: как я могу надежно вычислить дополнительные пиксели, которые мне нужно добавить?

Использование размера виджета сразу после его создания бессмысленно (дочерние элементы всегда имеют размер 100x30, родительские - 640x480, если только не существуют ограничения размера, созданные с помощью функций setMinimum/Maximum/Fixed size). Используйте horizontalHeader()->height() плюс verticalHeader()->length() (что возвращает viewportSizeHint()) и добавьте дважды frameWidth(). Обратите внимание: если вы используете sizeAdjustPolicy, это делается автоматически, но для обоих измерений.

musicamante 09.07.2024 10:20

frameWidth() действительно помогает. После добавления QTableWidget в макет и вызова show() (без него он не работает), можно вычислить необходимую высоту, используя widget->horizontalHeader()->height() плюс высоту всех строк (например, widget->rowCount() * widget->rowHeight(0), если все строки имеют одинаковую высоту) плюс 2 * widget->frameWidth(). Это работает для всех комбинаций Qt 5, Qt 6, Plasma 5, Plasma 5, Fusion и Breeze. Не могли бы вы опубликовать ответ, чтобы я мог его принять?

Tobias Leupold 09.07.2024 13:13

@TobiasLeupold да, опубликуйте свой ответ и примите его. Будущим читателям будет легче его найти.

Pamputt 09.07.2024 15:02

Я бы хотел, чтобы @musicamante заслужил за это комплименты ;-)

Tobias Leupold 09.07.2024 15:35

@TobiasLeupold Я смогу предоставить только пример на основе Python, надеюсь, этого будет достаточно. В любом случае нет необходимости вызывать show(), чтобы получить правильные размеры, если только вы не установили таблицу стилей для какого-либо родителя и это не повлияет на представление. В этом случае вам необходимо убедиться, что: 1. виджет правильно является родительским; 2. он полированный (ensurePolished()).

musicamante 09.07.2024 20:26

Без show()frameWidth() неверно. Но я попробую ensurePolished().

Tobias Leupold 09.07.2024 20:44

Еще раз спасибо за подсказку, достаточно вызвать ensurePolished(), чтобы получить правильный frameWidth() :-)

Tobias Leupold 09.07.2024 21:06

@TobiasLeupold (пожалуйста, не забывайте использовать @username, когда комментирует более одного пользователя, кроме вас). Дайте мне знать, если вы все равно примете ответ на основе Python.

musicamante 12.07.2024 00:59

@musicamante Ну, это вопрос C++, но, тем не менее, речь идет о вызове ensurePolished() и использовании frameWidth() для получения необходимых вам пикселей в дополнение к сумме всех высот строк. Так что в данном случае это на самом деле не имеет значения — вы можете даже просто ответить, упомянув эти функции, и все будет в порядке — независимо от используемого языка.

Tobias Leupold 12.07.2024 08:31

@TobiasLeupold Извините за поздний ответ. Что ж, учитывая сходство синтаксиса Python и C++ (за исключением определений, заголовков и т. д.), я уже отвечал на вопросы C++, используя код Python как форму псевдокода, но я понимаю, что это немного нарушает правила и не всех это устраивает, поэтому я обычно спрашиваю (кстати, под фразой «если вы все еще согласны» выше я имел в виду только «приемлемую форму», а не то, что вы должны принять ответ с самого начала). Я отвечу в ближайшее время.

musicamante 18.07.2024 02:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
10
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

вр; доктор

Для классов на основе QTableView вам следует учитывать высоту их вертикального заголовка (даже если он невидим), возможную высоту горизонтального заголовка (если он виден) и поля представления.

Также обязательным является обеспечение того, чтобы виджет также был отполирован по стилю.

Объяснение

Прежде всего, мы почти никогда не можем полагаться на первоначальный размер виджета.

По умолчанию все стандартные виджеты Qt возвращают следующее size() сразу после создания:

  • 640x480 для любого виджета, созданного без родительского QWidget в его конструкторе; предполагается, что это может быть виджет верхнего уровня (окно);
  • 100x30 для любого виджета, созданного с помощью родительского QWidget в его конструкторе;

Вышеупомянутое жестко закодировано в общем исходном коде QWidget, и единственным исключением являются виджеты, которые явно устанавливают ограничение размера в своих собственных конструкторах (AFAIR, ни один стандартный виджет Qt этого не делает): например, вызов setMinimumHeight(100) может переопределить высоту виджета, созданного без родительского элемента, или setMaximumWidth(500) можно сделать то же самое для виджета, созданного с родительским элементом.
Тем не менее, результат виджета size() будет учитывать вышеизложенное только после их применения.

Тем не менее, важно учитывать путь наследования виджета; в данном случае:

  1. QTableWidget
  2. QTableView
  3. QAbstractItemView
  4. QAbstractScrollArea
  5. QFrame
  6. QВиджет
  7. QObject

Это означает, что каждый уровень наследования, возможно, будет переопределять или наследовать (до определенного уровня) поведение класса, на котором он основан.

В этом конкретном случае необходимо учитывать свойство QFrame frameWidth , которое представляет собой ширину границы кадра, используемого для представления.

Однако обратите внимание, что это значение может быть ненадежным, поскольку стиль (в частности, использование QSS с переменной шириной границ) может использовать противоречивые границы.

Вышеупомянутый момент также косвенно важен: виджет необходимо доработать, чтобы получить правильную ширину рамки; QStyle виджета должен быть применен к виджету, что всегда важно: виджет может наследовать стиль или вести себя по-другому, является ли он виджетом верхнего уровня (окном) или нет. Сам стиль может по-разному «отшлифовывать» аспекты в зависимости от родителей. Некоторые внутренние значения могут быть установлены при создании и сброшены только при изменении родителя или изменения стиля, а подсказки по размеру также могут кэшироваться.

Итак, чтобы получить (возможную) правильную высоту, вам необходимо:

  1. убедитесь, что виджет уже является частью окончательной структуры виджета (родительский элемент должен быть правильно установлен, по крайней мере, для окна верхнего уровня), чтобы стиль был точно установлен/настроен;
  2. вызовите обеспеченияПолишед(), чтобы любое возможное кэшированное значение (включая косвенные значения и подсказки по размеру) было сброшено;
  3. получить правильную высоту элементов представления, используя length() вертикального заголовка (что обычно более точно, чем просто умножение rowHeight() первой строки на количество строк, и быстрее, чем перебор всех строк, поскольку заголовок вероятно, уже сделал это);
  4. добавьте frameWidth(), но вдвое (поскольку вам нужно учитывать как верхнее, так и нижнее поля), надеясь, что стиль/QSS использует одни и те же значения для всех сторон;

Обратите внимание, что более подходящим подходом должно быть выполнение вышеописанного в переопределениях представления sizeHint() и minimumSizeHint(), а также в соответствии с возможными изменениями макета модели и обеспечением установки правильного значения свойства sizeAdjustPolicy.

Другие вопросы по теме