Skip to content

feat: Implement Qt GUI for Medical Robot Control#1

Open
gucunlin wants to merge 1 commit into
masterfrom
feature/medical-robot-gui
Open

feat: Implement Qt GUI for Medical Robot Control#1
gucunlin wants to merge 1 commit into
masterfrom
feature/medical-robot-gui

Conversation

@gucunlin
Copy link
Copy Markdown
Owner

@gucunlin gucunlin commented Jun 6, 2025

This commit introduces a Qt 5.15 application, "MedicalRobotGUI," designed as a launcher for your modular surgical robot system.

Key Features:

  • User Interface:
    • Modern medical technology theme with a mint green color palette.
    • Main window title: "野战模组化人机协同手术机器人系统".
    • Two primary action buttons styled as semi-transparent cards:
      • "颅内血肿穿刺减压机器人模组"
      • "介入止血手术机器人模组"
    • Styling applied using Qt StyleSheets (QSS) for background gradients,
      button appearance (rounded corners, transparency, hover effects),
      and title text.
  • Functionality:
    • Each button launches an external executable.
    • Executable paths are configurable via a config.ini file located
      in the application's directory.
    • QSettings is used for reading the configuration.
    • QProcess::startDetached() is used to launch external processes
      asynchronously.
  • Error Handling:
    • Displays warnings/errors using QMessageBox if config.ini is
      missing, paths are not configured, or if a process fails to launch.
  • Project Structure:
    • Includes .pro file, main.cpp, mainwindow.h, mainwindow.cpp.
    • Placeholder config.ini and .bat files are included for testing.

The application provides a styled and functional interface for you to access different modules of the surgical robot system.

好的,这是翻译成中文的pull request总结:

Sourcery 总结

引入 MedicalRobotGUI Qt 应用程序,为模块化手术机器人模块提供一个样式化的启动器。

新功能:

  • 添加 Qt 5.15 应用程序,其主窗口具有主题 UI 和两个模块启动按钮。

增强功能:

  • 应用薄荷绿渐变主题和 QSS 样式,用于窗口、标题标签和按钮。
  • 使用 QSettings 从 config.ini 加载可执行文件路径,并在缺少配置时显示警告。
  • 使用 QProcess::startDetached 异步启动外部可执行文件,并在失败时显示错误对话框。

构建:

  • 添加 MedicalRobotGUI.pro 项目文件、main.cpp、mainwindow.h/.cpp、config.ini 模板和用于测试的占位符批处理脚本。
Original summary in English

Summary by Sourcery

Introduce the MedicalRobotGUI Qt application to provide a styled launcher for modular surgical robot modules.

New Features:

  • Add Qt 5.15 application with a main window featuring themed UI and two module-launch buttons.

Enhancements:

  • Apply mint green gradient theme and QSS styling for window, title label, and buttons.
  • Load executable paths from a config.ini using QSettings and display warnings on missing configuration.
  • Use QProcess::startDetached to launch external executables asynchronously with error dialogs on failure.

Build:

  • Add MedicalRobotGUI.pro project file, main.cpp, mainwindow.h/.cpp, config.ini template, and placeholder batch scripts for testing.

This commit introduces a Qt 5.15 application, "MedicalRobotGUI," designed
as a launcher for your modular surgical robot system.

Key Features:
-   **User Interface:**
    -   Modern medical technology theme with a mint green color palette.
    -   Main window title: "野战模组化人机协同手术机器人系统".
    -   Two primary action buttons styled as semi-transparent cards:
        -   "颅内血肿穿刺减压机器人模组"
        -   "介入止血手术机器人模组"
    -   Styling applied using Qt StyleSheets (QSS) for background gradients,
        button appearance (rounded corners, transparency, hover effects),
        and title text.
-   **Functionality:**
    -   Each button launches an external executable.
    -   Executable paths are configurable via a `config.ini` file located
        in the application's directory.
    -   `QSettings` is used for reading the configuration.
    -   `QProcess::startDetached()` is used to launch external processes
        asynchronously.
-   **Error Handling:**
    -   Displays warnings/errors using `QMessageBox` if `config.ini` is
        missing, paths are not configured, or if a process fails to launch.
-   **Project Structure:**
    -   Includes `.pro` file, `main.cpp`, `mainwindow.h`, `mainwindow.cpp`.
    -   Placeholder `config.ini` and `.bat` files are included for testing.

The application provides a styled and functional interface for you to
access different modules of the surgical robot system.
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Jun 6, 2025

## 审查者指南

