2015-01-29 3 views
2

Моя среда следующее:Qt: Странное поведение при вызове setGeometry на виджете QScrollArea

  • Qt 5.4, построить из источника с -platform win32-msvc2013 -opengl desktop -no-icu -skip webkit
  • Visual Studio 2013
  • Windows 7 x64

Рассмотрим следующую настройку (A QScrollArea, содержащая центрированный виджет с фиксированным размером):

QScrollArea scrollArea; 
scrollArea.setAlignment(Qt::AlignCenter); 
scrollArea.setWidgetResizable(false); 
QWidget scrollAreaWidgetContents; 
scrollArea.setWidget(scrollAreaWidgetContents); 

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

int w = 200, h = 200; 
scrollAreaWidgetContents.setGeometry(0, 0, w, h); 

И тут приходит странное поведение:
Если w и h равны текущей ширине и высоте (т.е. ничего не меняется), виджет переходит в верхний левый угол.
Если w и h отличаются от текущей ширины и высоты, виджеты остаются в центре и правильно изменяют его размер.

Я написал небольшое демонстрационное приложение, которое демонстрирует проблему. Если вы нажмете кнопку pushButton_Stay, виджеты перейдут в верхний левый угол.

#include <QtWidgets/QApplication> 
    #include <QPushButton> 
    #include <QVBoxLayout> 
    #include <QScrollArea> 

    QScrollArea *scrollArea; 
    QWidget *scrollAreaWidgetContents; 
    QPushButton *pushButton_Up; 
    QPushButton *pushButton_Down; 
    QPushButton *pushButton_Stay; 
    QVBoxLayout *layout; 

    int w = 200, h = 200; 

    void sizeUp() { 
     w += 10; 
     h += 10; 
     scrollAreaWidgetContents->setGeometry(0, 0, w, h); 
    } 

    void sizeDown() { 
     w -= 10; 
     h -= 10; 
     scrollAreaWidgetContents->setGeometry(0, 0, w, h); 
    } 

    void sizeStay() { 
     scrollAreaWidgetContents->setGeometry(0, 0, w, h); 
    } 

    int main(int argv, char **args) 
    { 
     QApplication app(argv, args); 

     // Scroll area 
     scrollArea = new QScrollArea; 
     scrollArea->setWidgetResizable(false); 
     scrollArea->setAlignment(Qt::AlignCenter); 
     scrollAreaWidgetContents = new QWidget(); 
     scrollAreaWidgetContents->setGeometry(QRect(0, 0, w, h)); 
     scrollAreaWidgetContents->setAutoFillBackground(true); 
     QPalette Pal(scrollAreaWidgetContents->palette()); 
     Pal.setColor(QPalette::Background, Qt::black); 
     scrollAreaWidgetContents->setPalette(Pal); 
     scrollArea->setWidget(scrollAreaWidgetContents); 

     // Buttons 
     pushButton_Up = new QPushButton(scrollAreaWidgetContents); 
     pushButton_Up->setGeometry(QRect(85, 50, 31, 23)); 
     pushButton_Up->setText("+"); 
     pushButton_Down = new QPushButton(scrollAreaWidgetContents); 
     pushButton_Down->setGeometry(QRect(85, 110, 31, 23)); 
     pushButton_Down->setText("-"); 
     pushButton_Stay = new QPushButton(scrollAreaWidgetContents); 
     pushButton_Stay->setGeometry(QRect(85, 80, 31, 23)); 
     pushButton_Stay->setText("0"); 
     QObject::connect(pushButton_Up, &QPushButton::clicked, sizeUp); 
     QObject::connect(pushButton_Stay, &QPushButton::clicked, sizeStay); 
     QObject::connect(pushButton_Down, &QPushButton::clicked, sizeDown); 

     // Central layout 
     layout = new QVBoxLayout; 
     layout->addWidget(scrollArea); 

     // Main window 
     QWidget window; 
     window.setGeometry(200, 200, 400, 400); 
     window.setLayout(layout); 
     window.show(); 

     return app.exec(); 
    } 

pushButton_Up Нажатие кнопки:

First picture

Нажатие на кнопку pushButton_Stay:

Second picture

Вопросы:

Что здесь не так?

Это ошибка? Если и да, может ли кто-нибудь подтвердить это?

Если это не ошибка, как я могу сделать так, чтобы виджет всегда находился в центре?

ответ

1

Что здесь случилось?

Это ошибка? Если и да, может ли кто-нибудь подтвердить это?

Кажется, второй вызов setGeometry с теми же аргументами использовать другое происхождение и координаты (0, 0) сделать виджет шаг в верхнем левом углу. Вы можете использовать другие координаты, такие как setGeometry(100, 50, w, h), чтобы увидеть разницу.

Вот source code of QWidget::setGeometry:

if (testAttribute(Qt::WA_WState_Created)) { 
    d->setGeometry_sys(r.x(), r.y(), r.width(), r.height(), true); 
    d->setDirtyOpaqueRegion(); 
} else { 
    data->crect.setTopLeft(r.topLeft()); 
    //   ^^^^^^^^^ Could be the reason why (0, 0) move to top-left 
    data->crect.setSize(r.size().boundedTo(maximumSize()).expandedTo(minimumSize())); 
    setAttribute(Qt::WA_PendingMoveEvent); 
    setAttribute(Qt::WA_PendingResizeEvent); 
} 

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


Если это не ошибка, как я могу сделать это, что виджет всегда остается по центру?

На самом деле вам не нужно звонить setGeometry, если вы только что хотите изменить размер виджета. Используйте resize вместо:

void sizeStay() { 
    scrollAreaWidgetContents->resize(w, h); 
} 

Это решает проблему в вашем случае.

+0

Вы правы. Функция изменения размера намного более уместна в этой ситуации, так как позиция автоматически определяется scrollarea в любом случае. Благодарю. – manuel

Смежные вопросы