The Qt Widgets Module
Qt Widgets provides a rich set of UI controls (widgets) for building traditional desktop and embedded GUIs. All widgets inherit from QWidget.
QObject
└── QWidget
├── QAbstractButton
│ ├── QPushButton
│ ├── QCheckBox
│ └── QRadioButton
├── QLabel
├── QLineEdit
├── QComboBox
├── QSlider
├── QSpinBox
└── QFrame
└── QAbstractScrollArea
└── QScrollArea
Core Widgets
QPushButton
#include <QPushButton>
QPushButton *btn = new QPushButton("Click Me", parent);
btn->setEnabled(true);
btn->setCheckable(true); // toggle button
connect(btn, &QPushButton::clicked, []() {
qDebug() << "Button clicked!";
});
QLabel
#include <QLabel>
QLabel *label = new QLabel("Hello Qt!", parent);
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("font-size: 18px; color: #00aaff;");
// Display an image
label->setPixmap(QPixmap(":/icons/logo.png").scaled(64, 64, Qt::KeepAspectRatio));
QLineEdit
#include <QLineEdit>
QLineEdit *edit = new QLineEdit(parent);
edit->setPlaceholderText("Enter value...");
edit->setMaxLength(20);
edit->setEchoMode(QLineEdit::Password); // for passwords
connect(edit, &QLineEdit::textChanged, [](const QString &text) {
qDebug() << "Text:" << text;
});
QComboBox
#include <QComboBox>
QComboBox *combo = new QComboBox(parent);
combo->addItems({"Option A", "Option B", "Option C"});
combo->setCurrentIndex(0);
connect(combo, &QComboBox::currentTextChanged, [](const QString &text) {
qDebug() << "Selected:" << text;
});
QSlider & QSpinBox
#include <QSlider>
#include <QSpinBox>
QSlider *slider = new QSlider(Qt::Horizontal, parent);
slider->setRange(0, 100);
slider->setValue(50);
QSpinBox *spin = new QSpinBox(parent);
spin->setRange(0, 100);
// Link them
connect(slider, &QSlider::valueChanged, spin, &QSpinBox::setValue);
connect(spin, &QSpinBox::valueChanged, slider, &QSlider::setValue);
Layouts
Layouts manage widget size and position automatically — essential for responsive UIs.
QVBoxLayout / QHBoxLayout
#include <QVBoxLayout>
#include <QHBoxLayout>
QWidget *window = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout(window);
QLabel *title = new QLabel("Temperature Monitor");
mainLayout->addWidget(title);
QHBoxLayout *row = new QHBoxLayout;
row->addWidget(new QLabel("Value:"));
row->addWidget(new QSpinBox);
mainLayout->addLayout(row);
QPushButton *btn = new QPushButton("Read");
mainLayout->addWidget(btn);
mainLayout->addStretch(); // push everything to the top
QGridLayout
#include <QGridLayout>
QGridLayout *grid = new QGridLayout(window);
// addWidget(widget, row, col, rowSpan, colSpan)
grid->addWidget(new QLabel("Name:"), 0, 0);
grid->addWidget(new QLineEdit, 0, 1, 1, 2);
grid->addWidget(new QLabel("Port:"), 1, 0);
grid->addWidget(new QSpinBox, 1, 1);
grid->addWidget(new QPushButton("OK"), 2, 2);
QMainWindow
QMainWindow provides a standard application layout with menu bar, toolbars, status bar, and a central widget:
// mainwindow.h
#include <QMainWindow>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
private slots:
void onFileOpen();
void onAbout();
private:
void setupMenuBar();
void setupStatusBar();
};
// mainwindow.cpp
#include "mainwindow.h"
#include <QMenuBar>
#include <QStatusBar>
#include <QLabel>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
setWindowTitle("EmbeddexAI Monitor");
resize(800, 600);
// Central widget
QLabel *central = new QLabel("Central Area", this);
central->setAlignment(Qt::AlignCenter);
setCentralWidget(central);
setupMenuBar();
statusBar()->showMessage("Ready");
}
void MainWindow::setupMenuBar() {
QMenu *fileMenu = menuBar()->addMenu("&File");
fileMenu->addAction("&Open", this, &MainWindow::onFileOpen);
fileMenu->addSeparator();
fileMenu->addAction("&Quit", qApp, &QCoreApplication::quit);
QMenu *helpMenu = menuBar()->addMenu("&Help");
helpMenu->addAction("&About", this, &MainWindow::onAbout);
}
void MainWindow::onFileOpen() {
statusBar()->showMessage("Opening file...");
}
void MainWindow::onAbout() {
QMessageBox::about(this, "About", "EmbeddexAI Qt Tutorial\nVersion 1.0");
}
Dialogs
#include <QDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
// File open dialog
QString file = QFileDialog::getOpenFileName(
this, "Open File", "/home", "Config Files (*.cfg *.ini)");
// Message box
QMessageBox::warning(this, "Warning", "Device not connected!");
int ret = QMessageBox::question(this, "Confirm", "Flash firmware?",
QMessageBox::Yes | QMessageBox::No);
if (ret == QMessageBox::Yes) { /* flash */ }
// Input dialog
bool ok;
QString text = QInputDialog::getText(this, "IP Address", "Enter IP:",
QLineEdit::Normal, "192.168.1.1", &ok);
Stylesheet (QSS)
Style Qt widgets with CSS-like syntax:
qApp->setStyleSheet(R"(
QWidget {
background-color: #1e1e2e;
color: #cdd6f4;
font-family: 'Fira Code', monospace;
font-size: 13px;
}
QPushButton {
background-color: #313244;
border: 1px solid #45475a;
border-radius: 6px;
padding: 6px 16px;
}
QPushButton:hover {
background-color: #585b70;
}
QPushButton:pressed {
background-color: #89b4fa;
color: #1e1e2e;
}
)");
Summary
| Widget | Use Case |
|---|---|
QPushButton | Trigger actions |
QLabel | Display text or images |
QLineEdit | Single-line text input |
QComboBox | Drop-down selection |
QSlider / QSpinBox | Numeric input |
QVBoxLayout / QHBoxLayout | Stack widgets vertically / horizontally |
QGridLayout | Grid-based positioning |
QMainWindow | Full app with menus and status bar |
Advanced Widgets
QTableWidget — Spreadsheet-Style Data
#include <QTableWidget>
QTableWidget *table = new QTableWidget(4, 3, this);
table->setHorizontalHeaderLabels({"Sensor", "Value", "Unit"});
// Populate
QStringList sensors = {"Temp", "Humidity", "Pressure", "Voltage"};
QStringList values = {"36.5", "60.2", "1013.25", "3.30"};
QStringList units = {"°C", "%RH", "hPa", "V"};
for (int row = 0; row < 4; ++row) {
table->setItem(row, 0, new QTableWidgetItem(sensors[row]));
table->setItem(row, 1, new QTableWidgetItem(values[row]));
table->setItem(row, 2, new QTableWidgetItem(units[row]));
}
table->resizeColumnsToContents();
QTabWidget — Tabbed Interface
#include <QTabWidget>
QTabWidget *tabs = new QTabWidget(this);
tabs->addTab(new ConfigPanel, QIcon(":/icons/settings.svg"), "Settings");
tabs->addTab(new MonitorPanel, QIcon(":/icons/monitor.svg"), "Monitor");
tabs->addTab(new LogPanel, QIcon(":/icons/log.svg"), "Log");
connect(tabs, &QTabWidget::currentChanged, [](int idx) {
qDebug() << "Switched to tab" << idx;
});
QSplitter — Resizable Panes
#include <QSplitter>
QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
splitter->addWidget(new QListView);
splitter->addWidget(new QTextEdit);
splitter->setSizes({250, 600}); // initial sizes in pixels
QStackedWidget — Page Switching
#include <QStackedWidget>
QStackedWidget *stack = new QStackedWidget(this);
stack->addWidget(new LoginPage); // index 0
stack->addWidget(new DashboardPage);// index 1
stack->addWidget(new SettingsPage); // index 2
// Switch pages
stack->setCurrentIndex(1); // show Dashboard
QProgressBar
#include <QProgressBar>
QProgressBar *bar = new QProgressBar(this);
bar->setRange(0, 100);
bar->setValue(0);
bar->setFormat("Flashing: %p%");
bar->setTextVisible(true);
// Indeterminate (busy)
bar->setRange(0, 0); // spinning bar
Visual: Layout Reference
┌──────────────────────────────────────────┐
│ QMainWindow │
│ ┌────────────────────────────────────┐ │
│ │ Menu Bar │ │
│ ├────────────────────────────────────┤ │
│ │ Tool Bar │ │
│ ├──────────────┬─────────────────────┤ │
│ │ │ │ │
│ │ QDockWidget │ Central Widget │ │
│ │ (sidebar) │ QStackedWidget │ │
│ │ │ │ │
│ ├──────────────┴─────────────────────┤ │
│ │ Status Bar │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Lab 1 — Device Config Form
// configform.h
class ConfigForm : public QWidget {
Q_OBJECT
public:
ConfigForm(QWidget *parent = nullptr) : QWidget(parent) {
auto *form = new QFormLayout(this);
m_portEdit = new QLineEdit("/dev/ttyUSB0");
m_baudBox = new QComboBox;
m_baudBox->addItems({"9600","19200","38400","115200"});
m_baudBox->setCurrentText("115200");
m_parityBox = new QComboBox;
m_parityBox->addItems({"None","Even","Odd"});
m_connectBtn = new QPushButton("Connect");
form->addRow("Port:", m_portEdit);
form->addRow("Baud:", m_baudBox);
form->addRow("Parity:", m_parityBox);
form->addRow(m_connectBtn);
connect(m_connectBtn, &QPushButton::clicked, this, &ConfigForm::onConnect);
}
signals:
void connectRequested(const QString &port, int baud);
private slots:
void onConnect() {
emit connectRequested(m_portEdit->text(),
m_baudBox->currentText().toInt());
}
private:
QLineEdit *m_portEdit;
QComboBox *m_baudBox;
QComboBox *m_parityBox;
QPushButton *m_connectBtn;
};
Lab 2 — Sensor Dashboard
class SensorDashboard : public QWidget {
Q_OBJECT
public:
SensorDashboard(QWidget *p = nullptr) : QWidget(p) {
auto *grid = new QGridLayout(this);
// Add sensor cards (label + progressbar)
addCard(grid, "Temperature", 0, 0, 100, "°C");
addCard(grid, "Humidity", 1, 0, 100, "%");
addCard(grid, "Pressure", 2, 900, 1100, "hPa");
}
void updateSensor(const QString &name, int value) {
if (m_bars.contains(name)) {
m_bars[name]->setValue(value);
m_labels[name]->setText(
QString("%1: %2").arg(name).arg(value));
}
}
private:
void addCard(QGridLayout *g, const QString &name,
int row, int min, int max, const QString &unit)
{
auto *label = new QLabel(name + ": --");
auto *bar = new QProgressBar;
bar->setRange(min, max);
bar->setFormat(QString("%p% (%v " + unit + ")"));
g->addWidget(label, row, 0);
g->addWidget(bar, row, 1);
m_labels[name] = label;
m_bars[name] = bar;
}
QHash<QString, QLabel*> m_labels;
QHash<QString, QProgressBar*> m_bars;
};
Interview Questions
Q1: What is the difference between a widget and a layout?
A widget is a visual element that can be displayed (button, label). A layout manages the position and size of child widgets within a parent widget. Layouts resize widgets automatically when the window is resized.
Q2: Why use QMainWindow instead of QWidget as the main window?
QMainWindowprovides a built-in menu bar, toolbars, dock widgets, and a status bar — features needed by most real applications. For simple dialogs or sub-panels,QWidgetis sufficient.
Q3: What happens to heap-allocated child widgets when the parent is destroyed?
Qt’s parent-child system ensures the parent deletes all heap-allocated children. You don’t need to
deletechild widgets manually if you set a parent.
Q4: How do you make a widget expand to fill available space?
Set a
QSizePolicywithExpandingor usesetMinimumSize/setMaximumSize. In layouts, calllayout->setStretchFactor(widget, 1)to give that widget more space.
Q5: What is QSS and where does it apply?
Qt Style Sheets (QSS) — a CSS subset for styling Qt widgets. Apply to the whole app (
qApp->setStyleSheet(...)), a window, or individual widgets. Supports selectors, pseudo-states (:hover,:pressed), and box model properties.
Application: Embedded Device Monitor
// monitor.h
class DeviceMonitor : public QMainWindow {
Q_OBJECT
public:
DeviceMonitor(QWidget *p = nullptr) : QMainWindow(p) {
setWindowTitle("Device Monitor v1.0");
resize(900, 600);
// Central splitter
auto *split = new QSplitter(Qt::Horizontal, this);
setCentralWidget(split);
// Left: device list
m_deviceList = new QListWidget;
m_deviceList->addItem("UART-0");
m_deviceList->addItem("SPI-1");
m_deviceList->addItem("I2C-2");
split->addWidget(m_deviceList);
// Right: tabs
auto *tabs = new QTabWidget;
tabs->addTab(buildStatusTab(), "Status");
tabs->addTab(buildLogTab(), "Log");
split->addWidget(tabs);
split->setSizes({200, 700});
// Status bar
m_statusBar = new QStatusBar;
setStatusBar(m_statusBar);
m_statusBar->showMessage("Ready");
// Timer: simulate readings
auto *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &DeviceMonitor::updateReadings);
timer->start(1000);
}
private slots:
void updateReadings() {
m_tempBar->setValue(20 + rand() % 40);
m_voltBar->setValue(28 + rand() % 10);
m_log->append(QDateTime::currentDateTime().toString("hh:mm:ss")
+ " Reading updated");
}
private:
QWidget *buildStatusTab() {
auto *w = new QWidget;
auto *form = new QFormLayout(w);
m_tempBar = new QProgressBar; m_tempBar->setRange(0, 80);
m_voltBar = new QProgressBar; m_voltBar->setRange(0, 50);
form->addRow("Temperature (°C):", m_tempBar);
form->addRow("Voltage (0.1V):", m_voltBar);
return w;
}
QWidget *buildLogTab() {
auto *w = new QWidget;
auto *lay = new QVBoxLayout(w);
m_log = new QTextEdit;
m_log->setReadOnly(true);
m_log->setFont(QFont("Courier", 10));
lay->addWidget(m_log);
return w;
}
QListWidget *m_deviceList;
QProgressBar *m_tempBar;
QProgressBar *m_voltBar;
QTextEdit *m_log;
QStatusBar *m_statusBar;
};
References
| Resource | Link |
|---|---|
| Qt Docs: Widget Classes | https://doc.qt.io/qt-6/qtwidgets-module.html |
| Qt Docs: Layout Management | https://doc.qt.io/qt-6/layout.html |
| Qt Docs: QMainWindow | https://doc.qt.io/qt-6/qmainwindow.html |
| Qt Docs: Style Sheets | https://doc.qt.io/qt-6/stylesheet.html |
Next tutorial → Qt Object Model & QObject