MFC转QT - Qt界面开发 - Qt Designer

MFC转QT - Qt界面开发 - Qt Designer

编码文章call10242025-05-07 11:59:224A+A-



Qt Designer概述

Qt Designer是Qt开发环境中的可视化UI设计工具,它允许开发者通过拖放方式设计用户界面,而不需要手写界面代码。这与MFC的对话框编辑器类似,但功能更强大、更灵活。

与MFC对话框编辑器的对比

特性

Qt Designer

MFC对话框编辑器

布局系统

灵活的布局管理器

基于坐标的定位

预览能力

所见即所得,支持实时预览

有限的预览功能

自定义控件

支持直接集成自定义控件

有限支持

国际化支持

内置文本提取与翻译支持

需要额外处理

表单继承

支持基于现有表单创建新表单

不直接支持

代码生成

生成XML格式UI文件,独立于代码

生成资源脚本和C++代码

信号槽连接

可视化信号槽编辑器

消息映射需手动编码

样式预览

支持样式表预览

不支持

对于从MFC迁移的开发者,Qt Designer提供了更直观、更高效的界面设计体验。

Qt Designer界面与操作

主要界面组件

  1. 控件面板(Widget Box) - 包含所有可用控件
  2. 对象检查器(Object Inspector) - 显示对象层次结构
  3. 属性编辑器(Property Editor) - 编辑选中控件的属性
  4. 信号槽编辑器(Signal/Slot Editor) - 建立对象间的连接
  5. 动作编辑器(Action Editor) - 管理应用程序动作
  6. 资源浏览器(Resource Browser) - 管理项目资源
  7. 设计区域(Form Editor) - 主要设计界面

基本操作流程

  1. 创建表单 - 从模板创建新表单(对话框、主窗口等)
  2. 添加控件 - 从控件面板拖放控件到设计区域
  3. 设置布局 - 选择控件应用布局管理器
  4. 调整属性 - 在属性编辑器中设置控件属性
  5. 建立连接 - 使用信号槽编辑器建立对象间连接
  6. 预览表单 - 使用Ctrl+R预览设计效果
  7. 保存表单 - 保存为.ui文件

常用快捷键

  • Ctrl+R - 预览表单
  • Ctrl+A - 选择所有控件
  • Ctrl+Z/Y - 撤销/重做
  • Ctrl+G - 打开布局网格设置
  • F3/F4 - 选择上/下一个控件
  • Ctrl+Shift+L - 切换表单视图
  • Alt+方向键 - 调整控件在布局中的关系

.ui文件与代码生成

Qt Designer创建的界面保存为XML格式的.ui文件,而不是直接生成C++代码。这种设计有几个重要优点:

  1. 界面设计与代码分离,便于协作开发
  2. 可以在不重新编译程序的情况下修改界面
  3. 支持在运行时动态加载界面
  4. 更容易维护和更新

.ui文件结构

.ui文件是一个XML文档,描述用户界面的结构、属性和布局:

 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
  <class>MainWindow</class>
  <widget class="QMainWindow" name="MainWindow">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>600</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>MainWindow</string>
   </property>
   <widget class="QWidget" name="centralwidget">
    <!-- 中央窗口小部件内容 -->
   </widget>
   <widget class="QMenuBar" name="menubar">
    <!-- 菜单栏内容 -->
   </widget>
   <widget class="QStatusBar" name="statusbar"/>
  </widget>
  <resources/>
  <connections/>
 </ui>

在代码中使用.ui文件

有两种主要方式使用.ui文件:

1. 使用uic工具生成C++代码

Qt的User Interface Compiler (uic) 可以将.ui文件转换为C++代码:

 // ui_mainwindow.h (自动生成)
 namespace Ui {
     class MainWindow {};
 }
 
 // 在你的类中使用生成的UI
 class MainWindow : public QMainWindow
 {
     Q_OBJECT
 
 public:
     MainWindow(QWidget *parent = nullptr);
     ~MainWindow();
 
 private:
     Ui::MainWindow *ui;
 };
 
 // 实现
 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
 {
     ui->setupUi(this); // 这一行设置ui
     
     // 现在可以通过ui访问控件
     ui->pushButton->setText("点击我");
     
     // 连接信号槽
     connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
 }
 
 MainWindow::~MainWindow()
 {
     delete ui;
 }

