I came across an article discussing this layout implementation, but the code was missing many components and could not run. It seems to be an AI-generated article, primarily emphasizing hands-on skills. Therefore, I borrowed the coding ideas and some code from that article to create a small demo that is functional and has all the source code open-sourced. Feel free to download and run it if you’re interested.Code repository:https://gitee.com/codeceo_net/qttest/tree/TopLeftMain/First, let’s take a look at the effect:
The layout consists of a top menu, a left menu, and a right area that loads different interfaces based on the selected menu item. Now, I will briefly list some of the code; the rest can be understood by downloading the source code and running it.imodule.h
#ifndef IMODULE_H
#define IMODULE_H
#include <QString>
#include <QIcon>
#include <QAction>
#include <QWidget>
/// Module class
class IModule {
public:
IModule();
// This function must be implemented by subclasses; the base class cannot be instantiated directly.
virtual ~IModule() = default;
virtual QString moduleName() const = 0; // Module name
virtual QIcon moduleIcon() const = 0; // Module icon
virtual QAction* moduleAction() const = 0; // Corresponding action for the module
virtual QWidget* moduleWidget() const = 0; // Corresponding main window for the module
};
#endif // IMODULE_H
This class represents the entity of the left menu. When we create a new menu, we assign this menu its layout and some related properties.
LeftMenu.h
#ifndef LEFTMENU_H
#define LEFTMENU_H
#include <QListWidget>
#include "imodule.h"
/// Left menu class
class LeftMenu: public QListWidget {
Q_OBJECT
public:
explicit LeftMenu(QWidget* parent = nullptr);
void addModuleItem(IModule* module); // Add module
void setCurrentModule(IModule* module); // Set current module
signals:
void moduleChanged(IModule* module); // Module switch signal
private:
QMap<QListWidgetItem*, IModule*> m_itemModuleMap; // Mapping of menu items to modules
};
#endif // LEFTMENU_H
leftmenu.cpp
#include "leftmenu.h"
/// Left navigation
LeftMenu::LeftMenu(QWidget* parent): QListWidget(parent) {
setFixedWidth(200); // Default width of the left menu
setMinimumWidth(200);
setMaximumWidth(200);
setStyleSheet(R"(
QListWidget { border: none; background: #f8f9fa; }
QListWidget::item { height: 40px; padding-left: 15px; background: #ffffff; color: #000000; }
QListWidget::item:selected { background: #e9ecef; color: #2c3e50; }
)");
// Signal-slot connection
connect(this, &QListWidget::itemClicked, this, [this](QListWidgetItem* item) {
emit moduleChanged(m_itemModuleMap.value(item));
});
}
// Add module
void LeftMenu::addModuleItem(IModule* module) {
if (!module) return;
QListWidgetItem* item = new QListWidgetItem(module->moduleIcon(), module->moduleName());
m_itemModuleMap[item] = module;
addItem(item);
}
// Select current module
void LeftMenu::setCurrentModule(IModule* module) {
for (auto it = m_itemModuleMap.constBegin(); it != m_itemModuleMap.constEnd(); ++it) {
if (it.value() == module) {
setCurrentItem(it.key());
break;
}
}
}
This is the layout class for the left menu, mainly implementing the addition of menus, highlighting the currently selected menu item, and listening to signal-slot connections.
moduleManager.h
#ifndef MODULEMANAGER_H
#define MODULEMANAGER_H
#include <QObject>
#include <mainwindow.h>
#include <imodule.h>
////// rief The ModuleManager class
/// Module management class
class ModuleManager: public QObject {
Q_OBJECT
public:
explicit ModuleManager(MainWindow* mainWindow, QObject* parent = nullptr);
void registerModule(IModule* module); // Register module
IModule* getModule(const QString& moduleName) const { return m_modules.value(moduleName, nullptr); } // Get module
// Get list
QList<IModule*> getAllModules() const { return m_modules.values(); }
// Check existence
bool hasModule(const QString& name) const {
return m_modules.contains(name);
}
private:
MainWindow* m_mainWindow = nullptr; // Main window
QMap<QString, IModule*> m_modules; // Mapping from module name to module
};
#endif // MODULEMANAGER_H
moduleManager.cpp
#include "modulemanager.h"
ModuleManager::ModuleManager(MainWindow* mainWindow, QObject* parent)
: QObject(parent), m_mainWindow(mainWindow) {}
void ModuleManager::registerModule(IModule* module) {
if (!module || m_modules.contains(module->moduleName())) return;
m_modules.insert(module->moduleName(), module);
// Add menu item to the left menu. How to get it?
m_mainWindow->getLeftMenu()->addModuleItem(module);
}
This class mainly acts as middleware to manage tools for adding menus to the menu.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <imodule.h>
#include <QStackedWidget>
#include <QSplitter>
#include <QHBoxLayout>
#include <top.h>
#include <leftmenu.h>
// #include <modulemanager.h>
// QT_BEGIN_NAMESPACE
// namespace Ui {
// class MainWindow;
// }
// QT_END_NAMESPACE
// Declaration to avoid multiple inclusions
class Top;
class LeftMenu;
class ModuleManager;
/// Main interface class
class MainWindow : public QMainWindow {
Q_OBJECT
public:
// explicit is a keyword in C++ that prevents the constructor or type conversion operator from being implicitly called, avoiding unexpected implicit type conversions.
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
// Module management interface
void registerModule(IModule* module); // Register module
void switchModule(const QString& moduleName); // Switch module
void initCentralLayout();
void initStatusBar();
void registerDemoModules();
LeftMenu* getLeftMenu() const { return m_leftMenu; } // Get left menu
protected:
void resizeEvent(QResizeEvent* event) override; // Window resize event
private:
// Core components
Top* m_topBar = nullptr; // Top navigation bar
LeftMenu* m_leftMenu = nullptr; // Left navigation menu
QStackedWidget* m_contentStack = nullptr; // Main content area (stacked window)
ModuleManager* m_moduleManager = nullptr; // Module manager
// Layout related
QWidget* m_centralContainer = nullptr; // Central container (wraps left menu + main content area)
QHBoxLayout* m_centralLayout = nullptr; // Central container layout
QSplitter* m_mainSplitter = nullptr; // Main splitter (left menu and main content area)
// private:
// Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
// #include "ui_mainwindow.h"
#include <mainwindow.h>
#include <top.h>
#include <leftmenu.h>
#include <top.h>
#include <modulemanager.h>
#include <QStatusBar>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent),
m_topBar(new Top()),
m_leftMenu(new LeftMenu()),
m_contentStack(new QStackedWidget()),
m_moduleManager(new ModuleManager(this)) {
// Basic window settings
setWindowTitle("General Interface Framework");
resize(1200, 800);
// Initialize core layout
initCentralLayout();
initStatusBar();
// Register demo modules (dynamically loaded in actual development)
registerDemoModules();
// Connect signals in m_leftMenu
// Signal-slot connection
connect(m_leftMenu, &LeftMenu::moduleChanged, this, [this](IModule* module) {
qDebug() << "Module clicked:" << module->moduleName();
//m_contentStack->setCurrentWidget(module->moduleWidget());
switchModule(module->moduleName());
});
}
MainWindow::~MainWindow() {}
void MainWindow::registerModule(IModule* module) {
m_moduleManager->registerModule(module);
}
void MainWindow::switchModule(const QString& moduleName) {
if (m_moduleManager->hasModule(moduleName)) { // Should actually get the module from m_moduleManager
m_leftMenu->setCurrentModule(m_moduleManager->getModule(moduleName)); // Need to supplement the module retrieval interface
auto widget = m_moduleManager->getModule(moduleName)->moduleWidget();
if (!widget) {
qDebug() << "moduleWidget() is null!";
} else {
qDebug() << "moduleWidget() exists:" << widget;
}
// If not yet added to stack, add it first
if (m_contentStack->indexOf(widget) == -1) {
m_contentStack->addWidget(widget);
}
m_contentStack->setCurrentWidget(widget);
}
}
void MainWindow::resizeEvent(QResizeEvent* event) {
QMainWindow::resizeEvent(event);
qDebug() << "resizeEvent";
}
void MainWindow::initCentralLayout() {
// Central container (wraps left menu + main content area)
m_centralContainer = new QWidget();
setCentralWidget(m_centralContainer);
// Main layout (horizontal arrangement: left menu + main content area)
m_centralLayout = new QHBoxLayout(m_centralContainer);
m_centralLayout->setContentsMargins(0, 0, 0, 0);
m_centralLayout->setSpacing(0);
// Insert top layout
m_centralLayout->setMenuBar(m_topBar);
// Main splitter (supports drag to adjust left menu width)
m_mainSplitter = new QSplitter(Qt::Horizontal);
m_mainSplitter->addWidget(m_leftMenu);
m_mainSplitter->addWidget(m_contentStack);
// Prevent left side from collapsing completely
//m_mainSplitter->setCollapsible(0, false); // The 0th widget (left menu) cannot collapse
// Set initial size
//m_mainSplitter->setSizes({100});
// Set stretch policy
//m_mainSplitter->setStretchFactor(0, 0); // Left side (not stretched)
//m_mainSplitter->setStretchFactor(1, 1); // Right side (mainly stretched)
m_centralLayout->addWidget(m_mainSplitter);
}
void MainWindow::initStatusBar() {
QStatusBar* statusBar = this->statusBar();
statusBar->setStyleSheet("QStatusBar{padding: 4px; background: #ffffff;}");
statusBar->showMessage("Ready");
}
// Register modules
void MainWindow::registerDemoModules() {
// Demo module 1: Home
class HomeModule : public IModule {
private:
QAction* m_action;
public:
HomeModule() {
m_action = new QAction(moduleIcon(), moduleName());
m_action->setShortcut(QKeySequence("Ctrl+1"));
}
QString moduleName() const override { return "Home"; }
QIcon moduleIcon() const override { return QIcon(":/icons/home.png"); }
QAction* moduleAction() const override {
return m_action;
}
QWidget* moduleWidget() const override {
QWidget* widget = new QWidget();
QVBoxLayout* layout = new QVBoxLayout(widget);
QLabel* qLabel = new QLabel("<h2>Welcome to the system</h2><p>This is the home content area</p>");
// Color
qLabel->setStyleSheet("QLabel { color: #34495e; }");
// Font size
QFont font = qLabel->font();
font.setPointSize(14);
qLabel->setFont(font);
layout->addWidget(qLabel);
return widget;
}
};
registerModule(new HomeModule());
// Demo module 2: Data Statistics
class StatsModule : public IModule {
private:
QAction* m_action;
public:
StatsModule() {
m_action = new QAction(moduleIcon(), moduleName());
m_action->setShortcut(QKeySequence("Ctrl+2"));
}
QString moduleName() const override { return "Data Statistics"; }
QIcon moduleIcon() const override {
return QIcon(":/icons/stat.png");
}
QAction* moduleAction() const override {
return m_action;
}
QWidget* moduleWidget() const override {
QWidget* widget = new QWidget();
QVBoxLayout* layout = new QVBoxLayout(widget);
QLabel* qLabel = new QLabel("<h2>Welcome to the system</h2><p>System data statistics</p>");
// Color
qLabel->setStyleSheet("QLabel { color: #34495e; }");
// Font size
QFont font = qLabel->font();
font.setPointSize(14);
qLabel->setFont(font);
layout->addWidget(qLabel);
return widget;
}
};
registerModule(new StatsModule());
// Default display home
switchModule("Home");
}
Next is the main interface, registering menus, adding layouts, connecting information slots, and other functionalities.
Finally, the entry function main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QStyleFactory>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// Global style settings (optional)
app.setStyle(QStyleFactory::create("Fusion"));
QPalette palette;
palette.setColor(QPalette::Window, QColor(240, 240, 240));
app.setPalette(palette);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
Okay, enough talk, just download the source code and experiment!
▼Follow me for more basic programming knowledge ▼

👆🏻👆🏻👆🏻Scan to follow👆🏻👆🏻👆🏻
▼Click “
” to like, it motivates me to keep updating ▼
Blog address: blog.codeceo.net
Reference article: General Interface Layout Framework Scheme in Qt C++