Russian Qt Forum
Ноябрь 25, 2024, 07:01 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Странное ограничение размеров QML ListView в QQuickWidget  (Прочитано 10911 раз)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« : Апрель 17, 2019, 23:07 »

Нужно сделать скроллируемый декорированный список строк с чекбоксами, и обязательно внутри QGraphicsScene - чтобы легко масштабировать под разные размеры экрана в Android. Всегда всё делал на виджетах. Но QListView и QListWidget с добавленными к ним виджетами не работают в QGraphicsScene. На эту тему уже есть баг репорт. Заранее просьба - не предлагать реализовать через делегатов для QListView. Я пробовал, получается такая мешанина, что это в только самом крайнем случае. В реальной задаче в элементе списка должны быть 12 текстовых полей с разными размерами шрифтов, и два чекбокса. Количество элементов списка в реальности до 150, но размер каждого элемента должен быть 200 пикселов, чтобы все поля поместились. И должны быть три разных варианта отображения с разными расположениями и размерами текстов. На QML это сделать было бы милое дело...

Поэтому попытался сделать на QML с помощью ListView и делегата, засунув их в QQuickWidget, а его уже в QGraphicsScene. При этом в QML я как свинья в апельсинах, то есть почти никак. Сначала вроде с помощью Интернет всё получилось - и список легко декорирован, и чекбокс без проблем, и текст на строках можно расположить где угодно и разного размера. То, что мне надо. Но потом... когда увеличил количество элементов в списке, вдруг обнаружил что вместо него в окне чёрное поле с какими-то графическими искажениями. И в консоли появились сообщения об ошибке:

Цитировать
QOpenGLFramebufferObject: Framebuffer incomplete attachment.
QOpenGLFramebufferObject: Framebuffer incomplete attachment.
QOpenGLFramebufferObject: Framebuffer incomplete attachment.
QOpenGLFramebufferObject: Framebuffer incomplete attachment.
QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment.

С меньшим числом элементов списка их не было.

Экспериментально установил, что всё это начинается если вертикальный размер изображения списка превышает 4096 пикселов. До 4096 всё работает, но с 4097 уже нет. Пытаюсь найти соответствующее описание где-нибудь - ничего не нахожу. Нашёл только близкую по теме проблему у одного разработчика на stackoverflow. Больше нигде никаких упоминаний о каких-либо ограничениях.

Прикладываю здесь исходник тестового приложения, компилировал и проверял в десктопном Linux с Qt 5.9. Изначально всё работает. Но если в начале файла testlist.cpp закомментировать первую строчку с #define works - после пересборки вместо красивого скроллирующего списка в окне будет какая-то хрень. Это увеличивает вертикальный размер элемента списка с 40 пикселов до 50, весь список получается 5000 пикселов вместо 4000, и оба-на.

Кто-нибудь слышал что-нибудь об этой проблеме? Есть какие-нибудь пути её обхода?
« Последнее редактирование: Апрель 18, 2019, 20:18 от Гурман » Записан

2^7-1 == 127, задумайтесь...
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #1 : Апрель 18, 2019, 01:08 »

Qt 5.12.2, macOS 10.13.6 — никаких проблем что с works, что без.
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #2 : Апрель 18, 2019, 03:01 »

О. Вот это надо проверить с Qt 5.12. ОС тут вряд ли имеет значение. Хотя... для рендеринга используется OpenGL, могут быть нюансы.

А если число элементов задать 150, а высоту каждого 200? Это соответственно const int num в методе TestList::FillList() и число в открытой ветке #ifdef works ниже.
« Последнее редактирование: Апрель 18, 2019, 03:13 от Гурман » Записан

2^7-1 == 127, задумайтесь...
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #3 : Апрель 18, 2019, 03:24 »

в этом случае наблюдаю ту же проблему, что и у тебя. но при количестве 150 и высоте 50 проблем нет.
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #4 : Апрель 18, 2019, 09:14 »

Надо запилить багрепорт - даже пример есть !

Я решил еще раз попробовать qml т.к. может придется сделать простое приложение, но чтобы работало и на андроиде и на десктопе.
Кроме Qml решения не вижу чтобы дважды не писать
И очень мало кто использует qml по сравнению в виджетами - чтото найти сложно, а сразу много непонятно )

Например при сборке и установке на андроит qt либы всегда помещаются в apk - что тормозит и сборку и запуск, как убрать непонятно.
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #5 : Апрель 18, 2019, 11:09 »

в этом случае наблюдаю ту же проблему, что и у тебя. но при количестве 150 и высоте 50 проблем нет.
Можете установить "границу" - при каком числе вертикальных пикселов ломается? У меня при 4096, это не случайное число - 2^12. Устанавливать приходится методом ловли льва в пустыне - то есть, подбором с половинным делением. Если это тоже степень двойки, то граница будет быстро заметна.

