Qt 信号槽的应用(二)

多个信号连接一个槽

        多个信号连接一个槽常用于多个对象处理同一类型的事情,在消费类软件中十分常见,例如黄骑士送餐软件,其UI是由很多按钮或自定义的小部件组成的 ,在这里实现一个简单的点餐界面, 目前只显示点餐名称,还没有加上其他信息。

以下是创建控件以及信号连接的部分:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QGridLayout>
#include <QPushButton>
#include <QMessageBox>

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

    //创建栅格布局
    QGridLayout *layout = new QGridLayout(ui->centralWidget);
    //为主页面设置栅格布局
    ui->centralWidget->setLayout(layout);

    QStringList list_menu = {"热干面", "牛肉拌面", "三鲜豆皮", "油饼包烧麦", "包子",  "面窝", "糊汤粉",  "鸡冠饺", "油酥饼", "欢喜坨", "糯米鸡", "糊汤米酒"};

    //创建菜单按钮,加入栅格布局中,
    int menu_count = list_menu.count();
    for(int i = 0; i < menu_count; i++){
        //创建菜单
        QPushButton *btn = new QPushButton(this);
        //设置可以选中的状态
        btn->setCheckable(true);
        btn->setChecked(false);
        //设置菜单名称
        btn->setText(list_menu[i]);
        //设置按钮大小
        btn->setFixedSize(150,55);
        //加入布局
        layout->addWidget(btn, i/4, i%4);
        //将按钮的点击信号连接到同一个槽
        connect(btn, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
    }

    //最后一行布局中加入label控件
    label = new QLabel(this);
    //布局,插入第3行,第0列,不跨行,跨4列, 左对齐
    layout->addWidget(label, menu_count/4, 0, 1, 4, Qt::AlignLeft);

    //设置最小宽度
    label->setMinimumWidth(150 * 4);
    //文字过多,自动换行
    label->setWordWrap(true);

    //设置按钮样式表
    setStyleSheet("QPushButton{color: white; background:#3465a4; border:none;}"
                  "QPushButton::hover{ background:#729fcf;}"
                  "QPushButton::pressed{ background:#204a87;}"
                  "QPushButton::checked{ background:#204a87;}"
                  );
}

以下是被所有信号连接的槽函数:

void MainWindow::onButtonClicked()
{
    QPushButton* btn = (QPushButton*)sender();
    if (!btn)
        return;

    //获取当前显示的文本
    QStringList list_text = label->text().split(" ");

    if (btn->isChecked()) {
        btn->setIcon(QIcon("://check.png"));
        //追加所选中的早点
        list_text.append( btn->text() );
    } else {
        btn->setIcon(QIcon(""));
        //移除所选中的早点
        list_text.removeOne(btn->text());
    }

    //显示当前选中的早点
    label->setText( list_text.join(" ") );
}

       1. 在代码中,所有按钮的点击事件都连接上了onButtonClicked槽函数,其目的是一致的,为了获取点餐名称。

       2. 在槽函数中使用了sender是为了得知哪个按钮被点击了,直接调用槽函数是得不到按钮对象的,只有通过点击触发进入槽函数才可以获取到按钮对象。

       3. 在实际场景下,仅仅以text属性作为用户数据,过于简陋了。如果需要增加额外的数据,比如编号、单价、份数、折扣等,可以在类中使用数据结构,将控件与其它数据做关联;也可以使用QPushButton的数据接口setUserData和userData方法来处理用户数据。

用户数据接口

        这里推荐使用用户数据接口: setUserData和userData, 其它widgets控件的也基本是一个套路。在对应的控件中存储数据是非常有必要的,可以减少全局的数据结构,也让数据与控件的交互更加便捷。

        上述的例子改造后,我们来看看效果:

 对上面的例子做出了如下修改:

        1. 将界面用设计器实现了一部分,按钮的创建还是在代码中进行。

        

        2. 定义了用户数据结构体,将名称和价格放入其中。

//用户数据
struct breakfastData : QObjectUserData
{
    QString name;
    double price;
};

以下是本例子完整的代码:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLabel>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void onButtonClicked();

private:
    Ui::MainWindow *ui;

    QStringList m_list_menu;
    double m_total_price;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QGridLayout>
#include <QPushButton>
#include <QMessageBox>

//用户数据
struct breakfastData : QObjectUserData
{
    QString name;
    double price;
};

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

    //初始化菜单配置
    const QStringList list_menu = {"热干面", "牛肉拌面", "三鲜豆皮", "油饼包烧麦", "包子",  "面窝", "糊汤粉",  "鸡冠饺", "油酥饼", "欢喜坨", "糯米鸡", "糊汤米酒"};
    const QList<double> list_price = {6.0, 12.0, 8.5, 7.0, 10.0, 2.5, 5.0, 2.5, 2.0, 1.5, 3.0, 3.0};
    int menu_count = list_menu.count();

    //创建菜单按钮,加入栅格布局中,
    for(int i = 0; i < menu_count; i++){
        //创建菜单
        QPushButton *btn = new QPushButton(this);
        //设置可以选中的状态
        btn->setCheckable(true);
        btn->setChecked(false);

        //设置用户数据
        breakfastData* data = new breakfastData;
        data->name = list_menu[i];
        data->price = list_price[i];
        btn->setUserData(Qt::UserRole, data);

        //设置菜单名称
        btn->setText(list_menu[i]);
        //设置按钮大小
        btn->setFixedSize(150,55);
        //加入布局
        ui->gridLayout->addWidget(btn, i/4, i%4);

        //将按钮的点击信号连接到同一个槽
        connect(btn, SIGNAL(clicked()), this, SLOT(onButtonClicked()));
    }

    //初始化数据
    m_list_menu.clear();
    m_total_price = 0.0;

    //设置按钮样式表
    setStyleSheet("QPushButton{color: white; background:#3465a4; border:none;}"
                  "QPushButton::hover{ background:#729fcf;}"
                  "QPushButton::pressed{ background:#204a87;}"
                  "QPushButton::checked{ background:#204a87;}"
                  );
}

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

void MainWindow::onButtonClicked()
{
    QPushButton* btn = (QPushButton*)sender();
    if (!btn)
        return;

    //获取用户数据
    breakfastData* data = (breakfastData*)btn->userData(Qt::UserRole);

    if (btn->isChecked()) {
        btn->setIcon(QIcon("://check.png"));
        //添加此早点
        if (!m_list_menu.contains(data->name)){
            m_list_menu.append(data->name);
            m_total_price += data->price;
        }
    } else {
        btn->setIcon(QIcon(""));
        //移除所选中的早点
        if (m_list_menu.contains(data->name)){
            m_list_menu.removeOne(data->name);
            m_total_price -= data->price;
        }
    }

    //结算
    if (!m_list_menu.isEmpty())
        ui->label_menu->setText( m_list_menu.join(" ") );
    else
        ui->label_menu->setText("");

    //显示总金额
    ui->label_result->setText(QString::number(m_total_price));
}

         

        

        

         

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值