Qt Designer 窗口/可视化组件及四种编辑模式 和 signals、slots 与 emit的关联

背景介绍

QT元对象系统组成

QObject
是QT对象模型的核心,包含信号和槽的类,必须直接或间接继承自 QObject 

Q_OBJECT
Q_OBJECT宏必须出现在类声明最顶部 (默认私有),用来开启信号和槽、动态属性系统,或QT元对象系统提供的其他服务

MOC
MOC编译器为QObject子类提供了一些实现元对象特性所需要的一些代码。比如说信号,大家只是在类声明的时候声明了所需要的信息,在MOC编译时,会为信号添加函数定义。

 

一、信号与槽的关联

1.1 信号(Signals)

“信号”,在Qt中,操作一个控件后,会产生和操作对应的信号

signals 前面不可加 public、private 和 protected 进行修饰;
类似虚函数,只要在头文件中声明它就够了,而且这些信号函数没有函数体定义,函数体由moc自动生成,不需要用户在.cpp文件中实现;
而且也不能有返回类型(即signals 区域的函数必须是 void 类型);
宏定义函数指针不能用于信号和槽的参数,信号和槽也不能有缺省参数

信号函数定义规则:
信号是类的成员函数,并且返回类型必须是void
信号函数只需要声明,不需要定义
参数可以随意指定,信号也支持重载
信号需要使用 signals 关键字进行声明
在程序中发送自定义信号:发送信号的本质就是调用信号函数 emit mysignals()
emit 是个空宏,没有特殊含义,仅用来表示这个语句是发射一个信号,不写可以,但不推荐。

内置公用信号:@e.g.   clicked()、clicked(bool)、pressed()、released()、toggled(bool);findNext()和findPrevious()

正常情况下单击按钮,响应顺序为:pressed() — <about 215ms> — released() — <almost 0ms> — clicked()。

@e.g.

signals:
void SendData(QString str);  // 信号函数
/*********************/
signals:
void mySignal();
void mySignal(int x);
void mySignalParam(int x,int y);

emit 发射信号:

xxx::yyy(zzz)
{
    emit mySignal();            //发射信号mySignal()
    emit mySignal(5);           //发射信号mySignal(int)
    emit mySignalParam(5,100);  //发射信号mySignalParam(5,100)
}

 

1.2 槽(Slots)

“槽”,在Qt中,“槽” 就是用来连接 “信号” 的函数。比如说,点击按钮后,按钮会产生一个点击信号,我们使用槽函数来接收点击信号,然后在槽函数中执行功能代码。

slots 在头文件声明时前面可以加 public、private 和 protected,因为 Qt 说槽函数是普通的C++成员函数,能被正常调用;
唯一特别性就是:可以关联多个信号,当和其关联的信号被 发射 emit 时,这个槽就会被调用;
宏定义函数指针不能用于信号和槽的参数,信号和槽也不能有缺省参数

槽函数定义规则:
槽函数的返回类型必须是void
槽函数的参数必须等于或少于信号的参数
当信号与槽函数的参数数量相同时,它们参数类型要完全一致

@e.g.

public slots:
private slots:
void GetData(QString str); // 槽函数
/********************/
public slots:
void mySlot();
void mySlot(int x);
void mySignalParam(int x,int y);

 

1.3 关联(Connect)

连接“信号”到“槽函数”,Connect()将信号与槽连接上:
@e.g. connect(&SD,SIGNAL(SendData(QString)),this,SLOT(GetData(QString)));
信号和槽的关联有三种方式,分别是直接关联、使用中介对象和使用Qt的元对象系统。下面将详细介绍这三种方式。

 

1.3.1 直接(函数)关联

@note 最简单常见,这是Qt早期的连接语法,使用"字符串"表示信号和槽。在编译时无法进行类型检查。
@fmt 

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

@anno connect(发送信号的对象,信号名, 接收信号的对象,槽函数名);

其中,sender是信号的发送者;SIGNAL()是代表信号的宏定义,里面的参数signal是信号;receiver是信号的接收者;SLOT()是代表槽的宏定义,里面的参数slot是槽函数。举个例子:

@e.g.

QObject::connect(sender, SIGNAL(mySignal()), receiver, SLOT(mySlot()));
QObject::connect(ui->pushButton1, SIGNAL(clicked()), this, SLOT(func()));

@cmt 这个connect的作用是,将界面的按钮(按钮命名为pushButton1)的点击信号clicked()连接到当前界面(用this表示)的槽函数func()。当点击界面的pushButton1按钮时,程序就会跑到this类中的func()函数里。

 

1.3.2 函数指针关联