Для этого нужно:
1. в файле testlist.cpp заменить строку:
    setResizeMode(QQuickWidget::SizeRootObjectToView);
на
    setResizeMode(QQuickWidget::SizeViewToRootObject);
2. в нём же закомментировать строки с 32 по 38 включительно
3. в файле main.qml раскомментировать строки 13 и 14
4. в строке 14 менять высоту в пикселах
« Последнее редактирование: Апрель 18, 2019, 12:03 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #6 : Апрель 18, 2019, 12:11 »

qate, в вашем сообщении по теме только замечание про баг репорт, всё остальное оффтопик. За мной не убудет, не впервой багрепорты Qt писать - надо только больше материала собрать. По поводу остального - если для Android не требуется делать скроллирующий список со сложными айтемами, которые должны собираться из разных элементов, то всё можно сделать на виджетах. И так что будет одинаково работать на всех ОС, включая Android. Правда, чтобы и выглядело одинаково, придётся все виджеты самостоятельно декорировать, то есть писать в них paintEvent() и рисовать им картинки. У меня таким способом сделано больше 20 приложений на Google Play, и да - они идентично работают в Windows и Linux. По поводу библиотек Qt - изучите Ministro. И просьба больше в этой ветке не оффтопить.
« Последнее редактирование: Апрель 18, 2019, 12:14 от Гурман » Записан

2^7-1 == 127, задумайтесь...
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #7 : Апрель 18, 2019, 12:24 »

Можете установить "границу" - при каком числе вертикальных пикселов ломается? У меня при 4096, это не случайное число - 2^12.

Возможно дело в ограничении на размер текстуры (Maximum OpenGL FrameBuffer Object size limit?). Соответственно, может не стоит устанавливать размер QQuickWidget больше этих лимитов.
Записан

Пока сам не сделаешь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #8 : Апрель 18, 2019, 12:55 »

Можете установить "границу" - при каком числе вертикальных пикселов ломается? У меня при 4096, это не случайное число - 2^12.

Возможно дело в ограничении на размер текстуры (Maximum OpenGL FrameBuffer Object size limit?). Соответственно, может не стоит устанавливать размер QQuickWidget больше этих лимитов.

Я тоже так сначала думал. Но... если в моём примере раскомментировать в файле main.qml строки, включающие использование QML типа Window (для этого надо ещё раскомментировать строку с anchors.fill parent в ListView) и выполнить шаг 1 из моего предыдущего сообщения, то это не подтверждается! Откроется отдельное окно с размерами, заданными в main.qml, и в нём будет скроллировать весь список, все 100 айтемов. Высота списка в этом случае 5000 пикселов.
Записан

2^7-1 == 127, задумайтесь...
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #9 : Апрель 18, 2019, 12:59 »

у меня предел 8192. подтвердил это, проверив максимальный размер буфера.
Код
C++ (Qt)
void TestList::showEvent(QShowEvent *e)
{
   GLint dims[2] = {0};
   glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &dims[0]);
   qDebug("%d %d", dims[0], dims[1]);
}
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #10 : Апрель 18, 2019, 14:09 »

Я тоже так сначала думал. Но... если в моём примере раскомментировать в файле main.qml строки, включающие использование QML типа Window (для этого надо ещё раскомментировать строку с anchors.fill parent в ListView) и выполнить шаг 1 из моего предыдущего сообщения, то это не подтверждается! Откроется отдельное окно с размерами, заданными в main.qml, и в нём будет скроллировать весь список, все 100 айтемов. Высота списка в этом случае 5000 пикселов.

А "QML типа Window" и QQuickWidget это одно и то же? Возможно, "QML типа Window" и имеет большие размеры, но, условно говоря, "viewport" для него гораздо меньше, и имеет ограничения по размеру framebuffer. На экране это отдельное окно реально высотой 5000 пикселей? И ошибки "QOpenGLFramebufferObject: Framebuffer incomplete attachment." при этом не появляются?
Записан

Пока сам не сделаешь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #11 : Апрель 18, 2019, 16:30 »

Я тоже так сначала думал. Но... если в моём примере раскомментировать в файле main.qml строки, включающие использование QML типа Window (для этого надо ещё раскомментировать строку с anchors.fill parent в ListView) и выполнить шаг 1 из моего предыдущего сообщения, то это не подтверждается! Откроется отдельное окно с размерами, заданными в main.qml, и в нём будет скроллировать весь список, все 100 айтемов. Высота списка в этом случае 5000 пикселов.