实现了一个 Qt5 启动器应用程序,该程序构建了一个带有标题和两个模块按钮的样式化主窗口,通过 QSettings 从 config.ini 读取外部可执行文件路径,并使用 QProcess::startDetached 异步启动每个模块,并使用基于 QMessageBox 的错误处理;还添加了项目元数据和占位符脚本。

#### 模块调用和处理的顺序图

```mermaid
sequenceDiagram
    actor User
    participant MainWindow
    participant QProcess
    participant ExternalModule
    participant QMessageBox

    User->>MainWindow: 点击模块按钮 (例如,模块 1)
    MainWindow->>MainWindow: onModuleButton1Clicked()
    MainWindow->>MainWindow: 检查是否配置了 module1ExePath
    alt 路径为空 (module1ExePath.isEmpty())
        MainWindow->>QMessageBox: warning(this, "执行错误", "模块 1 的路径未配置。")
        QMessageBox-->>User: 显示警告
    else 路径已配置
        MainWindow->>QProcess: startDetached(module1ExePath)
        alt startDetached() 返回 true (进程可能已启动)
            QProcess->>ExternalModule: (异步执行外部模块)
            alt QProcess 发出 errorOccurred 信号 (启动尝试后的异步错误)
                QProcess-)MainWindow: errorOccurred(QProcess::ProcessError error)
                MainWindow->>QMessageBox: critical(this, "进程错误", "启动进程失败: " + process->errorString())
                QMessageBox-->>User: 显示错误
            end
        else startDetached() 返回 false (立即启动失败)
            MainWindow->>QMessageBox: critical(this, "执行错误", "启动模块 1 失败: " + module1ExePath)
            QMessageBox-->>User: 显示错误
        end
    end

config.ini 结构的实体关系图

erDiagram
    "config.ini [Paths] Group" {
        string Module1Exe "模块 1 可执行文件的路径"
        string Module2Exe "模块 2 可执行文件的路径"
    }
    note "表示 config.ini 文件中的 [Paths] 部分。"
Loading

文件级别更改

Change Details Files
构建了主窗口 UI 并应用了自定义 QSS 样式
  • 定义了中心部件、布局、标题标签和两个操作按钮
  • 设置了窗口标题、大小和对齐属性
  • 应用了 Qt 样式表,用于渐变背景、按钮样式、悬停和按下效果
mainwindow.cpp
mainwindow.h
实现了配置加载和验证逻辑
  • 使用 QSettings 从 config.ini 加载模块路径
  • 检查了缺失的配置文件和空的路径条目
  • 通过 QMessageBox 显示了配置问题的警告对话框
mainwindow.cpp
config.ini
添加了进程管理和模块启动处理程序
  • 初始化了 QProcess 并将 errorOccurred 连接到关键的 QMessageBox
  • 创建了 onModuleButton1Clicked 和 onModuleButton2Clicked 插槽,调用 QProcess::startDetached
  • 使用回退错误对话框处理了启动失败
mainwindow.cpp
设置了项目构建文件和占位符脚本
  • 创建了 MedicalRobotGUI.pro,列出了 Qt 模块、源文件和头文件
  • 添加了 main.cpp 以实例化 QApplication 并显示 MainWindow
  • 包含了用于模块测试的占位符 .bat 脚本
MedicalRobotGUI.pro
main.cpp
placeholder1.bat
placeholder2.bat

提示和命令

与 Sourcery 交互

  • 触发新的审查: 在 pull request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 通过回复审查评论,要求 Sourcery 从审查评论创建一个 issue。您也可以回复审查评论并使用 @sourcery-ai issue 从中创建一个 issue。
  • 生成 pull request 标题: 在 pull request 标题中的任何位置写入 @sourcery-ai 以随时生成标题。您也可以在 pull request 上评论 @sourcery-ai title 以随时(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文中的任何位置写入 @sourcery-ai summary 以随时在您想要的位置生成 PR 摘要。您也可以在 pull request 上评论 @sourcery-ai summary 以随时(重新)生成摘要。
  • 生成审查者指南: 在 pull request 上评论 @sourcery-ai guide 以随时(重新)生成审查者指南。
  • 解决所有 Sourcery 评论: 在 pull request 上评论 @sourcery-ai resolve 以解决所有 Sourcery 评论。如果您已经解决了所有评论并且不想再看到它们,这将非常有用。
  • 驳回所有 Sourcery 审查: 在 pull request 上评论 @sourcery-ai dismiss 以驳回所有现有的 Sourcery 审查。如果您想重新开始新的审查,这将特别有用 - 不要忘记评论 @sourcery-ai review 以触发新的审查!

自定义您的体验

访问您的 仪表板 以:

  • 启用或禁用审查功能,例如 Sourcery 生成的 pull request 摘要、审查者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

```
Original review guide in English

