# Qt学习09：其他基本小控件

category: 后端开发
date: 2023/06/12
status: Published
summary: Qt学习记录：微调框 QSpinBox，时间日期：QDateTime，下拉框 QComboBox，滑块 QSlider 橡皮条 QRubberBand 
tags: Qt
type: Post

**文章首发于我的个人博客：[欢迎大佬们来逛逛](https://www.helloylh.com/)**

# QSpinBox

微调框，可以通过点击增加减小或者输入来调整数据。

![Untitled](Qt%E5%AD%A6%E4%B9%A009%EF%BC%9A%E5%85%B6%E4%BB%96%E5%9F%BA%E6%9C%AC%E5%B0%8F%E6%8E%A7%E4%BB%B6%20a2374c953b52474ea3605c6198aebff3/Untitled.png)

继承自：`QAbstractSpinBox`

同时这个类还具有Double类型的版本。

常用操作：

1. **setRange** ：设置范围
2. **setValue** ：设置初始值
3. **setWrapping** ： 设置可以重复，即到达最大值之后可以到达最小值
4. **setSingleStep** ： 设置每次的移动步数
5. **setPrefix** ：设置前缀

可以通过重写 父类的 `textFromValue` 来自定义数据的类型：

```cpp
class SpinBox :public QSpinBox{
public:
    SpinBox(QWidget* parent=nullptr)
        :QSpinBox(parent){
        strs<<"NULL"<<"一"<<"二"<<"三"<<"四"<<"五"<<"六"<<"日";
    }
    QString textFromValue(int value)const override{

        return strs[value];
    }
private:
    QStringList strs;
};
```

测试如下：

```cpp
void Widget::testQSpinBox()
{
    sp=new SpinBox(this);
    sp->setRange(1,7);

    //设置值
    sp->setValue(5);

    //循环
    sp->setWrapping(true);

    //步长
    sp->setSingleStep(1);

    //前缀后缀
    sp->setPrefix("周");
    sp->setSuffix("上学");

    //特殊显示最小值
    sp->setSpecialValueText("最底部!");

    //显示方式：直接看到，干净的
    qInfo()<<sp->text()<<sp->cleanText();
}
```

---

# QDateTimeEdit

时间日期显示类，并且还可以自己修改时间与日期

![Untitled](Qt%E5%AD%A6%E4%B9%A009%EF%BC%9A%E5%85%B6%E4%BB%96%E5%9F%BA%E6%9C%AC%E5%B0%8F%E6%8E%A7%E4%BB%B6%20a2374c953b52474ea3605c6198aebff3/Untitled%201.png)

它也继承自`QAbstractSpinBox` 本质是一个微调框

常用操作如下： 

使用`QDateTime::currentDateTime()`来获取当前时间日期。

```cpp
void Widget::testQDateTimeEdit()
{
    dt=new QDateTimeEdit(this);

    //设置当前时间
    dt->setDateTime(QDateTime::currentDateTime());

    //设置显示格式
    dt->setDisplayFormat("yyyy年MM月dd日-hh时mm分ss秒");

    //获取某段数值
    qInfo()<<dt->sectionCount()<<dt->sectionAt(2)<<dt->sectionText(dt->sectionAt(2));

    //日历弹出
    dt->setCalendarPopup(true);
}
```

如果我们要做一个钟表，即每时每刻我们的时间都要发生变化，则可以使用一个定时器来对这个控件的显示进行刷新：

```cpp
QTimer* dateTimer=new QTimer(this);
dateTimer->callOnTimeout(this,&Widget::timeGoOn);
dateTimer->start(100);

...

public slots:
	void Widget::timeGoOn()
	{
	    //时间流逝
		   dt->setDateTime(QDateTime::currentDateTime());
	}
```

---

# QComboBox

这是一个**下拉框**，可以下拉选择某个内容

![Untitled](Qt%E5%AD%A6%E4%B9%A009%EF%BC%9A%E5%85%B6%E4%BB%96%E5%9F%BA%E6%9C%AC%E5%B0%8F%E6%8E%A7%E4%BB%B6%20a2374c953b52474ea3605c6198aebff3/Untitled%202.png)

它继承自：`QWidget`

常用操作：

1. **addItem**：添加项目
2. **currentIndex**/**currentText**：获取当前选择的索引或者文本。
3. **insertItem**：给定一个索引，在这个位置插入一个新的项目
4. **itemData**：返回某个索引所代表的数据
5. **setEditable**：可以编辑并且插入
6. **setSizeAdjustPolicy**：可以根据调整下拉框的尺寸，取决于`QComboBox::SizeAdjustPolicy`
7. **setItemData：设置项目所代表的数据。**

常用信号：

1. **currentIndexChanged**：获取当前选择的项目的索引。
2. **currentTextChanged**：获取当前选择的文本

代码：

测试了基本功能，以及可以通过选择某个项目来获得这个项目所代表的数据内容。

```cpp
void Widget::testQComboBox()
{
    cbx=new QComboBox(this);
    //currentData

    QStringList datas{"北京","成都","济南","西安","沈阳","杭州","南京"};
    QStringList itemDatas{"北京市","四川省","山东省","陕西省","辽宁省","浙江省","江苏省"};
    cbx->addItems(datas);
    for (int i=0;i<datas.count();i++){
        cbx->setItemData(i,itemDatas[i]);
    }
		//获取项目映射的值
    connect(cbx,&QComboBox::currentIndexChanged,this,[=](int index){
        qInfo()<<"当前选择: "<<cbx->currentText()<<cbx->currentData().toString();
    });

    //可以编辑插入
    cbx->setEditable(true);

    //可以重复
    //cbx->setDuplicatesEnabled(true);

    //根据内容调整尺寸
    cbx->setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy::AdjustToContents);

    return;
		//基本插入函数
    cbx->addItem("唱跳");
    cbx->addItem("RAP");
    cbx->addItem("篮球");
    cbx->addItem(style()->standardIcon(QStyle::StandardPixmap::SP_DirHomeIcon),"吃鸡");
    cbx->insertSeparator(4);
    cbx->addItems(QStringList{"蔡徐坤","陈立农","范丞丞"});
}
```

---

# QSlider

这是一个**滑动条**。

![Untitled](Qt%E5%AD%A6%E4%B9%A009%EF%BC%9A%E5%85%B6%E4%BB%96%E5%9F%BA%E6%9C%AC%E5%B0%8F%E6%8E%A7%E4%BB%B6%20a2374c953b52474ea3605c6198aebff3/Untitled%203.png)

它继承自：`QAbstractSlider` ，一个抽象滑动类。

同样还有QScrollBar和QDial也都是继承自`QAbstractSlider` 这个抽象类。

他们两个也都是滑动相关的控件。

---

其构造函数：

我们可以通过**Qt::Orientation**来指定滑动条的位置：

1. Qt::Horizontal 是水平的
2. Qt::Vertical 是竖直的。

```cpp
QSlider(Qt::Orientation orientation, QWidget *parent = nullptr)
```

基本函数功能：

1. **setRange**：设置范围
2. **setTickInterval**：设置刻度
3. **setTickPosition**：设置刻度所在的位置

测试代码如下:

```cpp
void Widget::testQSlider()
{
    //Qt::Orientation::Horizontal
    sld=new QSlider(this);
    sld->setGeometry(100,100,20,100);

    sld->setRange(0,100);
    //手动设置值
    //sld->setValue(50);

    connect(sld,&QSlider::valueChanged,this,[=](int value){
        qInfo()<<value;
    });

    auto sbar=new QScrollBar(this);
    sbar->resize(20,100);

    auto dial=new QDial(this);
    dial->setGeometry(200,200,50,50);
}
```

---

# QRubberBand

设置一个橡皮条拖拽控件。

![Untitled](Qt%E5%AD%A6%E4%B9%A009%EF%BC%9A%E5%85%B6%E4%BB%96%E5%9F%BA%E6%9C%AC%E5%B0%8F%E6%8E%A7%E4%BB%B6%20a2374c953b52474ea3605c6198aebff3/Untitled%204.png)

它继承自：`QWidget`

具有以下的基本函数：

1. **move**：设置位置，我们使用此函数来确定选中范围的起始位置。
2. **setGeometry**：设置选中的范围的矩形区域
3. **shape**：显示的样式，使用到QRubberBand::Shape
4. **show**：必须调用show方法才会显示出来

如何实现这个选中的功能？

我们需要用到鼠标的事件：

1. **mousePressEvent**：鼠标点击时记录**起始坐标位置**
2. **mouseMoveEvent**：鼠标移动时**更新**矩形区域
3. **mouseReleaseEvent**：鼠标松开时矩形**消失**

具体实现如下：

```cpp
void Widget::mousePressEvent(QMouseEvent *ev)
{
    //橡皮条拖动
    origin=ev->pos(); //保存开始的位置
    rband->setGeometry(QRect(origin,QSize()));
    rband->show();
}

void Widget::mouseMoveEvent(QMouseEvent *ev)
{
    rband->setGeometry(QRect(origin,ev->pos()).normalized());
}

void Widget::mouseReleaseEvent(QMouseEvent *ev)
{
    rband->hide();
    qInfo()<<rband->geometry();
}
```

小案例：

选中矩形区域，并且**矩形区域内所有的多选框都被选中**：

注意判断是否包含的条件：`geometry`的`contains`方法

```cpp
void Widget::testQRubberBand()
{
    rband=new QRubberBand(QRubberBand::Shape::Line,this);

    //选中按钮
    for (int i=0;i<5;i++){
        for (int j=0;j<5;j++){
            auto chx=new QCheckBox(QString::number(i*5+j),this);
            chx->move(i*50,j*50);
        }
    }
}
void Widget::mousePressEvent(QMouseEvent *ev)
{
    //橡皮条拖动
    origin=ev->pos(); //保存开始的位置
    rband->setGeometry(QRect(origin,QSize()));
    rband->show();
}

void Widget::mouseMoveEvent(QMouseEvent *ev)
{
    rband->setGeometry(QRect(origin,ev->pos()).normalized());
}

void Widget::mouseReleaseEvent(QMouseEvent *ev)
{
    rband->hide();
    qInfo()<<rband->geometry();

    //处理批量点击按钮
    auto lists=this->children();
    for (auto& x:lists){
        auto chx=dynamic_cast<QCheckBox*>(x);
        if (chx && rband->geometry().contains(chx->geometry())){
            chx->setChecked(!chx->isChecked());
        }
    }
}
```