Widgets in Qt

The widget is the atom of the user interface: it receives mouse, keyboard and other events from the window system, and paints a representation of itself on the screen. Every widget is rectangular, and they are sorted in a Z-order. A widget is clipped by its parent and by the widgets in front of it.

A widget that is not embedded in a parent widget is called a window. Usually, windows have a frame and a title bar, although it is also possible to create windows without such decoration using suitable window flags). In Qt, QMainWindow and the various subclasses of QDialog are the most common window types.

Every widget’s constructor accepts one or two standard arguments:

  1. QWidget *parent = nullptr is the parent of the new widget. If it is nullptr (the default), the new widget will be a window. If not, it will be a child of parent, and be constrained by parent‘s geometry (unless you specify Qt::Window as window flag).
  2. Qt::WindowFlags f = { } (where available) sets the window flags; the default is suitable for almost all widgets, but to get, for example, a window without a window system frame, you must use special flags.

QWidget has many member functions, but some of them have little direct functionality; for example, QWidget has a font property, but never uses this itself. There are many subclasses which provide real functionality, such as QLabelQPushButtonQListWidget, and QTabWidget.

Top-Level and Child Widgets

A widget without a parent widget is always an independent window (top-level widget). For these widgets, setWindowTitle() and setWindowIcon() set the title bar and icon respectively.

Non-window widgets are child widgets, displayed within their parent widgets. Most widgets in Qt are mainly useful as child widgets. For example, it is possible to display a button as a top-level window, but most people prefer to put their buttons inside other widgets, such as QDialog.

A parent widget containing various child widgets.

The diagram above shows a QGroupBox widget being used to hold various child widgets in a layout provided by QGridLayout. The QLabel child widgets have been outlined to indicate their full sizes.

If you want to use a QWidget to hold child widgets you will usually want to add a layout to the parent QWidget. See Layout Management for more information.

Composite Widgets

When a widget is used as a container to group a number of child widgets, it is known as a composite widget. These can be created by constructing a widget with the required visual properties – a QFrame, for example – and adding child widgets to it, usually managed by a layout. The above diagram shows such a composite widget that was created using Qt Designer.

Composite widgets can also be created by subclassing a standard widget, such as QWidget or QFrame, and adding the necessary layout and child widgets in the constructor of the subclass. Many of the examples provided with Qt use this approach, and it is also covered in the Qt Tutorials.

Custom Widgets and Painting

Since QWidget is a subclass of QPaintDevice, subclasses can be used to display custom content that is composed using a series of painting operations with an instance of the QPainter class. This approach contrasts with the canvas-style approach used by the Graphics View Framework where items are added to a scene by the application and are rendered by the framework itself.

Each widget performs all painting operations from within its paintEvent() function. This is called whenever the widget needs to be redrawn, either as a result of some external change or when requested by the application.

Size Hints and Size Policies

When implementing a new widget, it is almost always useful to reimplement sizeHint() to provide a reasonable default size for the widget and to set the correct size policy with setSizePolicy().

By default, composite widgets which do not provide a size hint will be sized according to the space requirements of their child widgets.

The size policy lets you supply good default behavior for the layout management system, so that other widgets can contain and manage yours easily. The default size policy indicates that the size hint represents the preferred size of the widget, and this is often good enough for many widgets.

Events

Widgets respond to events that are typically caused by user actions. Qt delivers events to widgets by calling specific event handler functions with instances of QEvent subclasses containing information about each event.

If your widget only contains child widgets, you probably do not need to implement any event handlers. If you want to detect a mouse click in a child widget call the child’s underMouse() function inside the widget’s mousePressEvent().

The Scribble example implements a wider set of events to handle mouse movement, button presses, and window resizing.