А "QML типа Window" и QQuickWidget это одно и то же? Возможно, "QML типа Window" и имеет большие размеры, но, условно говоря, "viewport" для него гораздо меньше, и имеет ограничения по размеру framebuffer. На экране это отдельное окно реально высотой 5000 пикселей? И ошибки "QOpenGLFramebufferObject: Framebuffer incomplete attachment." при этом не появляются?


Нет, на экране это окно с тем размером, который задан в QML Window { width: height: }. Я делал его 600х300. Но в нём скроллирует всё полотно высотой 5000 пикселов, то есть весь мой QQuickWidget. Ошибки при этом не появляются. Значит он отрендерился в OpenGL полностью. Попозже сегодня попробую проверить есть ли в этом случае лимит, сейчас некогда.
« Последнее редактирование: Апрель 18, 2019, 16:35 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #12 : Апрель 18, 2019, 18:12 »

Сейчас проверил работу QQuickWidget в окне, заданном в QML, при больших размерах списка. То есть, main.qml выглядит так:
Код:
import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Controls 2.2

//Item {
Window {
    visible: true
    width: 600
    height: 300

    ListView {
        id:lView
        //width: 600
        //height: 4096
        anchors.fill: parent
        model: DeathList
        orientation: ListView.Vertical

        delegate: Rectangle {
            color: modelData.dead ? "darkred" : "white"

            width: lView.width
            height: 50

            Text {
                id:nameField
                anchors.left: parent.left
                anchors.verticalCenter: parent.verticalCenter
                text: modelData.name
                color: modelData.dead ? "white" : "black"
                width: contentWidth
            }

            Text {
                anchors.left: nameField.right
                anchors.leftMargin: 20
                anchors.verticalCenter: parent.verticalCenter
                text: modelData.age + qsTr("years old")
                color: modelData.dead ? "white" : "black"
                width: contentWidth
            }

            CheckBox {
                text: qsTr("dead")
                anchors.right: parent.right
                anchors.top:parent.top
                anchors.bottom: parent.bottom
                checked: modelData.dead
                onCheckedChanged: modelData.dead = checked
            }
        }
    }
}

В testlist.cpp
Код:
TestList::TestList(QWidget *p, uint _width) : QQuickWidget(p), width(_width)
{
    qsrand(QTime::currentTime().second());
    connect(this, SIGNAL(statusChanged(QQuickWidget::Status)), SLOT(changedStatus(QQuickWidget::Status)));
    setResizeMode(QQuickWidget::SizeRootObjectToView); // size in code
    //setResizeMode(QQuickWidget::SizeViewToRootObject); // size in QML
    QSurfaceFormat fmt = format();
    fmt.setSwapBehavior(QSurfaceFormat::SingleBuffer);
}

void TestList::FillList()
{
    const int num = 660;
    for( int i = 0; i < num; i++ )
        notebook.append( new NoteEntry("person_"+QString::number(i), qrand()%60+20, i%2) );
    rootContext()->setContextProperty("DeathList",QVariant::fromValue(notebook));
    setSource(QUrl("qrc:/main.qml"));
    if( ! rootContext()->isValid() )
    {
        qWarning()<<"QML is not valid";
        QApplication::quit();
    }
    resize( width, num * 50 );
}

То есть, размер полотна 33000 пикселов. И нормально оно в отдельном окне скроллирует всё. Но! В консоли сообщения те же сообщения об ошибках, и добавились ещё два:
Код:
QXcbShmImage: shmget() failed (22: ???????????? ????????) for size 120252000 (911x33000)
QXcbConnection: XCB error: 11 (BadAlloc), sequence: 591, resource id: 595, major code: 53 (CreatePixmap), minor code: 0
и... главное окно приложения (не то в котором список, а то которое MainWindow) стало чёрным. Что там внутри происходит пока сложно сказать, но список рендерится при помощи QpenGL, и рендерится без ошибок.
« Последнее редактирование: Апрель 18, 2019, 18:27 от Гурман » Записан

2^7-1 == 127, задумайтесь...
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #13 : Апрель 18, 2019, 18:28 »

QQuickWindow и QQuickWidget - найдите 10 отличий Улыбающийся.
Записан

Пока сам не сделаешь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #14 : Апрель 18, 2019, 18:55 »

QQuickWindow и QQuickWidget - найдите 10 отличий Улыбающийся.
Во-первых, независимо от количества отличий, есть одно совпадение - их содержимое рендерится в OpenGL. Во-вторых, мой TestList - он не стал QQuickWindow. Он так и остался QQuickWidget.
Записан

2^7-1 == 127, задумайтесь...
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.08 секунд. Запросов: 22.