qtcanpool 知 03:设计器pk手码

前言

先来解释下标题:设计器pk手码……

设计器:是指Qt Designer,就是在Qt开发过程中,部分界面或全部界面采用Designer的拖拽完成,然后功能逻辑通过手敲代码完成,俗称“拖控件”,常见于MFC这类软件设计方式。
手码:就是在Qt开发过程中,不使用Designer,所有界面和功能逻辑都是手敲代码完成,手速快的,看起来比较牛掰。

解释完,突然发现,就这样结束似乎也没什么问题,上面就是二者的区别,还有啥好pk的呢?

pk之前,作者也仿照别人来一个心路历程好了。

  1. 作者以前是学C语言的,Qt是在自学嵌入式Linux时接触的。因为没学过C++,突然搞起来Qt,还是很有难度的(本来水平就菜),那时候霍亚飞还没出《Qt Creator快速入门》这本书,作者寒假中根据他的博客开始学起来的,不过也都是一知半解,能看懂但自己不会写,只会抄别人的然后修改之。
  2. 这本书后来作者也没看过,博客里面的细节也早都忘得一干二净了,但是有一点,多年之后,再接触Qt时,作者还可以通过Designer(主要根据博客中学了Designer,且以前也糊里糊涂搞过MFC)来拖出来一些类似于“Hello World”水平的界面,所有功能都在一个叫mainwindow.cpp的超级文件中完成。
  3. 工作后,再次接触Qt是看到前辈给的部分代码,老板让借鉴这个残本开发一个功能,那里面没有ui文件,我该怎么拖拽我的控件呀?当时反复折腾一个串口的属性配置界面(波特率,数据位、校验位……),通过Designer一会就拖完了,但用手写要写好久(打字又不快,控件又不熟悉,编码水平又水),手写尽管痛苦,但是作者已经开始学习怎么拆分mainwindow.cpp这个Super File了,功能最后没完成 ……苦涩的沙吹痛脸庞的感觉
  4. 多年后,又接触了Qt,尽管水平还是依菜如故,但是,这次不再使用Designer了,已经全部通过手敲代码来完成,彻底算是抛弃Designer了。

读者看过上面的描述,可能会有疑虑:你也没怎么用过Desinger,你哪来勇气要将Designer和手码进行pk,你懂Designer的好吗?

确实,作者后来项目上再也没用过Designer,它的优美和高效作者也没有体会到,作者也怕写这篇文章会被那些Designer控喷……先不管Designer是为了高效和易学易用,还是对标其他语言的“拖控件”,作者不是要诋毁它,或者说不让人去用它,作者想将设计器和手码两种方式做一个梳理和比较,也许能给看到这篇文章的读者一些思路……

声音

关于Qt开发到底该不该用Designer,其实互联网上也有很多声音,大底如下:

  • 初学的话,还是手写代码,可以了解其中的机制,以后用Designer也会得心应手。
  • 机制是假的,能弄出来才是真。
  • 初学的话,还是用Desinger,能够快速拖拽出来,成就感满满。
  • 觉得Designer设计的又快又好,那就用它;如果觉得Designer是个累赘,还不如手写来的快,那就手码。
  • 还是自己手写代码,那个不爽。
  • Designer就是香。
  • 两者本质上是一样的,可以先用Designer设计个大概,不满意再手动修改。
  • 既然提供了Designer,说明有一定优势,多练习,慢慢体会两者的优缺点,最后达到灵活的在两者之间进行取舍和复合应用。
  • 如果用到大量布局管理器,建议手写。
  • 简单的默认样式用Designer当然快,但如果还要进行各种详细界面设置还是写代码方便。
  • 不用纠结这种问题,对于一个大型的项目,必然有很多自定义的widget,这些widget中有些纯代码方便(比如绘制全新的控件),有些Designer方便(比如组合现有的控件得到新的控件)。怎么方便怎么写就行了。
  • 如果你需要的界面控件都是相对标准,那么直接用designer;如果你需要的界面相对复杂,但主界面相对标准,用designer,个别自定义控件用手写。如果你需要的界面大框架就是自定义控件为主,那就手写。原则上能用designer就没什么必要手写,当然手写是很必要的辅助手段。所以不在于项目大小的问题,更多的在于你使用的整体界面风格。
  • 界面用Designer,逻辑手写,UI和逻辑分离。
  • 建议用designer ,当然有些情况下必须用代码。
  • 感觉直接拖会方便很多… 全自己写的话,布局感觉好麻烦,也不能马上看到效果。
  • 用代码写的,比较自由吧,缺点就是比较烦。
  • 用Designer的ui直接绘制吧,为什么要写代码呢?能省事就省吧。
  • ……