Reviewer's Guide

Implements a Qt5 launcher application that constructs a styled main window with title and two module buttons, reads external executable paths from a config.ini via QSettings, and uses QProcess::startDetached to asynchronously launch each module with QMessageBox-based error handling; also adds project metadata and placeholder scripts.

Sequence Diagram for Module Invocation and Handling

sequenceDiagram
    actor User
    participant MainWindow
    participant QProcess
    participant ExternalModule
    participant QMessageBox

    User->>MainWindow: Clicks Module Button (e.g., Module 1)
    MainWindow->>MainWindow: onModuleButton1Clicked()
    MainWindow->>MainWindow: Checks if module1ExePath is configured
    alt Path is Empty (module1ExePath.isEmpty())
        MainWindow->>QMessageBox: warning(this, "Execution Error", "Path for Module 1 is not configured.")
        QMessageBox-->>User: Displays Warning
    else Path is Configured
        MainWindow->>QProcess: startDetached(module1ExePath)
        alt startDetached() returns true (Process potentially launched)
            QProcess->>ExternalModule: (async execution of external module)
            alt QProcess emits errorOccurred signal (Asynchronous error after launch attempt)
                QProcess-)MainWindow: errorOccurred(QProcess::ProcessError error)
                MainWindow->>QMessageBox: critical(this, "Process Error", "Failed to start process: " + process->errorString())
                QMessageBox-->>User: Displays Error
            end
        else startDetached() returns false (Immediate launch failure)
            MainWindow->>QMessageBox: critical(this, "Execution Error", "Failed to start Module 1: " + module1ExePath)
            QMessageBox-->>User: Displays Error
        end
    end
Loading

Entity Relationship Diagram for config.ini Structure

erDiagram
    "config.ini [Paths] Group" {
        string Module1Exe "Path to Module 1 executable"
        string Module2Exe "Path to Module 2 executable"
    }
    note "Represents the [Paths] section within the config.ini file."
Loading

File-Level Changes

Change Details Files
Constructed main window UI and applied custom QSS styling
  • Defined central widget, layouts, title label, and two action buttons
  • Set window title, size, and alignment properties
  • Applied a Qt StyleSheet for gradient background, button styling, hover, and pressed effects
mainwindow.cpp
mainwindow.h
Implemented configuration loading and validation logic
  • Loaded module paths from config.ini using QSettings
  • Checked for missing config file and empty path entries
  • Displayed warning dialogs via QMessageBox for configuration issues
mainwindow.cpp
config.ini
Added process management and module launch handlers
  • Initialized QProcess and connected errorOccurred to a critical QMessageBox
  • Created onModuleButton1Clicked and onModuleButton2Clicked slots invoking QProcess::startDetached
  • Handled launch failures with fallback error dialogs
mainwindow.cpp
Set up project build files and placeholder scripts
  • Created MedicalRobotGUI.pro listing Qt modules, sources, and headers
  • Added main.cpp to instantiate QApplication and show MainWindow
  • Included placeholder .bat scripts for module testing
MedicalRobotGUI.pro
main.cpp
placeholder1.bat
placeholder2.bat

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gucunlin - 我已经查看了您的更改 - 这里有一些反馈:

  • 在调用静态 startDetached() 时,QProcess 成员及其 errorOccurred 连接未使用; 要么切换到 process->start() 以获得有意义的错误回调,要么删除未使用的 QProcess 实例。
  • 在尝试启动之前,验证每个配置的可执行路径是否存在(并且是可执行的),以便更早地捕获错误配置。
  • 考虑将大型内联样式表移动到外部 .qss 资源中,以实现更简洁的代码分离和可维护性。
以下是我在审查期间查看的内容
  • 🟡 一般问题:发现 4 个问题
  • 🟢 安全性:一切看起来都不错
  • 🟢 测试:一切看起来都不错
  • 🟡 复杂性:发现 1 个问题
  • 🟢 文档:一切看起来都不错

Sourcery 对开源是免费的 - 如果您喜欢我们的评论,请考虑分享它们 ✨
帮助我变得更有用! 请点击每个评论上的 👍 或 👎,我将使用反馈来改进您的评论。
Original comment in English