这是最常用的方式,qmake自动处理uic的调用。

2. 在运行时加载.ui文件

对于某些情况,可以在运行时动态加载界面:

 #include <QUiLoader>
 #include <QFile>
 
 QWidget* loadUiFile(const QString &uiFilePath)
 {
     QFile file(uiFilePath);
     file.open(QFile::ReadOnly);
     
     QUiLoader loader;
     QWidget *widget = loader.load(&file);
     file.close();
     
     return widget;
 }
 
 // 使用
 QWidget *myForm = loadUiFile(":/forms/myform.ui");
 QPushButton *button = myForm->findChild<QPushButton*>("pushButton");
 if (button) {
     button->setText("动态加载的按钮");
 }

这种方法需要包含QtUiTools模块。

与MFC资源对比

MFC

Qt

.rc和.rc2文件

.ui和.qrc文件

资源编辑器修改.rc

Qt Designer修改.ui

对话框ID和控件ID

对象名称

对话框模板代码类向导生成

uic自动生成ui_*.h

通过DDX/DDV交换数据

直接通过ui->控件访问

UpdateData()显式更新

无需显式调用更新

自定义控件的创建和使用

Qt Designer支持自定义控件,这是从MFC迁移时一个强大的功能,使得复杂界面组件可重用。

创建自定义控件

1. 组合现有控件

最简单的自定义控件是组合现有控件:

 // 例:创建带标签的输入框
 class LabeledLineEdit : public QWidget
 {
     Q_OBJECT
     Q_PROPERTY(QString label READ label WRITE setLabel)
     Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
     
 public:
     LabeledLineEdit(QWidget *parent = nullptr) : QWidget(parent)
     {
         // 创建布局
         QHBoxLayout *layout = new QHBoxLayout(this);
         layout->setMargin(0);
         
         // 创建子控件
         m_label = new QLabel(this);
         m_lineEdit = new QLineEdit(this);
         
         // 添加到布局
         layout->addWidget(m_label);
         layout->addWidget(m_lineEdit);
         
         // 连接信号
         connect(m_lineEdit, &QLineEdit::textChanged, 
                 this, &LabeledLineEdit::textChanged);
     }
     
     QString label() const { return m_label->text(); }
     void setLabel(const QString &text) { m_label->setText(text); }
     
     QString text() const { return m_lineEdit->text(); }
     void setText(const QString &text) { m_lineEdit->setText(text); }
     
 signals:
     void textChanged(const QString &text);
     
 private:
     QLabel *m_label;
     QLineEdit *m_lineEdit;
 };

2. 从头创建自定义绘制控件

对于需要自定义绘制的控件:

 // 例:自定义LED指示灯控件
 class LedIndicator : public QWidget
 {
     Q_OBJECT
     Q_PROPERTY(bool on READ isOn WRITE setOn)
     Q_PROPERTY(QColor onColor READ onColor WRITE setOnColor)
     
 public:
     LedIndicator(QWidget *parent = nullptr) : QWidget(parent), m_on(false), m_onColor(Qt::green)
     {
         setMinimumSize(24, 24);
     }
     
     bool isOn() const { return m_on; }
     void setOn(bool on) { 
         if (m_on != on) {
             m_on = on; 
             update(); 
         }
     }
     
     QColor onColor() const { return m_onColor; }
     void setOnColor(const QColor &color) { 
         m_onColor = color; 
         update(); 
     }
     
 protected:
     void paintEvent(QPaintEvent *) override
     {
         QPainter painter(this);
         painter.setRenderHint(QPainter::Antialiasing);
         
         // 绘制LED
         QRect r = rect().adjusted(2, 2, -2, -2);
         painter.setPen(Qt::black);
         painter.setBrush(m_on ? m_onColor : Qt::gray);
         painter.drawEllipse(r);
         
         // 绘制高光
         if (m_on) {
             painter.setPen(Qt::NoPen);
             painter.setBrush(QColor(255, 255, 255, 70));
             painter.drawEllipse(r.adjusted(r.width()/4, r.height()/4, -r.width()/2, -r.height()/2));
         }
     }
     
 private:
     bool m_on;
     QColor m_onColor;
 };