上面都是用户使用过程中体会到的两者区别,再来看看官方是怎么说的:
在这里插入图片描述
特点如下:

  • 所见即所得的方式编写和定义窗口或对话框,并可以使用不同的样式和分辨率对其进行测试。
  • 使用Qt的信号和插槽机制,Designer创建的小部件和表单可以与编程代码无缝集成,因此您可以轻松地将行为分配给图形元素。
  • 在Designer中设置的所有属性都可以在代码中动态更改。
  • 可以将自定义的组件通过插件方式集成到Designer。

好了,作者试着总结一下这些声音:

  • Designer所见即所得;手码靠空间想象。
  • Designer设计标准、层级简单的界面方便;手码灵活多变,写起来麻烦。
  • Designer设计界面,手码写逻辑,UI和逻辑分离。

暂时先不论这些声音的对错,下面用一个简单的例子看看真实情况是什么样的。

论证

Designer可以设计很复杂的界面,如果一个界面元素太多,可以分拆到不同的ui文件中完成,就是不必在一个ui文件(超级文件)上吊死。
Designer中有那么多控件,一个例子要多复杂才可以把它们拖拽清楚呢?还好,这里不是讲解Designer的使用教程,只需要通过一个小小的例子来探探其中的道道即可。

例子:实现一个窗口类MainWindow,其包含两个QPushButton,一个QLabel,一个QTextBrowser和多个Spacer,两个QPushButton文本分别显示“设计器”和“手码”,用户单击哪个按钮哪方就胜利,同时会改变显示“PK”的QLabel的底色。
在这里插入图片描述
主要代码如下:
在这里插入图片描述

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
  • mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

// designer
void MainWindow::on_pushButton_clicked()
{
    ui->label->setStyleSheet(QString::fromUtf8("background-color: rgb(0, 255, 0);\n"
"color: rgb(255, 255, 255);"));
}

// manual
void MainWindow::on_pushButton_2_clicked()
{
    ui->label->setStyleSheet(QString::fromUtf8("background-color: rgb(0, 0, 255);\n"
"color: rgb(255, 255, 255);"));
}
  • ui_mainwindow.h
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.15.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSpacerItem>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QTextBrowser>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_MainWindow
{
public:
    QWidget *centralwidget;
    QVBoxLayout *verticalLayout;
    QSpacerItem *verticalSpacer_2;
    QHBoxLayout *horizontalLayout_2;
    QSpacerItem *horizontalSpacer;
    QHBoxLayout *horizontalLayout;
    QPushButton *pushButton;
    QLabel *label;
    QPushButton *pushButton_2;
    QSpacerItem *horizontalSpacer_2;
    QTextBrowser *textBrowser;
    QSpacerItem *verticalSpacer;
    QMenuBar *menubar;
    QStatusBar *statusbar;

    void setupUi(QMainWindow *MainWindow)
    {
        if (MainWindow->objectName().isEmpty())
            MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
        MainWindow->resize(800, 600);
        centralwidget = new QWidget(MainWindow);
        centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
        verticalLayout = new QVBoxLayout(centralwidget);
        verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
        verticalSpacer_2 = new QSpacerItem(20, 149, QSizePolicy::Minimum, QSizePolicy::Expanding);

        verticalLayout->addItem(verticalSpacer_2);

        horizontalLayout_2 = new QHBoxLayout();
        horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2"));
        horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);

        horizontalLayout_2->addItem(horizontalSpacer);

        horizontalLayout = new QHBoxLayout();
        horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
        pushButton = new QPushButton(centralwidget);
        pushButton->setObjectName(QString::fromUtf8("pushButton"));

        horizontalLayout->addWidget(pushButton);

        label = new QLabel(centralwidget);
        label->setObjectName(QString::fromUtf8("label"));
        label->setStyleSheet(QString::fromUtf8("background-color: rgb(255, 0, 0);\n"
"color: rgb(255, 255, 255);"));
        label->setAlignment(Qt::AlignCenter);

        horizontalLayout->addWidget(label);

        pushButton_2 = new QPushButton(centralwidget);
        pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));

        horizontalLayout->addWidget(pushButton_2);


        horizontalLayout_2->addLayout(horizontalLayout);

        horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);

        horizontalLayout_2->addItem(horizontalSpacer_2);


        verticalLayout->addLayout(horizontalLayout_2);

        textBrowser = new QTextBrowser(centralwidget);
        textBrowser->setObjectName(QString::fromUtf8("textBrowser"));

        verticalLayout->addWidget(textBrowser);

        verticalSpacer = new QSpacerItem(20, 149, QSizePolicy::Minimum, QSizePolicy::Expanding);

        verticalLayout->addItem(verticalSpacer);

        MainWindow->setCentralWidget(centralwidget);
        menubar = new QMenuBar(MainWindow);
        menubar->setObjectName(QString::fromUtf8("menubar"));
        menubar->setGeometry(QRect(0, 0, 800, 22));
        MainWindow->setMenuBar(menubar);
        statusbar = new QStatusBar(MainWindow);
        statusbar->setObjectName(QString::fromUtf8("statusbar"));
        MainWindow->setStatusBar(statusbar);

        retranslateUi(MainWindow);

        QMetaObject::connectSlotsByName(MainWindow);
    } // setupUi

    void retranslateUi(QMainWindow *MainWindow)
    {
        MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));
        pushButton->setText(QCoreApplication::translate("MainWindow", "\350\256\276\350\256\241\345\231\250", nullptr));
        label->setText(QCoreApplication::translate("MainWindow", "PK", nullptr));
        pushButton_2->setText(QCoreApplication::translate("MainWindow", "\346\211\213\347\240\201", nullptr));
        textBrowser->setHtml(QCoreApplication::translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">PK\345\272\225\350\211\262\350\257\264\346\230\216\357\274\232</p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">\347\272\242\350\211\262\357\274\232\350\241\200\346\210\230\344\270\255</p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">\347\273\277\350\211\262\357\274\232\350\256\276\350\256\241\345\231\250\350\203\234</p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -q"
                        "t-block-indent:0; text-indent:0px;\">\350\223\235\350\211\262\357\274\232\346\211\213\347\240\201\350\203\234</p></body></html>", nullptr));
    } // retranslateUi

};