Hey @gucunlin - I've reviewed your changes - here's some feedback:

  • The QProcess member and its errorOccurred connection aren’t used when calling the static startDetached(); either switch to process->start() for meaningful error callbacks or remove the unused QProcess instance.
  • Validate that each configured executable path exists (and is executable) before attempting to launch to catch misconfigurations earlier.
  • Consider moving the large inline stylesheet into an external .qss resource for cleaner code separation and maintainability.
Here's what I looked at during the review
  • 🟡 General issues: 4 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread mainwindow.cpp
)";
this->setStyleSheet(styleSheet);

process = new QProcess(this); // Initialize QProcess
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: 未使用的 QProcess 实例

既然您只使用 QProcess::startDetached,那么 process 成员及其信号连接是不必要的。 考虑删除它们,或者如果您需要监视进程,请切换到 process->start()。

Original comment in English

issue: Unused QProcess instance

Since you're only using QProcess::startDetached, the process member and its signal connections are unnecessary. Consider removing them, or switch to process->start() if you need to monitor the process.

Comment thread mainwindow.cpp
Comment on lines +98 to +99
QString configFilePath = QDir::currentPath() + "/config.ini";
QSettings settings(configFilePath, QSettings::IniFormat);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): 使用 applicationDirPath() 获取配置位置

QDir::currentPath() 在运行时可能会发生变化。 使用 QCoreApplication::applicationDirPath() 或 QStandardPaths 来可靠地定位配置文件。

Suggested change
QString configFilePath = QDir::currentPath() + "/config.ini";
QSettings settings(configFilePath, QSettings::IniFormat);
+ QString configFilePath = QCoreApplication::applicationDirPath() + "/config.ini";
+ QSettings settings(configFilePath, QSettings::IniFormat);
Original comment in English

suggestion (bug_risk): Use applicationDirPath() for config location

QDir::currentPath() can vary at runtime. Use QCoreApplication::applicationDirPath() or QStandardPaths to reliably locate configuration files.

Suggested change
QString configFilePath = QDir::currentPath() + "/config.ini";
QSettings settings(configFilePath, QSettings::IniFormat);
+ QString configFilePath = QCoreApplication::applicationDirPath() + "/config.ini";
+ QSettings settings(configFilePath, QSettings::IniFormat);

Comment thread config.ini
Comment on lines +2 to +3
Module1Exe="placeholder1.bat"
Module2Exe="placeholder2.bat"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): INI 值不应包含引号

带引号的值会被按字面意思读取,从而导致无效的路径。 使用未带引号的值,例如 Module1Exe=placeholder1.bat。

Original comment in English

issue (bug_risk): INI values should not include quotes

Quoted values are read literally, causing invalid paths. Use unquoted values like Module1Exe=placeholder1.bat.

Comment thread mainwindow.cpp
Comment on lines +74 to +77
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error){
Q_UNUSED(error); // error variable might not be used explicitly in this simple handler
QMessageBox::critical(this, "Process Error", QString("Failed to start process: %1").arg(process->errorString()));
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: 利用错误处理程序中的错误代码

在 QMessageBox 中包含错误代码或 ProcessError 值可以更轻松地进行调试。

Suggested change
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error){
Q_UNUSED(error); // error variable might not be used explicitly in this simple handler
QMessageBox::critical(this, "Process Error", QString("Failed to start process: %1").arg(process->errorString()));
});
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error){
QString errorMsg = QString("Failed to start process: %1\nError code: %2")
.arg(process->errorString())
.arg(static_cast<int>(error));
QMessageBox::critical(this, "Process Error", errorMsg);
});
Original comment in English

suggestion: Leverage error code in error handler

Including the error code or ProcessError value in the QMessageBox can make debugging easier.

Suggested change
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error){
Q_UNUSED(error); // error variable might not be used explicitly in this simple handler
QMessageBox::critical(this, "Process Error", QString("Failed to start process: %1").arg(process->errorString()));
});
connect(process, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error){
QString errorMsg = QString("Failed to start process: %1\nError code: %2")
.arg(process->errorString())
.arg(static_cast<int>(error));
QMessageBox::critical(this, "Process Error", errorMsg);
});

Comment thread mainwindow.cpp
#include <QDir>
// QProcess is already included via mainwindow.h

MainWindow::MainWindow(QWidget *parent)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): 考虑通过提取辅助方法、删除未使用的 QProcess 成员以及统一重复的逻辑来重构,以提高清晰度和可维护性。