将自定义控件注册到Qt Designer

要在Qt Designer中使用自定义控件,需要创建插件:

 // 1. 创建插件类
 class MyCustomWidgetsPlugin : public QObject, public QDesignerCustomWidgetCollectionInterface
 {
     Q_OBJECT
     Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
     Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface")
     
 public:
     MyCustomWidgetsPlugin(QObject *parent = nullptr) : QObject(parent) 
     {
         m_widgets.append(new LabeledLineEditPlugin(this));
         m_widgets.append(new LedIndicatorPlugin(this));
     }
     
     QList<QDesignerCustomWidgetInterface*> customWidgets() const override
     {
         return m_widgets;
     }
     
 private:
     QList<QDesignerCustomWidgetInterface*> m_widgets;
 };
 
 // 2. 为每个控件创建插件接口
 class LabeledLineEditPlugin : public QObject, public QDesignerCustomWidgetInterface
 {
     Q_OBJECT
     Q_INTERFACES(QDesignerCustomWidgetInterface)
     
 public:
     // 实现所需接口方法...
     QString name() const override { return "LabeledLineEdit"; }
     QString group() const override { return "My Custom Widgets"; }
     QWidget *createWidget(QWidget *parent) override
     {
         return new LabeledLineEdit(parent);
     }
     // ...其他必要方法
 };

编译插件后,将其放入Qt Designer的插件目录即可在控件面板中看到自定义控件。

使用提升(Promotion)

对于不想创建Designer插件的场景,可以使用"提升"功能:

  1. 在Designer中放置一个基类控件(如QWidget)
  2. 右键点击 -> "Promote to..."
  3. 添加自定义类名和头文件
  4. 确认提升

这样在生成的代码中,会使用你的自定义类而不是基类。

表单设计最佳实践

1. 合理使用布局

  • 总是使用布局管理器而非固定位置
  • 嵌套布局创建复杂界面
  • 使用间隔(spacers)创建平衡的界面
  • 设置合适的边距和间距

2. 组织控件层次

  • 使用QGroupBox分组相关控件
  • 利用对象检查器保持清晰的对象层次
  • 为重要控件设置有意义的对象名

3. 优化属性设置

  • 设置buddy关系让标签支持快捷键
  • 使用Tab顺序工具设置合理的Tab导航
  • 为控件添加工具提示和状态提示
  • 设置合适的尺寸策略(SizePolicy)

4. 国际化考虑

  • 使用tr()包装所有用户可见文本
  • 为可能变长的文本预留足够空间
  • 避免在设计中假设特定文本长度

5. 表单间复用

  • 利用QUiLoader动态加载公共UI组件
  • 为常用组件创建单独的.ui文件
  • 在大型应用中组织.ui文件到逻辑目录

从MFC迁移到Qt Designer的技巧

对于有MFC经验的开发者,以下是迁移到Qt Designer的实用建议:

1. 思维转换

  • 放弃固定坐标的思维,拥抱布局系统
  • 使用对象名而非控件ID识别控件
  • 专注于声明性UI设计,而非程序式

2. 功能映射

  • MFC对话框模板 → Qt .ui文件
  • 对话框资源ID → 窗口类名
  • 控件变量 → ui->控件名
  • DDX/DDV → 直接属性访问
  • UpdateData() → 无需显式调用
  • 消息处理函数 → 信号槽连接

3. 工作流调整

  • 在Designer中完成所有界面设计
  • 在代码中处理逻辑和数据处理
  • 使用信号槽(而非消息)处理用户交互
  • 利用属性系统简化数据绑定
  • 使用.ui文件预览快速验证设计
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4