在上一篇 Qt 地址薄 (一) 界面设计 中,主要是实现了地址簿的界面,使用布局管理器进行元素的布局,并解释了 “子类化” 和 “所有权” 的概念。
本篇将在上面的基础上,在界面中新加三个 QPushButton 按钮,通过 “信号 - 槽函数” 机制,实现保存 Name 和 Address 内容的功能。
1 三个按钮
如下所示,在 AddressBook 的右侧,添加三个按钮,分别命名为 “Add”、“Submit” 和 "Cancel"

1.1 数据成员
这三个按钮与 AddressBook 是 "包含" 关系 (has-a),因此,可声明为 AddressBook 的数据成员
1 QPushButton *add_btn_; 2 QPushButton *submit_btn_; QPushButton *cancel_btn_;
为了保存输入的 Name 和 Address,声明一个 QMap<QString, QString> 类型的数据成员
QMap<QString, QString> contacts_;
为了保存 Name 和 Address 之前的内容,再声明两个 QString 类型的数据成员
1 QString old_name_; 2 QString old_addr_;
1.2 布局
新建 QVBoxLayout 型 layout_btn,将这三个按钮组合成一列,再将 layout_btn 加入到 主布局管理器 layout 中
1// three btn 2 add_btn_ = new QPushButton(tr("Add")); 3 submit_btn_ = new QPushButton(tr("Submit")); 4 cancel_btn_ = new QPushButton(tr("Cancel")); 5 6 // new layout_btn 7 QVBoxLayout *layout_btn = new QVBoxLayout; 8 layout_btn->addWidget(add_btn_, Qt::AlignTop); 9 layout_btn->addWidget(submit_btn_); 10 layout_btn->addWidget(cancel_btn_); 11 layout_btn->addStretch(); 12 13 // add layout_btn into layout 14 layout->addLayout(layout_btn,1,2);
1.3 addStrech() 函数
下图是布局管理器,调用 addStretch() 函数和未调用的区别

2 信号槽
2.1 功能描述
1) Add 功能
QLineEdit 和 QTextEdit 的默认为只读,若点击 Add 按钮,二者状态变为可编辑。此时,用户可输入 Name 和 Address 的内容。同时,显示出 Submit 和 Cancel 两个按钮
2) Submit 功能
点击 Submit 按钮,可将用户输入的 Name 和 Address 保存到程序中。若输入为空,则提示请输入的信息;若该 Name 已经添加过,则提示已经添加
3) Cancel 功能
点击 Cancel 按钮,可将用户输入的 Name 和 Address 取消掉,不进行保存,同时显示出之前的 Name 和 Address
2.2 信号槽机制
信号槽机制,主要用于 类对象之间的通信,是 Qt 的精髓所在,与之类似的有:观察者模式,回调机制等
当特定的事件发生后,相应的信号被发出,则与该信号 connect 的槽函数,随后被调用

2.3 connect 函数
使用 connect 函数,将发射信号的 类对象 + 信号,以及接收信号的 类对象 + 槽函数,连接起来

具体的实现代码如下:
1connect(add_btn_, SIGNAL(clicked()), this, SLOT(OnAdd())); 2connect(submit_btn_, SIGNAL(clicked()), this, SLOT(OnSubmit())); 3connect(cancel_btn_, SIGNAL(clicked()), this, SLOT(OnCancel()));
3 槽函数
头文件中声明了三个槽函数,如下所示:
1public slots: 2 void OnAdd(); 3 void OnSubmit(); 4 void OnCancel();
3.1 OnAdd() 函数
1void AddressBook::OnAdd() 2{ 3 old_name_ = name_line_->text(); // 保存以前的 Name 和 Address 4 old_addr_ = addr_text_->toPlainText(); 5 name_line_->clear(); 6 addr_text_->clear(); 7 8 name_line_->setReadOnly(false); // 设置 QLineEdit 和 QTextEdit 可编辑 9 name_line_->setFocus(Qt::OtherFocusReason); 10 addr_text_->setReadOnly(false); 11 12 add_btn_->setEnabled(false); // 显示 Submit 按钮 和 Cancel 按钮 13 submit_btn_->show(); 14 cancel_btn_->show(); 15}
3.2 OnSubmit() 函数
1void AddressBook::OnSubmit() 2{ 3 QString name = name_line_->text(); 4 QString address = addr_text_->toPlainText(); 5 6 if (name.isEmpty() || address.isEmpty()) { 7 QMessageBox::information(this, tr("Empty Field"), tr("Please enter a name and address.")); 8 return; 9 } 10 11 if (!contacts_.contains(name)) { 12 contacts_.insert(name, address); 13 QMessageBox::information(this, tr("Add Successful"), tr("\"%1\" has been added to your address book.").arg(name)); 14 } else { 15 QMessageBox::information(this, tr("Add Unsuccessful"), tr("Sorry, \"%1\" is already in your address book.").arg(name)); 16 return; 17 } 18 if (contacts_.isEmpty()) { 19 name_line_->clear(); 20 addr_text_->clear(); 21 } 22 23 name_line_->setReadOnly(true); 24 addr_text_->setReadOnly(true); 25 add_btn_->setEnabled(true); 26 submit_btn_->hide(); 27 cancel_btn_->hide(); 28}
3.3 OnCancel() 函数
1void AddressBook::OnCancel() 2{ 3 name_line_->setText(old_name_); 4 name_line_->setReadOnly(true); 5 addr_text_->setText(old_addr_); 6 addr_text_->setReadOnly(true); 7 8 add_btn_->setEnabled(true); // 设置 Add 按钮使能 9 submit_btn_->hide(); // 隐藏 Submit 和 Cancel 按钮 10 cancel_btn_->hide(); 11}
参考资料:
Qt 5.9 | Qt Widgets | Part 2 - Adding Addresses