You will need to supply the behavior and content for your own widgets, but here is a brief overview of the events that are relevant to QWidget, starting with the most common ones:

  • paintEvent() is called whenever the widget needs to be repainted. Every widget displaying custom content must implement it. Painting using a QPainter can only take place in a paintEvent() or a function called by a paintEvent().
  • resizeEvent() is called when the widget has been resized.
  • mousePressEvent() is called when a mouse button is pressed while the mouse cursor is inside the widget, or when the widget has grabbed the mouse using grabMouse(). Pressing the mouse without releasing it is effectively the same as calling grabMouse().
  • mouseReleaseEvent() is called when a mouse button is released. A widget receives mouse release events when it has received the corresponding mouse press event. This means that if the user presses the mouse inside your widget, then drags the mouse somewhere else before releasing the mouse button, your widget receives the release event. There is one exception: if a popup menu appears while the mouse button is held down, this popup immediately steals the mouse events.
  • mouseDoubleClickEvent() is called when the user double-clicks in the widget. If the user double-clicks, the widget receives a mouse press event, a mouse release event, (a mouse click event,) a second mouse press, this event and finally a second mouse release event. (Some mouse move events may also be received if the mouse is not held steady during this operation.) It is not possible to distinguish a click from a double-click until the second click arrives. (This is one reason why most GUI books recommend that double-clicks be an extension of single-clicks, rather than trigger a different action.)

Widgets that accept keyboard input need to reimplement a few more event handlers:

  • keyPressEvent() is called whenever a key is pressed, and again when a key has been held down long enough for it to auto-repeat. The Tab and Shift+Tab keys are only passed to the widget if they are not used by the focus-change mechanisms. To force those keys to be processed by your widget, you must reimplement QWidget::event().
  • focusInEvent() is called when the widget gains keyboard focus (assuming you have called setFocusPolicy()). Well-behaved widgets indicate that they own the keyboard focus in a clear but discreet way.
  • focusOutEvent() is called when the widget loses keyboard focus.

You may be required to also reimplement some of the less common event handlers:

  • mouseMoveEvent() is called whenever the mouse moves while a mouse button is held down. This can be useful during drag and drop operations. If you call setMouseTracking(true), you get mouse move events even when no buttons are held down. (See also the Drag and Drop guide.)
  • keyReleaseEvent() is called whenever a key is released and while it is held down (if the key is auto-repeating). In that case, the widget will receive a pair of key release and key press event for every repeat. The Tab and Shift+Tab keys are only passed to the widget if they are not used by the focus-change mechanisms. To force those keys to be processed by your widget, you must reimplement QWidget::event().
  • wheelEvent() is called whenever the user turns the mouse wheel while the widget has the focus.
  • enterEvent() is called when the mouse enters the widget’s screen space. (This excludes screen space owned by any of the widget’s children.)
  • leaveEvent() is called when the mouse leaves the widget’s screen space. If the mouse enters a child widget it will not cause a leaveEvent().
  • moveEvent() is called when the widget has been moved relative to its parent.
  • closeEvent() is called when the user closes the widget (or when close() is called).

Groups of Functions and Properties

ContextFunctions and Properties
Window functionsshow(), hide(), raise(), lower(), close().
Top-level windowswindowModifiedwindowTitlewindowIcon,
 isActiveWindowactivateWindow(), minimized,
 showMinimized(), maximizedshowMaximized(),
 fullScreenshowFullScreen(), showNormal().
Window contentsupdate(), repaint(), scroll(),setContentsMargins().
Geometryposx(), y(), rectsizewidth(), height(), move(), resize(), 
sizePolicysizeHint(), minimumSizeHint(), updateGeometry(),
 layout(), frameGeometrygeometrychildrenRect,
 childrenRegionadjustSize(), mapFromGlobal(), 
mapToGlobal(), mapFromParent(), mapToParent(), 
maximumSizeminimumSizesizeIncrementbaseSize,
 setFixedSize(),childAt(QPoint)
ModevisibleisVisibleTo(), enabledisEnabledTo(), modal,
 isWindow(), mouseTrackingupdatesEnabledvisibleRegion().
Look and feelstyle(), setStyle(), styleSheetcursorfontpalette,
 backgroundRole(), setBackgroundRole(), fontInfo(),
 fontMetrics().
Keyboard focus functionsfocusfocusPolicysetFocus(), clearFocus(), setTabOrder(), 
setFocusProxy(), focusNextChild(), focusPreviousChild().
Mouse and keyboard grabbinggrabMouse(), releaseMouse(), grabKeyboard(), 
releaseKeyboard(), mouseGrabber(), keyboardGrabber(),
grabShortcut().
Event handlersevent(), mousePressEvent(), mouseReleaseEvent(),
 mouseDoubleClickEvent(), mouseMoveEvent(),
 keyPressEvent(), keyReleaseEvent(), focusInEvent(),
 focusOutEvent(), wheelEvent(), enterEvent(), leaveEvent(),
 paintEvent(), moveEvent(), resizeEvent(), closeEvent(), 
dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(), 
dropEvent(), childEvent(), showEvent(), hideEvent(), 
customEvent(). changeEvent(),
System functionsparentWidget(), window(), setParent(), winId(), find(),
 metric().
Context menucontextMenuPolicycontextMenuEvent(),
 customContextMenuRequested(), actions()
Interactive helpsetToolTip(), setWhatsThis()

Horizontal, Vertical, Grid, and Form Layouts

The easiest way to give your widgets a good layout is to use the built-in layout managers: QHBoxLayoutQVBoxLayoutQGridLayout, QStackedLayout and QFormLayout. These classes inherit from QLayout, which in turn derives from QObject (not QWidget). They take care of geometry management for a set of widgets. To create more complex layouts, you can nest layout managers inside each other.

  • QHBoxLayout lays out widgets in a horizontal row, from left to right (or right to left for right-to-left languages).
  • QVBoxLayout lays out widgets in a vertical column, from top to bottom.
  • QGridLayout lays out widgets in a two-dimensional grid. Widgets can occupy multiple cells.
  • QFormLayout lays out widgets in a 2-column descriptive label- field style.
QWidget *window = new QWidget;
    QPushButton *button1 = new QPushButton("One");
    QPushButton *button2 = new QPushButton("Two");
    QPushButton *button3 = new QPushButton("Three");
    QPushButton *button4 = new QPushButton("Four");
    QPushButton *button5 = new QPushButton("Five");

    QHBoxLayout *layout = new QHBoxLayout;
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
    layout->addWidget(button4);
    layout->addWidget(button5);

    window->setLayout(layout);
    window->show();
QWidget *window = new QWidget;
    QPushButton *button1 = new QPushButton("One");
    QPushButton *button2 = new QPushButton("Two");
    QPushButton *button3 = new QPushButton("Three");
    QPushButton *button4 = new QPushButton("Four");
    QPushButton *button5 = new QPushButton("Five");

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 1, 0, 1, 2);
    layout->addWidget(button4, 2, 0);
    layout->addWidget(button5, 2, 1);

    window->setLayout(layout);
    window->show();
QWidget *window = new QWidget;
    QPushButton *button1 = new QPushButton("One");
    QLineEdit *lineEdit1 = new QLineEdit();
    QPushButton *button2 = new QPushButton("Two");
    QLineEdit *lineEdit2 = new QLineEdit();
    QPushButton *button3 = new QPushButton("Three");
    QLineEdit *lineEdit3 = new QLineEdit();

    QFormLayout *layout = new QFormLayout;
    layout->addRow(button1, lineEdit1);
    layout->addRow(button2, lineEdit2);
    layout->addRow(button3, lineEdit3);

    window->setLayout(layout);
    window->show();

Note: Widgets in a layout are children of the widget on which the layout is installed, not of the layout itself. Widgets can only have other widgets as parent, not layouts.

You can nest layouts using addLayout() on a layout; the inner layout then becomes a child of the layout it is inserted into.

Adding Widgets to a Layout

When you add widgets to a layout, the layout process works as follows:

  1. All the widgets will initially be allocated an amount of space in accordance with their QWidget::sizePolicy() and QWidget::sizeHint().
  2. If any of the widgets have stretch factors set, with a value greater than zero, then they are allocated space in proportion to their stretch factor (explained below).
  3. If any of the widgets have stretch factors set to zero they will only get more space if no other widgets want the space. Of these, space is allocated to widgets with an Expanding size policy first.
  4. Any widgets that are allocated less space than their minimum size (or minimum size hint if no minimum size is specified) are allocated this minimum size they require. (Widgets don’t have to have a minimum size or minimum size hint in which case the stretch factor is their determining factor.)
  5. Any widgets that are allocated more space than their maximum size are allocated the maximum size space they require. (Widgets do not have to have a maximum size in which case the stretch factor is their determining factor.)

Stretch Factors

Widgets are normally created without any stretch factor set. When they are laid out in a layout the widgets are given a share of space in accordance with their QWidget::sizePolicy() or their minimum size hint whichever is the greater. Stretch factors are used to change how much space widgets are given in proportion to one another.

If we have three widgets laid out using a QHBoxLayout with no stretch factors set we will get a layout like this:

Three widgets in a row

If we apply stretch factors to each widget, they will be laid out in proportion (but never less than their minimum size hint), e.g.

