Results 1 to 20 of 21

Thread: How to shrink a QMainWindow when its central widget is shrinked

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Jan 2016
    Posts
    76
    Thanks
    28
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows Android

    Default How to shrink a QMainWindow when its central widget is shrinked

    Hi all,

    Please take a look at these files:

    List.h:

    Qt Code:
    1. #ifndef LIST_H
    2. #define LIST_H
    3.  
    4. #include <QMainWindow>
    5. #include "task.h"
    6. #include <QVector>
    7.  
    8. class QLabel;
    9.  
    10. class List : public QMainWindow
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. explicit List(QWidget *parent = nullptr);
    16. void updateStatus();
    17. ~List();
    18.  
    19. public slots:
    20. void addTask();
    21. void removeTask(Task*);
    22. void taskStatusChanged();
    23.  
    24. private:
    25. QVector<Task*> mTasks;
    26. QLabel* statusLabel;
    27. QPushButton* addTaskButtun;
    28. QHBoxLayout* hBox;
    29. QVBoxLayout* vBox;
    30. };
    31.  
    32. #endif // LIST_H
    To copy to clipboard, switch view to plain text mode 

    List.cpp:

    Qt Code:
    1. #include "list.h"
    2. #include <QPushButton>
    3. #include <QLabel>
    4. #include <QHBoxLayout>
    5. #include <QVBoxLayout>
    6. #include <QString>
    7. #include <QInputDialog>
    8. #include <QLineEdit>
    9.  
    10. List::List(QWidget *parent)
    11. : QMainWindow(parent), mTasks()
    12. {
    13. statusLabel = new QLabel(tr("Status: 0 todo / 0 done"));
    14. addTaskButtun = new QPushButton(tr("Add task"));
    15.  
    16. hBox = new QHBoxLayout;
    17. hBox->addWidget(statusLabel);
    18. hBox->addStretch();
    19. hBox->addWidget(addTaskButtun);
    20.  
    21. vBox = new QVBoxLayout;
    22. vBox->addLayout(hBox);
    23. vBox->addStretch();
    24.  
    25. QWidget *widget = new QWidget;
    26. widget->setLayout(vBox);
    27. setCentralWidget(widget);
    28.  
    29. connect(addTaskButtun, &QPushButton::clicked, this, &List::addTask);
    30. updateStatus();
    31. }
    32.  
    33. //************************************************
    34.  
    35. void List::addTask() {
    36. bool ok;
    37. QString name = QInputDialog::getText(this, tr("Add Task"), tr("Task name"),
    38. QLineEdit::Normal, tr("Untitled task"), &ok);
    39.  
    40. if(ok && !name.isEmpty()) {
    41. Task* task = new Task(name);
    42. connect(task, &Task::removed, this, &List::removeTask);
    43. connect(task, &Task::statusChanged, this, &List::taskStatusChanged);
    44. mTasks.append(task);
    45. vBox->addWidget(task);
    46. updateStatus();
    47. }
    48. }
    49.  
    50. //*********************************************
    51.  
    52. void List::removeTask(Task* task) {
    53. mTasks.removeOne(task);
    54. vBox->removeWidget(task);
    55. delete task;
    56. updateStatus();
    57. }
    58.  
    59. //**************************************
    60.  
    61. void List::taskStatusChanged() {
    62. updateStatus();
    63. }
    64.  
    65. //************************************
    66.  
    67. void List::updateStatus() {
    68. int completedCount = 0;
    69.  
    70. for(auto t: mTasks)
    71. if(t->isCompleted())
    72. completedCount++;
    73.  
    74. int todoCount = mTasks.size() - completedCount;
    75. statusLabel->setText(QString("Statuse: %1 todo / %2 completed")
    76. .arg(todoCount) .arg(completedCount));
    77. }
    78.  
    79. //*****************************
    80.  
    81. List::~List()
    82. {
    83. delete vBox;
    84. }
    To copy to clipboard, switch view to plain text mode 

    Task.h:

    Qt Code:
    1. #ifndef TASK_H
    2. #define TASK_H
    3.  
    4. #include <QWidget>
    5. #include <QString>
    6.  
    7. class QCheckBox;
    8.  
    9. class Task : public QWidget
    10. {
    11. Q_OBJECT
    12.  
    13. public:
    14. explicit Task(const QString&, QWidget* parent = nullptr);
    15.  
    16. void setName(const QString&);
    17. QString name() const;
    18. bool isCompleted() const;
    19.  
    20. ~Task();
    21.  
    22. public slots:
    23. void rename();
    24.  
    25. signals:
    26. void removed(Task*);
    27. void statusChanged(Task*);
    28.  
    29. private slots:
    30. void checked(bool);
    31.  
    32. private:
    33. QCheckBox* checkbox;
    34. QPushButton* editButton;
    35. QPushButton* removeButton;
    36. QHBoxLayout* hBox;
    37. };
    38.  
    39. #endif // TASK_H
    To copy to clipboard, switch view to plain text mode 


    Task.cpp:

    Qt Code:
    1. #include "task.h"
    2. #include "list.h"
    3. #include <QInputDialog>
    4. #include <QWidget>
    5. #include <QHBoxLayout>
    6. #include <QPushButton>
    7. #include <QCheckBox>
    8.  
    9. Task::Task(const QString& name, QWidget* parent) : QWidget (parent)
    10. {
    11. checkbox = new QCheckBox;
    12. editButton = new QPushButton(tr("Edit"));
    13. removeButton = new QPushButton(tr("Remove"));
    14.  
    15. hBox = new QHBoxLayout;
    16. hBox->addWidget(checkbox);
    17. hBox->addStretch();
    18. hBox->addWidget(editButton);
    19. hBox->addWidget(removeButton);
    20.  
    21. setLayout(hBox);
    22.  
    23. setName(name);
    24.  
    25. connect(editButton, &QPushButton::clicked, this, &Task::rename);
    26. connect(removeButton, &QPushButton::clicked, [this]()->void {
    27. emit removed(this);
    28. });
    29. connect(checkbox, &QCheckBox::toggled, this, &Task::checked);
    30. };
    31.  
    32. //*************************************
    33.  
    34. void Task::setName(const QString& name) {
    35. checkbox->setText(name);
    36. }
    37.  
    38. //********************************************
    39.  
    40. QString Task::name() const {
    41. return checkbox->text();
    42. }
    43.  
    44. //*****************************
    45.  
    46. bool Task::isCompleted() const {
    47. return checkbox->isChecked();
    48. }
    49.  
    50. //****************************************
    51.  
    52. void Task::rename() {
    53. bool ok;
    54. QString value = QInputDialog::getText(this, tr("Edit task"), tr("Task name"),
    55. QLineEdit::Normal, this->name(), &ok);
    56. if(ok && !value.isEmpty())
    57. setName(value);
    58. }
    59.  
    60. //************************************
    61.  
    62. void Task::checked(bool checked) {
    63. QFont font(checkbox->font());
    64. font.setStrikeOut(checked);
    65. checkbox->setFont(font);
    66.  
    67. emit statusChanged(this);
    68. }
    69.  
    70. //**************************************************
    71.  
    72. Task::~Task() {
    73. delete hBox;
    74. }
    To copy to clipboard, switch view to plain text mode 

    When I add tasks "untitled task 1" to "untitled task 3", image number 1 below:

    3.jpg

    then remove "untitled task 2", the frame/window doesn't shrink and the space for that task is just vacant, image number 2. I like it to decrease and fit the remained tasks, like image number 3. When a task is added, the window increases in size, so when one is removed, it should decrease in size too.

    I tested the followings one by one in void List::updateStatus() {, but none worked as expected!

    What should be used instead, please?

    Qt Code:
    1. this->sizeHint();
    2. this->update();
    3. this->resize(sizeHint());
    4. this->adjustSize();
    To copy to clipboard, switch view to plain text mode 
    Last edited by franky; 21st July 2019 at 17:25.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    I think it is because in the List constructor, you add stretch to the vbox layout. The Task widgets you add go below that, so when you remove one, the stretch just expands to fill the empty space in between the hbox and the first remaining task.

    Try not using the stretch at all. If that doesn't work, try using QBoxLayout::insertWidget() instead of addWidget() (which appends the new widget to the end of the layout, thus "trapping" the stretch between it and the start of the layout). In this case, your code would look something like this (assuming you still add the stretch during construction):

    Qt Code:
    1. vbox->insertWidget( vbox->count() - 1, task );
    To copy to clipboard, switch view to plain text mode 

    I don't know if this will solve the non-shrink problem, but at least you won't have a gap when you remove a task because the stretch will always be at the end of the layout.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. The following user says thank you to d_stranz for this useful post:

    franky (22nd July 2019)

  4. #3
    Join Date
    Jan 2016
    Posts
    76
    Thanks
    28
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Neither worked unfortunately!

    Without vBox->addStretch();, shrink won't be applied but merely we have a sparsely populated area, after removing some tasks:

    3.png

    And when I keep vBox->addStretch();, and use vBox->insertWidget(vBox->count() - 1, task); instead of vBox->addWidget(task);, we will have this, once again:

    3.png

  5. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Yes, your second screen shot is what I expected to see.

    What you will probably have to do is implement a resize() on your List window when you remove a Task. In that slot, get the size of the List window -before- removing the Task, get the size of the Task itself, remove it, then resize the List height to be the original height minus the Task height.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  6. The following user says thank you to d_stranz for this useful post:

    franky (22nd July 2019)

  7. #5
    Join Date
    Jan 2016
    Posts
    76
    Thanks
    28
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Good, thanks. There's always a way in programming!

    I added the slot in List, but I think inside it, vBox should be resized, not? (And not the central widget of QMainWindow)

  8. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    The QMainWindow is in charge of resizing its contents. I am pretty sure it asks the layout for the central widget for its size hint and adds the frame, menu bars, toolbars, status bars sizes as appropriate. So if the vbox layout never shrinks, it will return a size hint that includes the empty space.

    But try it out to resize the vbox. If it works, it works. Riht now, I don't see any method in the QVBoxLayout class (or its base classes) that allows you to directly set the size.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  9. The following user says thank you to d_stranz for this useful post:

    franky (23rd July 2019)

  10. #7
    Join Date
    Jan 2016
    Posts
    76
    Thanks
    28
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Thanks.

    I was actually much dealt with height() and width() in the List.cpp file, but these two both belong to the central widget and hence, I couldn't make the job done using them.
    How to access the height/width of the base class (QMainWindow) which is indeed in charge of the overall size, please, so that we can modify it when a remove is accomplished?

  11. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Your List class is derived from QMainWindow, isn't it? If your slots to add / remove new Task widgets are in the List class, then you can just call "height()" in those slots and you will get the height of the List widget. You then just call resize() after you compute the new height.

    You don't want to change the height using the pointer to the central widget because QMainWindow (List) and the layout won't let it happen.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  12. #9
    Join Date
    Jan 2016
    Posts
    76
    Thanks
    28
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Your List class is derived from QMainWindow, isn't it? If your slots to add / remove new Task widgets are in the List class, then you can just call "height()" in those slots and you will get the height of the List widget. You then just call resize() after you compute the new height.
    I added resize(height() - 100, width()) to removeTask, (-100, just to test):

    Qt Code:
    1. void List::removeTask(Task* task) {
    2. mTasks.removeOne(task);
    3. vBox->removeWidget(task);
    4. delete task;
    5. updateStatus();
    6.  
    7. resize(height() - 100, width());
    8. }
    To copy to clipboard, switch view to plain text mode 

    When I hover the mouse on height(), this message is shown:
    inline int QWidget::height() const , so that QWidget in our example is List, right?

    So in that slot, when we use resize via a smaller height, the widget List must resize normally, and since this slot is called each time we remove a Task, therefore List is expected to shrink that way.

    But it doesn't work as expected!

  13. #10
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    But it doesn't work as expected!
    Well, what does happen? Anything? Nothing?

    You should probably call "task->deleteLater()" instead of "delete task". You are in the middle of a slot, and control needs to return to the event loop so that Qt can clean up properly and take whatever other action is needed to redraw the UI. deleteLater() will delete the widget when the event loop runs.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  14. The following user says thank you to d_stranz for this useful post:

    franky (25th July 2019)

  15. #11
    Join Date
    Jan 2016
    Posts
    76
    Thanks
    28
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to shrink a QMainWindow when its central widget is shrinked

    Very good, thanks for the precious info. I use the function this way:

    Qt Code:
    1. void List::removeTask(Task* task) {
    2. mTasks.removeOne(task);
    3. vBox->removeWidget(task);
    4. task->deleteLater();
    5. updateStatus();
    6.  
    7. resize(height() - 100, width());
    8. }
    To copy to clipboard, switch view to plain text mode 

    After entering 5 tasks:

    3.PNG

    And then deleting the first four ones, I got this! It's actually the way I meant I doesn't work.

    4.PNG

Similar Threads

  1. Replies: 1
    Last Post: 10th August 2014, 21:06
  2. Replies: 0
    Last Post: 28th March 2013, 00:22
  3. Widget auto shrink
    By been_1990 in forum Qt Programming
    Replies: 9
    Last Post: 24th January 2013, 01:43
  4. Replies: 8
    Last Post: 28th June 2011, 14:57
  5. Central Widget of QMainWindow
    By sumsin in forum Qt Programming
    Replies: 3
    Last Post: 13th March 2006, 18:32

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.