以下是一些小的、重点突出的步骤,可以减少重复、提取逻辑块并删除未使用的 QProcess 成员。

  1. 删除 process(您从不调用其非静态 API):
    • 删除头文件中的 QProcess* process; 字段
    • 删除 ctor 中的创建和整个析构函数

  2. MainWindow.cpp提取辅助函数,以便您的 ctor 仅将它们连接起来:

MainWindow::MainWindow(QWidget* parent)
  : QMainWindow(parent)
{
  initWindow();
  initUi();
  initStyles();
  loadConfig();
  initConnections();
}
  1. 将两个启动槽合并为一个方法:
// header
private:
  void launchModule(const QString& exePath, const QString& moduleName);

// cpp
void MainWindow::launchModule(const QString& exePath, const QString& moduleName)
{
  if (exePath.isEmpty()) {
    QMessageBox::warning(this, "Execution Error",
                         QString("%1 path is not configured.").arg(moduleName));
    return;
  }
  if (!QProcess::startDetached(exePath)) {
    QMessageBox::critical(this, "Execution Error",
        QString("Failed to start %1: %2").arg(moduleName, exePath));
  }
}
  1. 统一您的 signal→slot 接线
void MainWindow::initConnections()
{
  connect(moduleButton1, &QPushButton::clicked, this, [this]{
    launchModule(module1ExePath, "Module 1");
  });
  connect(moduleButton2, &QPushButton::clicked, this, [this]{
    launchModule(module2ExePath, "Module 2");
  });
}
  1. 提取 UI 设置和样式
void MainWindow::initWindow()
{
  setWindowTitle("野战模组化人机协同手术机器人系统");
  resize(1200, 800);
}

void MainWindow::initUi()
{
  centralWidget = new QWidget(this);
  setCentralWidget(centralWidget);
  mainLayout = new QVBoxLayout(centralWidget);
  // … create titleLabel, moduleButton1/2, layouts …
  centralWidget->setLayout(mainLayout);
}

void MainWindow::initStyles()
{
  setStyleSheet(R"(
    QMainWindow { background-color: qlineargradient… }
    /* … */
  )");
}

这保留了所有行为,但将每个关注点移到一个小的辅助函数中,删除了重复的按钮逻辑,并删除了未使用的 QProcess

Original comment in English

issue (complexity): Consider refactoring by extracting helper methods, removing the unused QProcess member, and unifying duplicated logic for clarity and maintainability.

Here are a few small, focused steps to collapse duplication, pull out logical blocks, and drop the unused QProcess member.

  1. Remove process (you never call its non‐static API):
    • Delete the QProcess* process; field in the header
    • Remove its creation in the ctor and the entire destructor

  2. Extract helpers in MainWindow.cpp so your ctor just wires them up:

MainWindow::MainWindow(QWidget* parent)
  : QMainWindow(parent)
{
  initWindow();
  initUi();
  initStyles();
  loadConfig();
  initConnections();
}
  1. Collapse the two launch slots into one method:
// header
private:
  void launchModule(const QString& exePath, const QString& moduleName);

// cpp
void MainWindow::launchModule(const QString& exePath, const QString& moduleName)
{
  if (exePath.isEmpty()) {
    QMessageBox::warning(this, "Execution Error",
                         QString("%1 path is not configured.").arg(moduleName));
    return;
  }
  if (!QProcess::startDetached(exePath)) {
    QMessageBox::critical(this, "Execution Error",
        QString("Failed to start %1: %2").arg(moduleName, exePath));
  }
}
  1. Unify your signal→slot wiring:
void MainWindow::initConnections()
{
  connect(moduleButton1, &QPushButton::clicked, this, [this]{
    launchModule(module1ExePath, "Module 1");
  });
  connect(moduleButton2, &QPushButton::clicked, this, [this]{
    launchModule(module2ExePath, "Module 2");
  });
}
  1. Pull out UI setup and styling:
void MainWindow::initWindow()
{
  setWindowTitle("野战模组化人机协同手术机器人系统");
  resize(1200, 800);
}

void MainWindow::initUi()
{
  centralWidget = new QWidget(this);
  setCentralWidget(centralWidget);
  mainLayout = new QVBoxLayout(centralWidget);
  // … create titleLabel, moduleButton1/2, layouts …
  centralWidget->setLayout(mainLayout);
}

void MainWindow::initStyles()
{
  setStyleSheet(R"(
    QMainWindow { background-color: qlineargradient… }
    /* … */
  )");
}

This preserves all behavior but moves each concern into a tiny helper, removes duplicated button logic, and drops the unused QProcess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant