При расчете высоты, необходимой для QTableWidget
, чтобы все строки были видны и не добавлялась полоса прокрутки, недостаточно взять количество строк, умножить их на высоту строки и добавить высоту заголовка. Нужно добавить еще несколько пикселей, которые, похоже, зависят от используемого стиля.
Несколько лет назад я попросил решение этой самой проблемы, и подсказки, данные в соответствующем посте, работали для Qt 5: дополнительные пиксели можно вычислить, взяв высоту виджета и вычитая высоту области просмотра и высоту заголовка.
При использовании Qt 6 и Plasma 6 это больше не работает для всех стилей.
Это все еще работает для Fusion, где, например. высота виджета — 480 пикселей, высота области просмотра — 456, а заголовок — 22, в результате чего мне нужны 2 пикселя:
Но при использовании Breeze высоты другие: 480 пикселей для виджета, 450 для области просмотра и 30 для заголовка, в результате получается 0 (а нам понадобится 4 пикселя). Таким образом, при использовании Breeze я снова получаю полосы прокрутки:
Итак, вопрос тот же: как я могу надежно вычислить дополнительные пиксели, которые мне нужно добавить?
frameWidth()
действительно помогает. После добавления QTableWidget
в макет и вызова show()
(без него он не работает), можно вычислить необходимую высоту, используя widget->horizontalHeader()->height()
плюс высоту всех строк (например, widget->rowCount() * widget->rowHeight(0)
, если все строки имеют одинаковую высоту) плюс 2 * widget->frameWidth()
. Это работает для всех комбинаций Qt 5, Qt 6, Plasma 5, Plasma 5, Fusion и Breeze. Не могли бы вы опубликовать ответ, чтобы я мог его принять?
@TobiasLeupold да, опубликуйте свой ответ и примите его. Будущим читателям будет легче его найти.
Я бы хотел, чтобы @musicamante заслужил за это комплименты ;-)
@TobiasLeupold Я смогу предоставить только пример на основе Python, надеюсь, этого будет достаточно. В любом случае нет необходимости вызывать show()
, чтобы получить правильные размеры, если только вы не установили таблицу стилей для какого-либо родителя и это не повлияет на представление. В этом случае вам необходимо убедиться, что: 1. виджет правильно является родительским; 2. он полированный (ensurePolished()
).
Без show()
frameWidth()
неверно. Но я попробую ensurePolished()
.
Еще раз спасибо за подсказку, достаточно вызвать ensurePolished()
, чтобы получить правильный frameWidth()
:-)
@TobiasLeupold (пожалуйста, не забывайте использовать @username
, когда комментирует более одного пользователя, кроме вас). Дайте мне знать, если вы все равно примете ответ на основе Python.
@musicamante Ну, это вопрос C++, но, тем не менее, речь идет о вызове ensurePolished()
и использовании frameWidth()
для получения необходимых вам пикселей в дополнение к сумме всех высот строк. Так что в данном случае это на самом деле не имеет значения — вы можете даже просто ответить, упомянув эти функции, и все будет в порядке — независимо от используемого языка.
@TobiasLeupold Извините за поздний ответ. Что ж, учитывая сходство синтаксиса Python и C++ (за исключением определений, заголовков и т. д.), я уже отвечал на вопросы C++, используя код Python как форму псевдокода, но я понимаю, что это немного нарушает правила и не всех это устраивает, поэтому я обычно спрашиваю (кстати, под фразой «если вы все еще согласны» выше я имел в виду только «приемлемую форму», а не то, что вы должны принять ответ с самого начала). Я отвечу в ближайшее время.
Для классов на основе QTableView вам следует учитывать высоту их вертикального заголовка (даже если он невидим), возможную высоту горизонтального заголовка (если он виден) и поля представления.
Также обязательным является обеспечение того, чтобы виджет также был отполирован по стилю.
Прежде всего, мы почти никогда не можем полагаться на первоначальный размер виджета.
По умолчанию все стандартные виджеты Qt возвращают следующее size()
сразу после создания:
Вышеупомянутое жестко закодировано в общем исходном коде QWidget, и единственным исключением являются виджеты, которые явно устанавливают ограничение размера в своих собственных конструкторах (AFAIR, ни один стандартный виджет Qt этого не делает): например, вызов setMinimumHeight(100)
может переопределить высоту виджета, созданного без родительского элемента, или setMaximumWidth(500)
можно сделать то же самое для виджета, созданного с родительским элементом.
Тем не менее, результат виджета size()
будет учитывать вышеизложенное только после их применения.
Тем не менее, важно учитывать путь наследования виджета; в данном случае:
Это означает, что каждый уровень наследования, возможно, будет переопределять или наследовать (до определенного уровня) поведение класса, на котором он основан.
В этом конкретном случае необходимо учитывать свойство QFrame frameWidth , которое представляет собой ширину границы кадра, используемого для представления.
Однако обратите внимание, что это значение может быть ненадежным, поскольку стиль (в частности, использование QSS с переменной шириной границ) может использовать противоречивые границы.
Вышеупомянутый момент также косвенно важен: виджет необходимо доработать, чтобы получить правильную ширину рамки; QStyle виджета должен быть применен к виджету, что всегда важно: виджет может наследовать стиль или вести себя по-другому, является ли он виджетом верхнего уровня (окном) или нет. Сам стиль может по-разному «отшлифовывать» аспекты в зависимости от родителей. Некоторые внутренние значения могут быть установлены при создании и сброшены только при изменении родителя или изменения стиля, а подсказки по размеру также могут кэшироваться.
Итак, чтобы получить (возможную) правильную высоту, вам необходимо:
rowHeight()
первой строки на количество строк, и быстрее, чем перебор всех строк, поскольку заголовок вероятно, уже сделал это);frameWidth()
, но вдвое (поскольку вам нужно учитывать как верхнее, так и нижнее поля), надеясь, что стиль/QSS использует одни и те же значения для всех сторон;Обратите внимание, что более подходящим подходом должно быть выполнение вышеописанного в переопределениях представления sizeHint()
и minimumSizeHint()
, а также в соответствии с возможными изменениями макета модели и обеспечением установки правильного значения свойства sizeAdjustPolicy.
Использование размера виджета сразу после его создания бессмысленно (дочерние элементы всегда имеют размер 100x30, родительские - 640x480, если только не существуют ограничения размера, созданные с помощью функций setMinimum/Maximum/Fixed size). Используйте
horizontalHeader()->height()
плюсverticalHeader()->length()
(что возвращаетviewportSizeHint()
) и добавьте дваждыframeWidth()
. Обратите внимание: если вы используете sizeAdjustPolicy, это делается автоматически, но для обоих измерений.