Three widgets with different stretch factors in a row

Custom Widgets in Layouts

When you make your own widget class, you should also communicate its layout properties. If the widget uses one of Qt’s layouts, this is already taken care of. If the widget does not have any child widgets, or uses a manual layout, you can change the behavior of the widget using any or all of the following mechanisms:

Call QWidget::updateGeometry() whenever the size hint, minimum size hint or size policy changes. This will cause a layout recalculation. Multiple consecutive calls to QWidget::updateGeometry() will only cause one layout recalculation.

If the preferred height of your widget depends on its actual width (e.g., a label with automatic word-breaking), set the height-for-width flag in the widget’s size policy and reimplement QWidget::heightForWidth().

Even if you implement QWidget::heightForWidth(), it is still a good idea to provide a reasonable sizeHint().

For further guidance when implementing these functions, see the Qt Quarterly article Trading Height for Width.

indexOf , itemAt , setAlignment , setContentsMargins , setSizeConstraint , setSpacing , takeAt
for boxlayout
addSpacing , addStretch , setDirection , addStrut and you can use insert instead of add to determine the index

size hint

class TObject1:public QFrame
{
    Q_OBJECT
public:
    explicit TObject1(QWidget* obj=nullptr):QFrame(obj)
    {
        this->setMouseTracking(true);// tracking cursor without press
        this->setStyleSheet("background-color: black");
        this->setMaximumSize(900,300);
    }
    void mouseMoveEvent(QMouseEvent *event) override{
        event->setAccepted(true);// don't move event to parent
    }
    QSize sizeHint() const override{//default size
        return QSize(600,200);
    }
    QSize minimumSizeHint() const override{// minimum size
        return QSize(300,100);
    }
};

QWidget w;
QVBoxLayout vb(&w);
TObject1 to1,to2;
to1.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);//fixed vertical to size hint
to2.setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed);//fixed vertical to size hint
vb.addWidget(&to1,Qt::AlignLeft);
vb.setSizeConstraint(QLayout::SetDefaultConstraint);
QSpacerItem si(100,100,QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Expanding);
vb.addSpacerItem(&si);
vb.addWidget(&to2,Qt::AlignLeft);
w.show();

size policy


QWidget w;
QVBoxLayout vb(&w);
TObject1 to1,to2;
QSizePolicy policy1(QSizePolicy::Expanding,QSizePolicy::Expanding),policy2(QSizePolicy::Expanding,QSizePolicy::Expanding);
policy1.setVerticalStretch(1);
policy2.setVerticalStretch(2);
to1.setSizePolicy(policy1);
to2.setSizePolicy(policy2);
QSpacerItem si(100,100,QSizePolicy::Policy::Fixed,QSizePolicy::Policy::Fixed);
vb.addSpacerItem(&si);
vb.addWidget(&to1);
vb.addWidget(&to2);
w.show();

Most important functions in QSizePolicy
setControlType , setRetainSizeWhenHidden , transpose

isVisibleTo


QFrame frame1,frame2(&frame1),frame3(&frame2),frame4(&frame3);
frame2.hide();
qDebug()<<frame4.isVisibleTo(&frame1);//false
qDebug()<<frame4.isVisibleTo(&frame3);//true
//window id 
QFrame frame1,frame2(&frame1),frame3(&frame2),frame4(&frame3);
qDebug()<<(frame4.window()->winId()==frame1.winId());//true
frame1.find(frame4.winId()).hide();
//widget scroll you can use QScrollArea instead
QWidget frame1;
QLabel label1(" one ",&frame1), label2(" two ",&frame1), label3(" three ",&frame1);
label1.setGeometry(50,50,100,100);
label2.setGeometry(200,50,100,100);
label3.setGeometry(350,50,100,100);
frame1.resize(200,200);
frame1.show();
frame1.scroll(-120,0);//scroll right
void mousePressEvent(QMouseEvent *event) override{
   qDebug()<<"press on it";
}
QWidget frame1;
QPushButton button1(" one ",&frame1), button2(" two ",&frame1), button3(" three ",&frame1);
TObject1 to(&frame1);
button1.setGeometry(50,50,100,100);
button2.setGeometry(200,50,100,100);
button3.setGeometry(350,50,100,100);
to.setGeometry(500,50,100,100);
to.grabMouse();//buttons never take any mouse events all events grabbed by to

note : if you want to take QPixmap for widget use grab