namespace Ui {
    class MainWindow: public Ui_MainWindow {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_MAINWINDOW_H

看破

  • 看:头文件中声明了namespace Ui { class MainWindow; },并定义了私有成员变量Ui::MainWindow *ui;源文件中包含了#include "ui_mainwindow.h",这个头文件哪里来的?
    破:ui_mainwindow.h头文件是根据mainwindow.ui生成的,mainwindow.ui实际上是一个xml文件,里面定义了控件的一些信息,qmake编译过程,会调用一个uic工具,会将xxx_ui文件编译成ui_xxx.h头文件。
  • 看:头文件中有两个按钮的槽函数,除了命名奇怪外,单击按钮是怎么将信号关联到槽的呢?
    破:pushButton和pushButton_2实际上是两个按钮的对象名,可以在designer界面进行有意义的命名,此处为了演示就比较随意。至于如何关联到槽的,注意观察ui_mainwindow.h中的这句QMetaObject::connectSlotsByName(MainWindow);,根据名称连接槽,官方介绍如下:
    在这里插入图片描述

效果如下:
在这里插入图片描述

例子也看完了,是时候总结一下了:

  1. Designer适合初学者吗?
    作者认为是适合的,你看Designer的界面,左侧是基础的控件集合,上侧是信号、布局等操作,右上侧是整个界面元素树,右下侧是不同控件的属性,中心是设计区……右键中心区中的控件,还可以快速设置样式、关联槽、提升(promote)类等,这多适合初学者全面快速了解Qt Widgets的类呀!
  2. Designer高效吗?
    中心区在布局的时候,所见即所得,很爽,即便有时需要打破布局重新布,也是动动鼠标分分钟解决,但如果元素特别多,会稍微麻烦点,有时候可能牵一发而动全身。
  3. Designer真的做到UI和逻辑分离了吗?
    我们看到ui_xxx.h头文件中,Ui类中定义了一堆开放的成员变量,然后在setupUi接口中进行创建,只要Designer支持控件的操作,都可以在setupUi中自动生成,但对于那些自己设计的类呢?那些非标准的接口怎么设置?只能在ui文件之外单独动态的设置,这相当于初始化被强行分在了不同地方,实际上破坏了整体,而且手码就不能做到逻辑分离吗?手码一切!!况且这里都是属于界面,有什么要分离的呢。
  4. Designer中控件命名问题
    如果不对这些控件进行有意义的命名,在ui外部获取成员变量的时候会很头疼,常常记不住名字,通过图形化的方式来命名不一定比手码快。控件命名和对象名被强绑成一样的,不知道是不是可以解绑。
  5. Designer的ui文件不利于阅读
    ui文件是xml文件,不利于阅读,需要先编译生成ui_xxx.h头文件才行,不过拿来先编译,似乎是必须的流程,无图无真相,谁上来还看代码。
  6. Designer的ui文件编辑受限制
    ui文件需要依赖Designer来编辑,对于一些环境上没有Designer的比较费事,当然你如果不装Designer的话,可以直接修改ui文件(靠本事吃饭),毕竟它本质是xml文件。
  7. Designer的模块化设计怎么样?
    通常开发过程中,一个界面布局可能由多个部分组成,每个部分都可以设计成一个类,模块化设计,维护和复用等都方便。采用ui文件进行设计,如果把所有元素都布局在一起,当需要复用某一部分的时候,就有点不方便了,如果也采用模块化设计,可能需要提升类或多ui文件的方式……设计自己的类是常有的事,用提升来兼容Designer是不是显得多余……
  8. ……

上面总结的,是作者个人以为的,难免有的观点会片面,因为作者确实对Designer不是特别熟。

后语

为什么有人会觉得只会“拖控件”的开发是比较Low的?如果你只会拖控件,可能你没有参与过稍大点的项目,可能你不经常设计自己的类,可能你编码能力偏弱,可能你只是初学者,可能你很菜……

个人觉得,要尽快摆脱“拖控件”的束缚,你看那qt-creator的代码,你看那QtitanRibbon的代码,你看那qtcanpool的代码,基本上没有ui文件,所以,你懂得……

### 回答1: “qt canpool fancy demo”在中文中意思是“使用Qt可以创建华丽的演示”。Qt是一个开源的跨平台应用程序开发框架,它提供了丰富的图形界面和功能库,可用于创建各种类型的应用程序,包括演示。 Qt Canpool Fancy Demo为开发者提供了一个用于展示Qt框架强大功能的例子。通过使用Qt的图形界面系统和图形渲染引擎,开发者可以创建出华丽的、吸引人的演示。这些演示可以包含各种特效、动画、渐变和其他视觉元素,以展示Qt的灵活性和多样性。 Qt Canpool Fancy Demo还可以展示Qt的多平台兼容性。Qt可以在多种操作系统上运行,包括Windows、macOS、Linux等等。这意味着您可以使用Qt来创建适用于不同平台的演示,以满足不同用户的需求。 此外,Qt Canpool Fancy Demo还可以展示Qt图形用户界面设计的优势。Qt提供了一个可视化界面设计,使开发者能够通过简单拖拽组件的方式进行界面设计。这个设计工具非常强大且易于使用,使得开发者可以在短时间内创建出华丽的演示。 总的来说,Qt Canpool Fancy Demo展示了Qt框架作为一个功能强大的应用程序开发工具的能力。无论是在图形界面设计、特效展示还是多平台兼容性方面,Qt都可以帮助开发者创建出华丽而且功能丰富的演示。 ### 回答2: Qt Canpool Fancy Demo是一个使用Qt框架开发的漂亮的演示程序。 该演示程序使用Qt的图形界面和动画特效功能,展示了一些引人注目的特性。它有一个精致的用户界面,设计简洁而美观。用户可以通过演示程序中的按钮和菜单来进行各种操作。 Qt Canpool Fancy Demo演示了一些高级的图形特效,如淡入淡出、旋转和缩放。用户可以通过控制面板来调整这些特效的参数,使得演示效果更加个性化。同时,程序还展示了一些图形控件的使用方法,如按钮、滑动条和进度条等。 除了图形特效,Qt Canpool Fancy Demo还提供了一些实用的功能。例如,用户可以通过程序中的文件浏览来选择和编辑文件,还可以通过网络浏览来访问网站。这些功能增加了应用程序的实用性和趣味性。 通过Qt的跨平台特性,Qt Canpool Fancy Demo可以运行在多种操作系统上,如Windows、MacOS和Linux等。这使得用户可以在不同的设备上获得相同的优秀使用体验。 总体而言,Qt Canpool Fancy Demo是一个用Qt开发的令人赏心悦目的演示程序,融合了图形特效、实用功能和跨平台优势。无论是作为学习Qt开发的入门示例,还是用作参考和灵感的源泉,该演示程序都能够为用户带来很多乐趣和启发。 ### 回答3: Qt Canpool Fancy Demo是一个使用Qt框架编写的演示程序。这个演示程序采用了qtcanpool库来实现多线程并行计算的功能。 在这个演示中,通过多线程计算和并行处理,可以提高程序的计算效率和响应速度。当程序运行时,它会将计算任务分配给多个线程,每个线程会同时执行一部分任务,然后将结果汇总。 Qt Canpool Fancy Demo的界面设计精美,采用了Qt的图形界面库来创建演示程序的用户界面。用户可以通过演示程序的界面来输入计算任务的参数和数据,然后点击开始按钮来启动计算过程。 在计算过程中,演示程序会动态显示计算进度和计算结果。通过多线程并行计算,程序可以更快地完成计算任务,并将计算结果显示给用户。 此外,Qt Canpool Fancy Demo还提供了一些额外的功能,例如任务管理、线程调度和错误处理等。这些功能使得程序更加健壮和高效,用户可以更轻松地使用和控制程序的运行。 总之,Qt Canpool Fancy Demo是一个使用Qt框架开发的演示程序,通过多线程并行计算来提高计算效率和响应速度。它具有精美的界面设计和丰富的功能,非常适合用于演示和教学等用途。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值