@note 这种连接方式在编译时进行了类型检查,但在一些情况下可能不够灵活,比如连接到一个基类的槽。
@fmt 

QObject::connect(sender, &SenderClass::signal, receiver, &ReceiverClass::slot);

  

1.3.3 Lambda表达式连接(C++11及以后版本):

@note 这种方式可以使用 Lambda表达式 作为槽的实现,非常方便。
@fmt 

QObject::connect(sender, &SenderClass::signal, [=]() { /* slot implementation */ });

  

1.3.4 使用中介对象

@note 复杂的通信关系,这种方式可以帮助解耦信号发送者和信号接收者之间的关系
@e.g.

QObject::connect(sender, SIGNAL(mySignal()), mediator, SLOT(handleSignal()));
QObject::connect(mediator, SIGNAL(processedSignal()), receiver, SLOT(mySlot()));

 

1.3.5 使用Qt的元对象系统

@note Qt的 元对象系统 是一种基于反射的机制。QMetaMethod::fromSignalQMetaMethod::fromSlot
@e.g.

QObject::connect(sender, QMetaMethod::fromSignal(&Sender::mySignal), receiver, QMetaMethod::fromSlot(&Receiver::mySlot));

 

1.3.6 Qt5 连接方式·函数指针关联

@note 这种语法在Qt5中引入,允许指定连接类型,例如Qt::AutoConnection、Qt::DirectConnection等。
@fmt

 QObject::connect(sender, &SenderClass::signal, receiver, &ReceiverClass::slot, Qt::ConnectionType);

  

五种连接方式:

Qt::AutoConnection:"自行”连接为默认连接方式。连接类型在信号发射时确定(运行时,而非编译时)。
根据线程亲和性,即信号和槽所在的线程自动选择连接方式。如果在同一线程,使用的是Qt::DirectConnection;否则多线程时则使用Qt::QueuedConnnection。

Qt::DirectConnection:信号被发送时,立即"直接"调用槽函数。适用于信号和槽在同一线程的情况,槽在信号发射的线程里执行。

Qt::QueuedConnection:将信号放入接收者线程的"事件队列"中,由接收者线程在适当的时候处理。
适用于跨线程通信。当控制权回到receiver所在线程时才执行槽函数。槽函数在receiver的线程里执行。

Qt::BlockingQueuedConnection:与QueuedConnection类似,但发送信号的线程会被阻塞,直到接收者线程处理完,槽函数返回。
当receiver和sender在同一个线程里时,不可以使用该方式,否则会发生死锁。

Qt::UniqueConnection:确保连接是唯一的,防止多次连接同一个信号和槽。如果已经存在相同的连接,新的连接将不会被创建。
该类型可以和上面的类型配合,用或“|”处理即可。当连接已经存在时,再次连接会失败。其实就是为了保证连接的唯一性。

注意:当使用QueuedConnection时,参数类型必须是 Qt 的 meta-object system 知道的类型,因为Qt要拷贝参数。可以connect()前调用qRegisterMetaType()来注册数据类型。

 

https://blog.csdn.net/weixin_55887103/article/details/142086124
https://blog.csdn.net/weixin_42812764/article/details/109516019


二、 Qt Designer 四种编辑模式

Qt Designer提供四种编辑模式: Widget Editing ModeSignals and Slots Editing Mode Buddy Editing ModeTab Order Editing Mode

 

在使用Qt Designer进行界面设计时,您将始终处于以下四种模式之一。要在此模式之间切换,请从“编辑”菜单或工具栏中选择它即可。
下表详细描述了这些模式。

窗口部件编辑模式(Widget Editing Mode),窗体内部件,可以操作更改表单的外观、添加布局以及编辑部件的属性。要切换到此模式,请按 F3。这是Qt Designer的默认模式。
信号/槽编辑模式(Signals and Slots Editing Mode),可以使用Qt的信号和槽机制将不同部件关联到一起。要切换到此模式,请按 F4。
伙伴编辑模式(Buddy Editing Mode),可以将“伙伴部件Buddy widget”(如编辑框)分配给标签(Lable)组件,以帮助它们正确处理“键盘焦点”。
Tab顺序编辑模式(Tab Order Editing Mode),可以设置部件接收“键盘焦点”(Tab和Shift+Tab)的切换顺序。

 

三、QMainWindow, QWidget 和 QDialog 三个窗口类区别

QMainWindow、QWidget和QDialog是Qt框架中常用的三个窗口类,它们在Qt应用程序中扮演不同的角色。

 

3.1 QMainWindow(主窗口):

