1、创建项目&修改组件的对象名字和显示文本内容
创建一个 Widget Application 项目类 QDialog,在创建窗体时选择基类 QDialog,生成的类命名为 QWDialog,并选择生成窗体。
在界面设计时,对需要访问的组件修改其objectName,比如各个按钮,需要读取输入的编辑框,需要显示结果的标签等,以便在程序里区分。对于不需要程序访问的组件则无需修改其 objectName,如用于界面上组
件分组的 GroupBox、Frame、布局等,让 UI 设计器自动命名即可。
- objectName是窗体上创建的组件的实例名称,必须唯一,因为程序访问组件是通过objectName进行访问的。
- 窗体的 objectName 就是窗体的类名称,在 UI 设计器里不要修改窗体的 objectName,窗体的实例名称需要在使用窗体的代码里去定义。
2、界面组件布局
2.1、界面组件的层次关系。
使用容器类:如 QgoupBox、QtabWidget、QFrame 等。
例如,将 3 个 CheckBox 组件放置在一个 GroupBox 组件里,该 GroupBox组件就是这 3 个 CheckBox 的容器,移动这个 GroupBox 就会同时移动其中的 3 个 CheckBox:在窗体上放置了2个GroupBox组件,在groupBox1里放置 3 个 CheckBox 组件,在 groupBox2 里放置 3 个 RadioButton 组件
2.2、布局管理
2.2.1、组件面板中的Layouts和Spacers
2.2.2、工具栏:调整设计器进入不同的状态,进行布局设计。
单击需要布局的组件,然后点击布局按钮
- 在窗体上选中组件时Ctrl可以实现组件多选
- 选择容器内组件,相当于选择了其内部的所有组件
此时,选中两个groupBox,点击Lay Out Horizontally,实现水平布局
3、信号与槽
槽就是一个函数:槽函数可以和一个信号关联,当信号被发射时,关联的槽函数被自动执行。
信号与槽关联是用 QObject::connect()函数实现的,其基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
connect()是QObject类的一个静态函数,而QObject是所有Qt类的基类,在实际调用时可以忽略前面的限定符,所以可以直接写为:
connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
其中:
- sender 是发射信号的对象的名称,
- signal()是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。
- receiver 是接收信号的对象名称
- slot()是槽函数的名称,需要带括号,有参数时还需要指明参数。
SIGNAL和STOT是Qt的宏,用于指明信号与槽,并将他们的参数转换为相应的字符串。
(1)一个信号可以连接多个槽,例如:
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));
- 这是当一个对象 spinNum 的数值发生变化时,所在窗体有两个槽进行响应,一个 addFun()用于计算,一个 updateStatus()用于更新状态。
- 当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。
- 当信号和槽函数带有参数时,在 connect()函数里,要写明参数的类型,但可以不写参数名称。
(2)多个信号可以连接同一个槽
例如在本项目的设计中,让三个选择颜色的 RadioButton的 clicked()信号关联到相同的一个自定义槽函数 setTextFontColor()。
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
这样,当任何一个 RadioButton 被单击时,都会执行 setTextFontColor()函数。
(3)一个信号可以连接另外一个信号
例如:
connect(spinNum, SIGNAL(valueChanged(int)), this, SIGNAL (refreshInfo(int));
这样,当一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。
(4)严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。
(5)在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT。
(6)当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。
只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。
4 可视化生成槽函数原型和框架
下面开始设计程序功能。对于该程序,希望它的功能如下。
- 单击 UnderLine、Italic、Bold 3 个 CheckBox 时,根据其状态,设置 PlainTextEdit 里的文字的字体样式;
- Black、Red、Blue 3 个 RadioButton 是互斥选择的,单击某个 RadioButton 时,设置文字的颜色;
- 单击“确定”“取消”或“退出”按钮时,关闭窗口,退出程序。
4.1、字体样式设置
选中chkBoxUnder 组件---->“Go to slot…”,出现下面的对话框:列出了QCheckBox类的所有信号,第一个是clicked(),第2个是带bool参数的clicked(bool)
- 信号clicked():需要在代码中读取CheckBox组件的选中状态
- 信号号 clicked(bool):将CheckBox组件当前的选择状态作为一个参数传递,在响应代码中可以直接利用这个传递的参数
选择 clicked(bool),然后单击“OK”按钮,在 QWDialog 的类定义中,会在 private slots 部分自动增加一个槽函数声明,函数名是根据发射对象及其信号名称自动命名的。
void on_chkBoxUnder_clicked(bool checked);
同时,在 qwdialog.cpp 文件中自动添加了函数 on_chkBoxUnder_clicked(bool)的框架。添加代码
void QWDialog::on_chkBoxUnder_clicked(bool checked)
{QFont font = ui->txtEdit->font();font.setUnderline(checked);ui->txtEdit->setFont(font);
}
以同样的方法为 Italic 和 Bold 两个 CheckBox 设计槽函数,编译后运行,发现已经实现了修改字体的下划线、斜体、粗体属性的功能,说明信号与槽函数已经关联了。
QWDialog 的构造函数执行ui->setupUi(this); ------->的 ui_qwdialog.h 中setupUi有:
QMetaObject::connectSlotsByName(QWDialog);
connectSlotsByName<QWDialog>函数将搜索QWDialog界面上的所有组件,将信号与槽函数的信号和槽关联起来。它假设槽函数的名称是:void on_<object name>_<signal name>(<signal parameters>)
比如,通过UI设计器的操作,为chkBoxUnder自动生成的槽函数是:void QWDialog::on_chkBoxUnder_clicked(bool checked)。那么,connectSlotsByName()就会将此信号和槽函数关联起来,如同执行了下面的这样一条语句:
connect(chkBoxUnder, SIGNAL(clicked (bool)), this, SLOT (on_chkBoxUnder_clicked (bool));
这就是用 UI 设计器可视化设计某个组件的信号响应槽函数,而不用手工去将其关联起来的原因,都是在界面类的构造函数里调用 setupUi()自动完成了关联。
总结:
1、选中组件--->go to slot---->clicked(bool)----->添加代码
2、checkBox可以同时选中
4.2、字体颜色设置
设置字体的 3 个 RadioButton 是互斥性选择的,即一次只有一个 RadioButton 被选中,虽然也可以采用可视化设计的方式设计其 clicked()信号的槽函数,但是这样就需要生成 3 个槽函数。这里可以简化设计,即设计一个槽函数,将 3 个 RadioButton 的 clicked()信号关联到这一个槽函数。为此,在 QWDialog 类的 private slots 部分增加一个槽函数定义如下:
void setTextFontColor();
提示 将鼠标光标移动到这个函数的函数名上面,单击右键,在弹出的快捷菜单中选择“Refactor”→“Add Definition in qwdialog.cpp”,就可以在 qwdialog.cpp 文件中自动为函数 setTextFontColor()生成一个函数框架。
void QWDialog::setTextFontColor()
{QPalette Plet = ui->txtEdit->palette();if(ui->rBtnBlack->isChecked())Plet.setColor(QPalette::Text, Qt::black);else if(ui->rBtnBlue->isChecked())Plet.setColor(QPalette::Text, Qt::blue);else if(ui->rBtnRed->isChecked())Plet.setColor(QPalette::Text, Qt::red);ui->txtEdit->setPalette(Plet);
}
由于这个槽函数是自定义的,所以不会自动与 RadioButton 的 clicked()事件关联,此时编译后运行程序不会实现改变字体颜色的功能。需要在 QWDialog 的构造函数中手工进行关联,代码如下
QWDialog::QWDialog(QWidget *parent) :QDialog(parent),ui(new Ui::QWDialog)
{ui->setupUi(this);connect(ui->rBtnBlack, SIGNAL(clicked()), this, SLOT(setTextFontColor()));connect(ui->rBtnBlue, SIGNAL(clicked()), this, SLOT(setTextFontColor()));connect(ui->rBtnRed, SIGNAL(clicked()), this, SLOT(setTextFontColor()));
}
总结:1、QWDialog 类的 private slots声明槽函数:void setTextFontColor();点击函数名Refactor生成在qwdialog.cpp生成函数框架,并补全函数。
2、在qwdialog.cpp的构造函数里面手动关联
3、RadioButton为单选框
4.3、按钮功能设置
“确定”表示确认选择并关闭对话框,“取消”表示取消选择并关闭对话框,“退出”则直接关闭对话框。
QWDialog是从QDialog继承而来的,QDialog提供了accept(),erject(),close()等槽函数来表示这三种状态,只需要将按钮的clicked()信号与相应槽函数关联即可。
在 UI 设计器里,单击上方工具栏里的“Edit Signals/Slots”按钮[快捷键为F4,取消为F3],窗体进入信号与槽函数编辑状态。
将鼠标移动到“确定”按钮上方,再按下鼠标左键,移动到窗体的空白区域释放左键,这时出现[确定&窗口]关联对话框
- 左侧的列表框里显示了 btnOK 的信号,选择 clicked(),右边的列表框里显示了QWDialog 的槽函数,选择 accept(),单击“OK”按钮
- btnCancel 的 clicked()信号与 QWDialog 的 reject()槽函数关联
- btnClose的 clicked()信号与 QWDialog 的 close()槽函数关联。
- 右侧列表框中没有 close()槽函数,需要勾选下方的“Show signals and slots inherited from QWidget”才会出现 close()函数。
设置完 3 个按钮的信号与槽关联之后,在窗体下方的 Signals 和 Slots 编辑器里也显示了这 3个关联。实际上,可以直接在 Signals 和 Slots 编辑器进行关联设置。现在编译并运行程序,单击这 3 个按钮都会关闭程序。
现在编译并运行程序,单击这 3 个按钮都会关闭程序。
那么,这 3 个按钮的信号与槽函数的关联是在哪里实现的呢?答案在 setupUi()函数里,在setupUi()函数里自动增加了以下 3 行代码:
QObject::connect(btnOK, SIGNAL(clicked()), QWDialog, SLOT(accept()));
QObject::connect(btnCancel, SIGNAL(clicked()), QWDialog, SLOT(reject()));
QObject::connect(btnClose, SIGNAL(clicked()), QWDialog, SLOT(close()));