概念:QMainWindow是Qt中的主窗口类,通常用于创建具有菜单栏 QMenuBar、工具栏 QTooBar、状态栏 QStatusBar等常见应用程序界面元素的窗口。
分类:属于顶级窗口类。
优势:提供了丰富的布局和管理功能,方便构建复杂的多文档界面(MDI)应用程序。
应用场景:适用于需要展示多个子窗口、具有菜单和工具栏的应用程序,如文本编辑器、图形编辑器等。

 

QMainWindow 中使用布局管理器

我们有时候会在 QMainWindow 中使用 QVBoxLayout 或 QHBoxLayout 时,无法显示布局中的内容
原因:QMainWindow 类默认使用了一个 QVBoxLayout 作为其主布局。当尝试将 QVBoxLayout 或 QHBoxLayout 直接设置为 QMainWindow 的布局时,它们可能会与 QMainWindow 默认的主布局冲突,导致布局无法正确显示。
解决办法:
要在 QMainWindow 中使用 QVBoxLayout 或 QHBoxLayout,可以将它们放置在 QWidget 中,并将该 QWidget 设置为 QMainWindow 的  “中心部件central widget”

KDiff3App::KDiff3App(QWidget* pParent, const QString& name, KDiff3Part* pKDiff3Part):
    QMainWindow(pParent) //previously KMainWindow
{
    setWindowFlags(Qt::Widget);
    setObjectName(name);
    m_pKDiff3Part = pKDiff3Part;
    m_pKDiff3Shell = qobject_cast<KParts::MainWindow*>(pParent);

    /* 1. 创建一个 QWidget 作为this"主窗口QMainWindow"的“中心部件” *
    m_pCentralWidget = new QWidget(this);
    
    /* 创建一个 QVBoxLayout,并将其设置为 “中心部件” 的“垂直布局管理器” */
    QVBoxLayout* pCentralLayout = new QVBoxLayout(m_pCentralWidget);
    pCentralLayout->setContentsMargins(0, 0, 0, 0);
    pCentralLayout->setSpacing(0);    
    /*  设置 QWidget 为 “主窗口QMainWindow” 的 “中心部件central widget” */
    setCentralWidget(m_pCentralWidget);

    /* 2. 创建一个 QWidget 作为“中心部件”的 “主工作区” */
    m_pMainWidget = new QWidget(m_pCentralWidget);
    m_pMainWidget->setObjectName("MainWidget");
    /* 设置 QWidget 为 “中心部件central widget” 的 “主工作区” */    
    pCentralLayout->addWidget(m_pMainWidget);
    m_pMainWidget->hide();

    setWindowTitle("KDiff3");
    setUpdatesEnabled(false);
    
    // ...
}

布局/分割函数,使用方式:

// 创建布局同时绑定父窗口部件: 
new QVBoxLayout( QWidget* parent)
// 后期将布局添加到 QWidget 窗口中: 
QWidget*parent->setLayout( QVBoxLayout* );
   
// 布局添加“分割器”: 
QVBoxLayout* ->addWidget( QSplitter* )
// 布局添加窗口: 
QVBoxLayout* ->addWidget( QWidget* )
// 布局添加滚轮: 
QVBoxLayout* ->addWidget( QScrollBar* )

// 创建可水平分割“主”分割器(无父窗口):
 new QSplitter(Qt::Horizontal,0)
// 从父窗口创建可垂直分割器: 
new QSplitter(Qt::Vertical, QWidget* parent)
// 分割器添加新窗口: 
QSplitter* ->addWidget( QWidget*  )

 

3.2 QWidget(窗口):

概念:QWidget是Qt中的基本窗口类,是所有用户界面控件的基类,可以作为其他窗口类的父类。
分类:属于顶级窗口类。
优势:提供了基本的窗口功能,如事件处理、布局管理等,可用于创建自定义的窗口。
应用场景:适用于创建简单的窗口,如对话框、工具窗口等。

3.3 QDialog(对话框):

概念:QDialog是Qt中用于创建对话框的窗口类,通常用于与用户进行交互,获取用户输入或显示消息
分类:属于顶级窗口类。
优势:提供了对话框特有的功能,如模态对话框、按钮布局等,方便与用户进行简单的交互。
应用场景:适用于需要与用户进行交互的场景,如消息框、输入框、文件选择框等。

3.4 其他Qt内置(对话框):

对话框输入控件:QFileDialog(文件对话框),QInputDialog(输入对话框),QColorDialog(颜色对话框),QFontDialog(字体对话框)
对话框显示控件:QMessageBox(信息提示框),QErrorMessage(错误提示框),QProgressDialog(进度提示框)

总结:
QMainWindow适用于创建具有菜单栏、工具栏和状态栏等复杂界面的应用程序;
QWidget是基本的窗口类,可作为其他窗口类的父类;
QDialog用于创建对话框,方便与用户进行交互。
它们在功能和应用场景上有所区别,开发者可以根据具体需求选择合适的窗口类来构建Qt应用程序的界面。

 四、 Qt GUI 设计:UI 界面可视化组件

参考文献:
https://developer.aliyun.com/article/1478616
https://xie.infoq.cn/article/9938aee0c0919b74cef3df266

4.0 界面可视化组件分类:

分别为:布局组件(Layouts)、分隔组件(Spacers)、按钮组件(Buttons)、表项视图(Item Views)、表项组件(Item Widgets)、容器组件(Containers)、输入组件(Input Widgets)、显示组件(Display Widgets)

 下面只详细介绍一些常用组件:

4.1 布局组件(Layouts)

布局组件包括:Vertical Layout(水平布局)、Horizontal Layout(垂直布局)、Grid Layout(网格布局)、Form Layout(表单布局)。

QVBoxLayout (垂直布局):VBox Layout按垂直方向排列其子部件。它们会根据容器的大小自动调整子部件的大小和位置。可以向垂直布局添加部件,并控制它们的对齐方式、间距等属性。
QHBoxLayout (水平布局):HBox Layout按水平方向排列其子部件。类似于垂直布局,它们会根据容器的大小自动调整子部件的大小和位置。可以向水平布局添加部件,并控制它们的对齐方式、间距等属性。

4.2 分隔组件(Spacers)

分隔组件包括:Horizontal Spacer(水平分隔)、Vertical Spacer(垂直分隔)。

 

4.3 按钮组件(Buttons)

按钮组件包括:QPushButton(按键按钮)、QToolButton(工具按钮)、QRadioButton(单选框)、QCheckButton(复选框)、QCommandLinkButton(命令链接按钮)、QDialogButtonBox(对话框确认-选择按钮框)。


 

4.4 表项视图(Item Views)

表项视图包括:QListView(列表视图)、QTreeView(树状视图)、QTableView(表格视图)、QColumnView(列表视图)、QUndoView(撤销视图)。



 

4.5 表项组件(Item Widgets)

表项组件包括:QListWidget(列表表项)、QTreeWidget(树状表项)QTableWidget(表格表项)。

 

4.6 容器组件(Containers)

容器组件包括:QGroupBox(组合框,可以在内部添加内容,并修改标题头)、QScrollArea(带滑动条的框)、QToolBox(抽屉式框)、QTabWidget(标签式框)、QStackedWidget(栈式,需要信号启动)、
QFrame(带边框的布局)、QWidget(不带边框的布局)、QMdiarea(多文档分栏显示){QMdiSubWindow}、QDockWidget(浮动窗口)、QAxWidget(只可以在 Windows 环境使用)。

QSplitter (窗口分割器):

 

4.7 输入组件(Input Widgets)

输入组件包括:QComboBox(组合框下拉框)、QFontDialog(下拉字体对话框)、QlineEdit(单行编辑框)、QTextEdit(多行编辑框,只可以查看文字、图片和动画)、QPlainTextEdit(多行文字编辑框)、
QSpinBox(整型数字调节框)、QDoubleSpinBox(浮点数字调节框)、QTimeEdit(时间输入)、QDateEdit(日期输入)、QDateTimeEdit(日期和时间输入)、QDial(罗盘旋转输入)、
QScrollBar(滚动条){Horizontal Scroll Bar(水平滚动条)、Vertical Scroll Bar(垂直滚动条)}、QSlider(直线拖动输入){Horizontal Slider(水平滑动条)、Vertical Slider(垂直滑动条)}、
QkeySequenceEdit(快捷键输入)。


调节输入控件:QAbstractSpinBox(步长调节输入)
滑动输入控件:QRubberBand(橡皮筋拖拽)

QScrollBar (滚动条):

4.8 显示组件(Display Widgets)

显示组件包括:QLabel(标签显示框,可查看文本、网页、图片和动画等)、QTextBrowser(文本签显示框)、QGraphicsView(绘图工具)、QCalendarWidget(日历)、QLCDNumber(LCD 液晶数码显示)、
QProgressBar(进度条显示)、Line{Horizontal Line(水平分割线)、Vertical Line(垂直分割线)}、QOpenGLWidget(OpenGL(Open Graphics Library,开放图形库)图形渲染的部件,
可以在 PyQt 和 Qt 的应用中显示图形(包括 2D 和 3D 图形))、QQuickWidget(加载 QML 文件)。

 

posted @ 2024-12-13 20:21  suntroop  阅读(328)  评论(0)    收藏  举报