目录

按钮类控件

QPushButton

设置按钮文本

给按钮设置图标

设置按钮快捷键

设置按钮重复触发

QRadioButton

设置选项是否被选中

设置选项是否可以选中

设置选项禁用

设置选项是否排他

将选项分组

题外话-按钮(选项)相关的信号

QCheckBox

 设置选项是否被选中

设置选项是否可以选中

显示类控件

QLabel

设置文本内容

设置label文本的格式

给label添加图片

设置内容(主要指图片)自动拉伸填充整个label

设置文本对齐方式

设置文本自动换行

设置文本缩进

设置内部文本和文本框的边距

设置标签的伙伴

QLCDNumber

题外话——关于Qt中线程修改界面

QProgressBar

QCalendarWidget

输入类控件

QLineEdit

题外话——关于正则表达式验证输入框数据

QTextEdit

QComboBox

QSpinBox

QDateTimeEdit

QDial

QSlider

题外话——给Qslider设置快捷键

多元素控件

QListWidget

QTableWidget

QTreeWidget

容器类控件

QGroupBox

QTabWidget

布局管理器

QVBoxLayout(垂直布局管理器)

QHBoxLayout(水平布局管理器)

QGridLayout

题外话——控件大小策略对布局的影响

QFormLayout(表单布局管理器)

QSpacerItem


按钮类控件

QPushButton

设置按钮文本

ui->pushButton->setText(QString("这是一个按钮"));

给按钮设置图标

  QIcon icon(":/rose.jpg");
  ui->pushButton->setIcon(icon);//给按钮设置图标
  ui->pushButton->setIconSize(QSize(20,20));//设置图标尺寸

设置按钮快捷键

ui->a->setShortcut(QKeySequence("ctrl+w"));//组合键ctrl+w
ui->b->setShortcut(QKeySequence("w"));//字母w是快捷键
ui->c->setShortcut(QKeySequence(Qt::Key_C));//字母C是快捷键
ui->d->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_S));//组合键ctrl+s

设置按钮重复触发

ui->c->setAutoRepeat(true);//开启按钮点击的重复触发
ui->c->setAutoRepeatDelay(1000);//以ms为单位,设置按住多久之后开始重复触发
ui->c->setAutoRepeatInterval(500);//设置开始重复出发后每次间隔多久触发一次

QRadioButton

设置选项是否被选中

ui->a->setChecked(true);

设置选项是否可以选中

ui->a->setCheckable(false);
//即使设置了无法选中,也会发送信号,执行槽

设置选项禁用

ui->a->setEnabled(false);
//完全禁用选项,不会发送信号

设置选项是否排他

ui->a->setAutoExclusive(false);
//默认就是排他的
//排他意味着,一旦选了这个选项,其他的选项不能被选择,已经被选择的会取消选择

将选项分组

分组之后组合组之间的选项互不影响,比如排他性

    QButtonGroup *group1 = new QButtonGroup(this);
    QButtonGroup *group2 = new QButtonGroup(this);

    //把a,b,c按钮添加到组1
    group1->addButton(ui->a);
    group1->addButton(ui->b);
    group1->addButton(ui->c);

    //把d,e,f按钮添加到组2
    group2->addButton(ui->d);
    group2->addButton(ui->e);
    group2->addButton(ui->f);

可见分组是使用QButtonGroup类进行的


题外话-按钮(选项)相关的信号

上面是Qt提供的5种关于按钮点击后发出的信号,他们的含义分别是:

  1. clicked():鼠标点击按钮又松开后触发
  2. clicked(bool):这个一般是选项按钮使用,鼠标点击按钮又松开后触发,还会把点击后选项的状态(是否选中)作为参数传给槽
  3. pressed():鼠标点击按钮并在松开之前松开就触发
  4. released():鼠标点击按钮在松开之后触发
  5. toggled(bool):鼠标点击后如果选项状态改变才被触发(比如从选中变成未选中),并把改变后的状态作为参数传递给槽

QCheckBox

 设置选项是否被选中

ui->a->setChecked(true);

设置选项是否可以选中

ui->a->setCheckable(false);
//即使设置了无法选中,也会发送信号,执行槽

判断选项是否被选中

ui->a->isChecked()

注:QCheckBox默认是不排他


显示类控件

QLabel

设置文本内容

ui->label->setText("haha");

设置label文本的格式

ui->label1->setTextFormat(Qt::PlainText);//纯文本格式
ui->label2->setTextFormat(Qt::RichText);//富文本(html格式)
ui->label3->setTextFormat(Qt::MarkdownText);//Markdown文本格式

ui->label1->setText("这是纯文本");
ui->label2->setText("<b>这是富文本</b>");//会按照html语法解析并显示出相应样式的文本
ui->label3->setText("# 这是Markdown文本");//会按照Markdown语法解析并显示出相应样式的文本

给label添加图片

QPixmap pix(":/rose.jpg");
label->setPixmap(pix);

设置内容(主要指图片)自动拉伸填充整个label

label->setScaledContents(true);

设置文本对齐方式

ui->label_1->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);//水平垂直居中
ui->label_2->setAlignment(Qt::AlignRight);//靠右对齐
ui->label_3->setAlignment(Qt::AlignLeft | Qt::AlignTop);//左上对齐
ui->label_4->setAlignment(Qt::AlignBottom);//靠下对齐

效果如下:


设置文本自动换行

 ui->label_1->setWordWrap(true);

一般来说文本长度超过label的width后就会显示不出来,自动换行就是让超出的文本在下一行显示。


设置文本缩进

ui->label_1->setIndent(20);// 单位是像素

如果设置了换行,每一行都会有缩进


设置内部文本和文本框的边距

ui->label_1->setMargin(10);//单位是像素

文本内容上下左右方向和文本框的距离


设置标签的伙伴

ui->c->setText("&A");//把标签文本设置成"&"+字母
ui->c->setBuddy(ui->a);//设置标签的伙伴为一个按钮,这样可以通过Alt+A的方式激活标签的伙伴即该按钮

注:QLabel没有滚动条


QLCDNumber

这里我们只展示一个使用QLCDNumber的倒计时示例:

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


    timer = new QTimer(this);//创建定时器对象,该定时器自带一种信号timout()
    ui->number->display(10);//设置QLCDNumber的值为10

    connect(timer,&QTimer::timeout,this,&Widget::handler);//把定时器的信号和槽关联起来

    timer->start(1000);//让定时器开始发信号,并设置信号发射的时间间隔,ms为单位
}

void Widget::handler()
{
    ui->number->display(ui->number->intValue()-1);//每隔1秒减一
    if(ui->number->intValue() == 0)
    {
        timer->stop();//让定时器停止发送信号
    }
}

下面是他的其他主要属性,要设置的时候直接使用set+属性名(首字母大写即可):

注:QLCDNumber中有value (double类型)和 intValue两个属性表示值,且他们是联动的,比如value为1.5,inValue就为2。设置QLCDNumber中value 和 intValue的⽅法名字为display , 而不是setValue或者setIntValue。


题外话——关于Qt中线程修改界面

在Qt中为了防止线程干扰,只有主线程才能修改界面(但可以创建线程),QApplication对象在main函数调用exec函数后,主线程开始时间循环,依此处理对界面的修改任务这意味着他是单线程处理所有事件的,一但某事件花费较长时间就会阻塞,因此线程+sleep实现倒计时的方法行不通。

QProgressBar

通过一个进度条程序来了解它的基本使用,要设置的时候直接使用set+属性名(首字母大写即可)

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

    //进度条对于样式的设置有特定的格式就像下面
    ui->progressBar->setStyleSheet("QProgressBar::chunk {background-color: #05B8CC;}");
    timer = new QTimer(this);//创建定时器对象,该定时器自带一种信号timout()
    connect(timer,&QTimer::timeout,this,&Widget::handler);//把定时器的信号和槽关联起来

    timer->start(100);//让定时器开始发信号,并设置信号发射的时间间隔
}

void Widget::handler()
{
    ui->progressBar->setValue(ui->progressBar->value()+1);//让进度条的值+1
    if(ui->progressBar->value() == 0)
    {
        timer->stop();//让定时器停止发送信号
    }
}

下面是它的主要属性:


QCalendarWidget

通过一个示例我们使用一下QCalendarWidget:

//这是日期选择改变的槽函数
void Widget::on_calendarWidget_selectionChanged()
{
    //获取当前选择的日期
    QDate date = ui->calendarWidget->selectedDate();
    //将当前选中的日期显示到标签上
    ui->label->setText(date.toString());
}

下面是QCalendarWidget的一些主要属性和它自带的信号,可以查看文档进行使用:


输入类控件

QLineEdit

下面是其主要属性:

下面是一个例子:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
     
    ui->lineEdit_id->setPlaceholderText("请输入用户名");//设置输入框为空的提示
    ui->lineEdit_id->setClearButtonEnabled(true);//启用清空按钮
    ui->lineEdit_id->setMaxLength(5);

    ui->lineEdit_pass->setPlaceholderText("请输入密码");//设置输入框为空的提示
    ui->lineEdit_pass->setClearButtonEnabled(true);//启用清空按钮
    ui->lineEdit_pass->setEchoMode(QLineEdit::Password);//设置文本的显示方式是密码方式,用符号代替用户输入的内容呈现

    ui->lineEdit_phone->setPlaceholderText("请输入电话号码");//设置输入框为空的提示
    ui->lineEdit_phone->setClearButtonEnabled(true);//启用清空按钮
    ui->lineEdit_phone->setInputMask("000-0000-0000");//设置内容格式约束,0表示该位置只能是数字
}
//设置按钮的点击事件
void Widget::on_pushButton_clicked()
{
    //获取性别信息
    QString gender = ui->radioButton_male->isChecked() ? "男":"女";

    //打印输入框的信息
    qDebug()<<"姓名"<<ui->lineEdit_id->text();
    qDebug()<<"密码"<<ui->lineEdit_pass->text();
    qDebug()<<"电话"<<ui->lineEdit_phone->text();
    qDebug()<<"性别"<<gender;
}

下面是另一个例子:

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

    //设置两个输入框为密码模式,防止密码回显
    ui->lineEdit->setEchoMode(QLineEdit::Password);
    ui->lineEdit_2->setEchoMode(QLineEdit::Password);
}
//比较两个输入框的密码是否相等
void Widget::compare()
{
    QString x1 = ui->lineEdit->text();
    QString x2 = ui->lineEdit_2->text();

    if(x1.isEmpty() && x2.isEmpty())
    {
        ui->label->setText("当前输入为空");
    }
    else if(x1 == x2)
    {
        ui->label->setText("两次密码一致");
    }
    else
    {
        ui->label->setText("两次密码不一致");
    }
}
//设置输入框的文本改变信号对应的槽
void Widget::on_lineEdit_textEdited(const QString &arg1)
{
    compare();
}
//设置输入框的文本改变信号对应的槽
void Widget::on_lineEdit_2_textEdited(const QString &arg1)
{
    compare();
}


题外话——关于正则表达式验证输入框数据

QlineEdit中的inputMask元素上面我们已经使用过了,但是他只能进行简单的验证,正则表达式验证才是经常被使用的输入框数据验证方法。

正则表达式是⼀种在计算机中常用的, 使用特殊字符描述⼀个字符串的特征的机制 。 在进⾏字
符串匹配时非常有用。 正则表达式的语法还比较复杂, ⼀般都是随用随查, 不需要背下来:
正则表达式文档:https://learn.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2008/ae5bf541(v=vs.90)?redirectedfrom=MSDN
正则表达式在线工具: https://regextester.buyaocha.com/

接下来是在Qt中使用简单正则表达式进行手机号码输入验证的示例程序:

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

    //创建一个正则表达式
    QRegExp regexp("^1\\d{10}$");//^1表示开头必须是1,\d{10}表示接下来是10个数字(多加一个\表示转义),$是结束符

    //创建一个验证器并设置进输入框控件中,验证器的生命周期个输入框一样
    ui->lineEdit->setValidator(new QRegExpValidator(regexp));
}

//设置输入框文本数据改变的信号对应的槽函数
void Widget::on_lineEdit_textChanged(const QString &arg1)
{
    QString x = arg1;
    int pos;

    //获取lineEdit中的验证器并且调用验证函数,成功则返回true,失败则返回false并把第一个不匹配的位置返回到pos中。
    if(ui->lineEdit->validator()->validate(x,pos) == QValidator::Acceptable)
    {
        //如果匹配了就解开按钮限制
        ui->pushButton->setEnabled(true);
    }
    else
    {
        //不匹配就禁用按钮
        ui->pushButton->setEnabled(false);
    }

}


QTextEdit

QTextEdit和QPlainTextEdit属性和信号差不多,只不过QTextEdit支持富文本(也就是html和MarkDown等语法)而QPlainTextEdit只支持纯文本

下面是相关属性和QTextEdit自带信号:

下面是写的一些测试信号的代码:

void Widget::on_textEdit_textChanged()
{
    qDebug()<<"当前文本内容"<<ui->textEdit->toPlainText();
}

void Widget::on_textEdit_cursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    qDebug()<<"光标位置"<<cursor.position();
}

void Widget::on_textEdit_selectionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();
    qDebug()<<"选中的内容变成了:"<<cursor.selectedText();
}

void Widget::on_textEdit_undoAvailable(bool b)
{
      qDebug()<<"可以进行undo操作了?"<<b;
}

void Widget::on_textEdit_redoAvailable(bool b)
{
    qDebug()<<"可以进行redo操作了?"<<b;
}

void Widget::on_textEdit_copyAvailable(bool b)
{
    qDebug()<<"选中了?"<<b;
}

注意:QTextEdit获取文本的方式是toPlainText(),toHtmlText()等,而不是text()。


QComboBox

下面是QComboBox的核心属性,方法,以及信号

下面是一个使用的例子:

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

    ui->comboBox_1->addItem("麦辣鸡腿堡");
    ui->comboBox_1->addItem("牛肉堡");
    ui->comboBox_1->addItem("虾堡");

    ui->comboBox_2->addItem("薯条");
    ui->comboBox_2->addItem("土豆");
    ui->comboBox_2->addItem("蛋挞");

    ui->comboBox_3->addItem("可乐");
    ui->comboBox_3->addItem("雪碧");
}

void Widget::on_pushButton_clicked()
{
    qDebug()<<"汉堡"<<ui->comboBox_1->currentText();
    qDebug()<<"小食"<<ui->comboBox_2->currentText();
    qDebug()<<"可乐"<<ui->comboBox_3->currentText();
}

在大多数情况中,我们是从配置文件中读取选项的而不是写死的,所以再展示一个文件读取设置选项的例子:


QSpinBox

QspinBox用于整数,QDoubleSpinBox用于小数,用法都是类似的,这里我们只讲QSpinBox。

下面是QSpinBox的核心属性和信号:

下面是使用QSpinBox的代码示例:

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

    ui->comboBox->addItem("可乐");
    ui->comboBox->addItem("雪碧");

    //设置微调范围
    ui->spinBox->setRange(1,5);
    //设置初始值
    ui->spinBox->setValue(1);
}

void Widget::on_pushButton_clicked()
{
    qDebug()<<"您选择的是"<<ui->comboBox->currentText()<<ui->spinBox->value();
}


QDateTimeEdit

下面是其核心属性与信号:

下面是简单的使用示例:

void Widget::on_pushButton_clicked()
{
    QDateTime x1 = ui->dateTimeEdit_1->dateTime();
    QDateTime x2 = ui->dateTimeEdit_2->dateTime();

    int days = x1.daysTo(x2);
    int sec = x1.secsTo(x2);

    int hours =(sec/3600)%24;

    ui->label->setText(QString("爱你已经持续了")+QString::number(days)+QString("天零")+QString::number(hours)+QString("小时"));
}

计算时间差的注意事项:

上面我们使用的是QDateTime中的daysTo函数计算两个日期之间隔了多少天,但是我们会发现,像(2000 1/1 23:55 —— 2000 1/2 00:01)也会被当作隔了一天(实际上不到一个小时),这个问题官方文档中也有提及。解决方法就是不使用daysTo函数计算间隔天数而是先使用secsTo计算出秒数,再根据秒数计算天数


QDial

下面是QDial的主要属性和信号:

下面是对QDial的简单使用:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->dial->setWrapping(true);//设置可循环调整
    ui->dial->setRange(0,100);//设置数值范围
    ui->dial->setValue(100);//设置初始数值
    ui->dial->setNotchesVisible(true);//设置显示刻度线
}


//旋钮数值改变信号对应的槽函数
void Widget::on_dial_valueChanged(int value)
{
    //设置窗口的不透明度
    this->setWindowOpacity((double)value /100);
}


QSlider

下面是QSlider的主要属性:

下面协议一个通过滚动条控制窗口大小的示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->horizontalSlider->setMinimum(100);//设置最小值
    ui->horizontalSlider->setMaximum(2000);//设置最大值
    ui->horizontalSlider->setValue(774);//设置初始值
    ui->horizontalSlider->setSingleStep(20);//设置每移动一步增加/减少多少数值

    ui->verticalSlider->setMinimum(100);
    ui->verticalSlider->setMaximum(2000);
    ui->verticalSlider->setValue(530);
    ui->verticalSlider->setSingleStep(20);
}

//设置水平条值变化对应的槽信号
void Widget::on_horizontalSlider_valueChanged(int value)
{
    QRect rect = this->geometry();
    this->setGeometry(rect.x(),rect.y(),ui->horizontalSlider->value(),rect.height());
}
//设置垂直条值变化对应的槽信号
void Widget::on_verticalSlider_valueChanged(int value)
{
    QRect rect = this->geometry();
    this->setGeometry(rect.x(),rect.y(),rect.width(),ui->verticalSlider->value());
}


题外话——给Qslider设置快捷键

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QShortcut* add = new QShortcut(this);//创建快捷键对象
    add->setKey(QKeySequence("+"));//设置快捷键
    QShortcut* sub = new QShortcut(this);
    sub->setKey(QKeySequence("-"));

    //初始化滚动条
    ui->horizontalSlider->setValue(50);
    ui->horizontalSlider->setRange(0,100);

    //关联快捷键激活信号和槽函数
    connect(add,&QShortcut::activated,this,&Widget::Add);
    connect(sub,&QShortcut::activated,this,&Widget::Sub);
}

void Widget::Add()
{
    ui->horizontalSlider->setValue((ui->horizontalSlider->value())+5);
    ui->label->setText(QString("当前数值为:")+QString::number(ui->horizontalSlider->value()));
}

void Widget::Sub()
{
    ui->horizontalSlider->setValue((ui->horizontalSlider->value())-5);
    ui->label->setText(QString("当前数值为:")+QString::number(ui->horizontalSlider->value()));
}

这样一来按下+,-就可以让滚动条移动了


多元素控件

多元素控件里面包含的内容是都是一个个“item”对象

QListWidget

下面是QListWidget的主要属性,方法,信号:

下面是使用QListWidget的示例(列表中的元素是QListWidget类型):

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

    //开启鼠标追踪,让QListWidget跟踪鼠标移动事件
    ui->listWidget->setMouseTracking(true);

    //添加固定的列表项,这里使用了两种添加方式
    ui->listWidget->addItem("原神");
    ui->listWidget->addItem(new QListWidgetItem("c++"));
}

//给添加按钮设置槽函数
void Widget::on_pushButton_add_clicked()
{
    QString temp = ui->lineEdit->text();
    if(!temp.isEmpty())
    {
        //添加元素
        ui->listWidget->addItem(temp);
    }
}
//给删除按钮设置槽函数
void Widget::on_pushButton_delete_clicked()
{
    int row = ui->listWidget->currentRow();
    if(row>=0)
    //按照行号删除元素
    ui->listWidget->takeItem(row);
}

void Widget::on_listWidget_itemEntered(QListWidgetItem *item)
{
     qDebug()<<"鼠标悬停在:"<<item->text();
}

void Widget::on_listWidget_itemDoubleClicked(QListWidgetItem *item)
{
    qDebug()<<"点两次:"<<item->text();
}

void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
    qDebug()<<"选了不同的元素";
}


QTableWidget

下面是QTableWidget的主要方法和信号:

下面是QTableWidgetItem的主要方法:

下面是QTableWidget的示例(列表中的元素是QTableWidget类型):

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

    //添加两行
    ui->tableWidget->insertRow(0);
    ui->tableWidget->insertRow(1);

    //添加三列
    ui->tableWidget->insertColumn(0);
    ui->tableWidget->insertColumn(1);
    ui->tableWidget->insertColumn(2);

    //给每个列设置表头
    ui->tableWidget->setHorizontalHeaderItem(0,new QTableWidgetItem("学号"));
    ui->tableWidget->setHorizontalHeaderItem(1,new QTableWidgetItem("姓名"));
    ui->tableWidget->setHorizontalHeaderItem(2,new QTableWidgetItem("分数"));

    //给表格第一行添加元素
    ui->tableWidget->setItem(0,0,new QTableWidgetItem("001"));
    ui->tableWidget->setItem(0,1,new QTableWidgetItem("张三"));
    ui->tableWidget->setItem(0,2,new QTableWidgetItem("55"));
    //给表格第二行添加元素
    ui->tableWidget->setItem(1,0,new QTableWidgetItem("002"));
    ui->tableWidget->setItem(1,1,new QTableWidgetItem("李四"));
    ui->tableWidget->setItem(1,2,new QTableWidgetItem("99"));

}

void Widget::on_pushButton_addrow_clicked()
{
    int rowcount = ui->tableWidget->rowCount();
    ui->tableWidget->insertRow(rowcount);
}

void Widget::on_pushButton_delrow_clicked()
{
    int rowcount = ui->tableWidget->currentRow();
    ui->tableWidget->removeRow(rowcount);
}

void Widget::on_pushButton_addcol_clicked()
{
    //获取输入框的数据
    QString temp;
    temp = ui->lineEdit->text();

    if(!temp.isEmpty())
    {
        //添加新的列
       int colcount = ui->tableWidget->columnCount();
       ui->tableWidget->insertColumn(colcount);
       //添加列的表头
       ui->tableWidget->setHorizontalHeaderItem(colcount,new QTableWidgetItem(temp));
    }
}

void Widget::on_pushButton_delcol_clicked()
{
    int colcount = ui->tableWidget->currentColumn();
    ui->tableWidget->removeColumn(colcount-1);
}


QTreeWidget

下面是QTreeWidget 和 QTreeWidgetItem (QTreeWidget中的元素类型)的核心属性,信号,方法:

QTtreeWidget的根节点只能修改名字而不能删除,并且QTtreeWidget只能用来操作顶层节点(也就是根节点下面的第一层节点),而添加或删除普通节点是通过QTreeWidgetItem节点本身进行操作的

下面是对QTreeWidget的使用示例:

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

    //设置根节点(也就是树)的名称
    ui->treeWidget->setHeaderLabel("动物");

    //创建三个顶层节点
    QTreeWidgetItem* top1 = new QTreeWidgetItem();
    top1->setText(0,"狗");//给顶层节点设置文本/图片,可以设置多个文本/图片
    ui->treeWidget->addTopLevelItem(top1);//添加顶层节点

    QTreeWidgetItem* top2 = new QTreeWidgetItem();
    top2->setText(0,"猫");
    ui->treeWidget->addTopLevelItem(top2);

    QTreeWidgetItem* top3 = new QTreeWidgetItem();
    top3->setText(0,"鱼");
    ui->treeWidget->addTopLevelItem(top3);

    //给每个节点新增一些子节点
    QTreeWidgetItem* child1 = new QTreeWidgetItem();
    child1->setText(0,"金毛");
    top1->addChild(child1);

    QTreeWidgetItem* child2 = new QTreeWidgetItem();
    child2->setText(0,"哈巴狗");
    top1->addChild(child2);

    QTreeWidgetItem* child3 = new QTreeWidgetItem();
    child3->setText(0,"布偶猫");
    top2->addChild(child3);

    QTreeWidgetItem* child4 = new QTreeWidgetItem();
    child4->setText(0,"大毛毛");
    top2->addChild(child4);
}

void Widget::on_pushButton_addtop_clicked()
{
    //获取输入框中的内容
    QString temp = ui->lineEdit->text();
    if(!temp.isEmpty())
    {
        QTreeWidgetItem* top1 = new QTreeWidgetItem();
        top1->setText(0,temp);//给顶层节点设置文本/图片,可以设置多个文本/图片
        ui->treeWidget->addTopLevelItem(top1);//添加顶层节点
    }
}

void Widget::on_pushButton_addchild_clicked()
{
    //获取当前选中的节点
    QTreeWidgetItem* item = ui->treeWidget->currentItem();

    //获取输入框中的内容
    QString temp = ui->lineEdit->text();

    //创建一个新节点
    QTreeWidgetItem* child = new QTreeWidgetItem();
    child->setText(0,temp);
    item->addChild(child);
}

void Widget::on_pushButton_delete_clicked()
{
    //获取当前选中的节点
    QTreeWidgetItem* item = ui->treeWidget->currentItem();

    //获取当前选中节点的父节点
    QTreeWidgetItem* parent = item->parent();

    //如果当前选中的节点是顶层节点
    if(parent == nullptr)
    {
        //获取当前节点在顶层中的下标
        int index = ui->treeWidget->indexOfTopLevelItem(item);
        //删除该节点
        ui->treeWidget->takeTopLevelItem(index);
    }
    //如果当前选中的节点是普通节点
    else
    {
        //删除该子节点
        parent->removeChild(item);
    }

}


容器类控件

容器类控件里面包含的是其它控件,被包含的控件的父元素会变成容器类控件而不是QWidget了,并且被容器类控件分割后,一些本来关联的控件会变得不关联,比如多个Radio Button,本来是只能选一个(即他们是有关联的),一但被容器类控件分割后被分割的控件就自成一组

QGroupBox

下面是QGroupBox的核心属性以及使用示例:


QTabWidget

QTabWidget里包含的是若干个QWidget控件,相当于若干个新的窗口

下面是QTabWidget的核心属性和信号:

下面是QTabWidget的使用示例:

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

    //让标签页显示关闭按钮,点击按钮可以发出关闭信号
    ui->tabWidget->setTabsClosable(true);

    //在标签页1创建一个label
    QLabel* label = new QLabel(ui->tab);
    label->setText("这是第一个标签页");
    label->resize(200,50);
    //设置标签页1的标题
    ui->tabWidget->setTabText(0,"标签页0");

    //在标签页1创建一个label
    QLabel* label2 = new QLabel(ui->tab_2);
    label2->setText("这是第一个标签页");
    label2->resize(200,50);
    //设置标签页1的标题
    ui->tabWidget->setTabText(1,"标签页1");
}

//添加新的标签页
void Widget::on_pushButton_clicked()
{
    //获取当前标签页的数量
    int n = ui->tabWidget->count();
    //创建新窗口
    QWidget* newtab = new QWidget(ui->tabWidget);
    //将窗口添加到标签页并设置标签页的标题
    ui->tabWidget->addTab(newtab,QString("标签页")+QString::number(n));
    //给新的标签页添加label
    QLabel * label = new QLabel(newtab);
    label->setText(QString("这是第")+QString::number(n)+QString("个标签页"));
    label->resize(200,50);

    //设置当前选中的标签页为新标签页
    ui->tabWidget->setCurrentIndex(n);
}
//删除选中的标签页
void Widget::on_pushButton_2_clicked()
{
    //获取当前选中的标签页的下标
    int index = ui->tabWidget->currentIndex();
    //删除当前标签页
    ui->tabWidget->removeTab(index);
}
//设置关闭信号关联的槽
void Widget::on_tabWidget_tabCloseRequested(int index)
{
    //删除当前标签页
    ui->tabWidget->removeTab(index);
}


布局管理器

之前使用Qt在界面上创建的控件, 都是通过"绝对定位"的方式来设定的。 也就是每个控件所在的位置, 都需要计算坐标, 最终通过 setGeometry 或者 move 方式摆放过去.这种设定方式其实并不方便. 尤其是界面如果内容比较多, 不好计算 . 而且⼀个窗口大小往往是可以调整 的, 按照绝对定位的方式, 也 无法自适应窗口大小
因此 Qt 引入 "布局管理器" (Layout) 机制, 来解决上述问题布局管理器内的控件的大小间距等是自动调整的,而且可以自适应窗口大小 。不过布局管理器相当于一个容器类控件,其中的控件和外界控件并不关联。

QVBoxLayout(垂直布局管理器)

下面是关于QVLayout的主要属性:

下面是使用示例:
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    QPushButton *a = new QPushButton("按钮1");
    QPushButton *b = new QPushButton("按钮2");
    QPushButton *c = new QPushButton("按钮3");
    
    //创建布局管理器
    QVBoxLayout* layout = new QVBoxLayout();
    //给布局管理器添加元素
    layout->addWidget(a);
    layout->addWidget(b);
    layout->addWidget(c);
    
    //给当前窗口添加布局管理器
    this->setLayout(layout);
}

注意:一个窗口默认只有一个布局管理器的时候才能起作用。并且如果我们通过QtDesigner方式添加布局管理器的话是默认也不起效果的,实际上,通过QtDesigner方式创建一个布局管理器相当于先创建一个新的Widget然后在Widget里面创建布局管理器,这样对于顶层窗口来说是没有布局管理器的,因此无效,虽然Designer不在对象树显示这一点,我们从xml文件中也可以看出:


QHBoxLayout(水平布局管理器)

特性和垂直布局管理器相同,我们直接写一个例子:

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


    QPushButton *a = new QPushButton("按钮1");
    QPushButton *b = new QPushButton("按钮2");
    QPushButton *c = new QPushButton("按钮2");
    QPushButton *d = new QPushButton("按钮2");

    //创建水平布局管理器
    QHBoxLayout* layout1 = new QHBoxLayout();
    layout1->addWidget(c);
    layout1->addWidget(d);

    //创建垂直布局管理器
    QVBoxLayout* layout2 = new QVBoxLayout();
    //给垂直布局管理器添加元素
    layout2->addWidget(a);
    layout2->addWidget(b);
    layout2->addLayout(layout1);

    //给当前窗口添加布局管理器
    this->setLayout(layout2);
}

注意:布局管理器之间可以嵌套,上面的例子就是用垂直布局管理器嵌套了水平布局管理器。


QGridLayout

QVBoxLayout只是垂直方向上的布局管理,QHBoxLayout只是水平上的布局管理,为了实现二维布局管理,我在QHBoxLayout中使用了布局管理器嵌套的方式,但是这样做未免过于繁琐。QGridLayout就是解决这个问题的二维布局管理器

下面是它的主要属性:

下面是使用的例子:

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


    QPushButton *a = new QPushButton("按钮1");
    QPushButton *b = new QPushButton("按钮2");
    QPushButton *c = new QPushButton("按钮2");
    QPushButton *d = new QPushButton("按钮2");

    //创建Grid布局管理器
    QGridLayout* layout = new QGridLayout();
    layout->addWidget(a,0,0);//添加控件的时候指明控件处在管理器中的位置坐标
    layout->addWidget(b,1,0);
    layout->addWidget(c,2,0);
    layout->addWidget(d,2,100);

    //给当前窗口添加布局管理器
    this->setLayout(layout);
}

我在添加d按钮的时候特地写了100这个很大的数字,但是d按钮并没有跑到很远的地方,因此,我们指定的坐标只是指定相对顺序而不是整整意义上的坐标

下面是关于水平拉伸系数的使用示例:

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

    QPushButton *a = new QPushButton("按钮1");
    QPushButton *b = new QPushButton("按钮2");
    QPushButton *c = new QPushButton("按钮3");
    QPushButton *d = new QPushButton("按钮4");
    QPushButton *e = new QPushButton("按钮5");
    QPushButton *f = new QPushButton("按钮6");

    //创建Grid布局管理器
    QGridLayout* layout = new QGridLayout();
    layout->addWidget(a,0,0);//添加控件的时候指明控件处在管理器中的位置坐标
    layout->addWidget(b,0,1);
    layout->addWidget(c,0,2);
    layout->addWidget(d,1,0);
    layout->addWidget(e,1,1);
    layout->addWidget(f,1,2);

    //设置某一列的水平拉升系数(列与列之中控件的宽度比)
    layout->setColumnStretch(0,0);
    layout->setColumnStretch(1,1);
    layout->setColumnStretch(2,2);

    //给当前窗口添加布局管理器
    this->setLayout(layout);
}


layout->setColumnStretch(0,0);并不代表比例为0,而是代表这一列的控件不参与按照比例变化的过程

下面是关于垂直拉伸系数的使用示例:

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

    QPushButton *a = new QPushButton("按钮1");
    QPushButton *b = new QPushButton("按钮2");
    QPushButton *c = new QPushButton("按钮3");
    QPushButton *d = new QPushButton("按钮4");
    QPushButton *e = new QPushButton("按钮5");
    QPushButton *f = new QPushButton("按钮6");

    //创建Grid布局管理器
    QGridLayout* layout = new QGridLayout();
    layout->addWidget(a,0,0);//添加控件的时候指明控件处在管理器中的位置坐标
    layout->addWidget(b,0,1);
    layout->addWidget(c,0,2);
    layout->addWidget(d,1,0);
    layout->addWidget(e,1,1);
    layout->addWidget(f,1,2);

    //设置某一行的垂直拉升系数(行与行之中控件的宽度比)
    layout->setRowStretch(0,0);
    layout->setRowStretch(1,1);

    //给当前窗口添加布局管理器
    this->setLayout(layout);
}


题外话——控件大小策略对布局的影响

我们发现,上面垂直拉伸系数的设置完全没有效果,因为按钮(其它控件一般也有这种情况)的大小策略会影响布局

我们修改代码:

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

    QPushButton *a = new QPushButton("按钮1");
    QPushButton *b = new QPushButton("按钮2");
    QPushButton *c = new QPushButton("按钮3");
    QPushButton *d = new QPushButton("按钮4");
    QPushButton *e = new QPushButton("按钮5");
    QPushButton *f = new QPushButton("按钮6");

    //创建Grid布局管理器
    QGridLayout* layout = new QGridLayout();
    layout->addWidget(a,0,0);//添加控件的时候指明控件处在管理器中的位置坐标
    layout->addWidget(b,0,1);
    layout->addWidget(c,0,2);
    layout->addWidget(d,1,0);
    layout->addWidget(e,1,1);
    layout->addWidget(f,1,2);

    //设置按钮的尺寸措施
    a->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    b->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    c->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    d->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    e->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    f->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);

    //设置某一行的垂直拉升系数(行与行之中控件的宽度比)
    layout->setRowStretch(0,0);
    layout->setRowStretch(1,1);

    //给当前窗口添加布局管理器
    this->setLayout(layout);
}

有效果了。


QFormLayout(表单布局管理器)

本质上是QGridLayout的特殊情况,用于创建表单类型的布局。

直接写一个使用示例:

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


    QLabel* label1 = new QLabel("姓名");
    QLabel* label2 = new QLabel("电话");
    QLineEdit* line1 = new QLineEdit();
    QLineEdit* line2 = new QLineEdit();
    //创建表单布局管理器
    QFormLayout* layout = new QFormLayout();
    layout->addRow(label1,line1);//每次添加一行,每行由两个部分组成
    layout->addRow(label2,line2);

    //给当前窗口添加布局管理器
    this->setLayout(layout);
}


QSpacerItem

使用布局管理器的时候, 可能需要在控件之间, 添加⼀段空白。 就可以使用QSpacerItem来表示。
下面是使用示例:
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);


    QPushButton* a = new QPushButton();
    QPushButton* b = new QPushButton();
    QPushButton* c = new QPushButton();
    QPushButton* d = new QPushButton();
    //创建表单布局管理器
    QHBoxLayout* layout = new QHBoxLayout();
    //给当前窗口添加布局管理器
    this->setLayout(layout);

    //创建Spacer对象
    QSpacerItem* sp = new QSpacerItem(200,200);

    layout->addWidget(a);
    layout->addWidget(b);
    layout->addWidget(c);
    layout->addSpacerItem(sp);//添加空白
    layout->addWidget(d);
}


每个控件都是Qt中内置的类,我们可以通过继承者这些类,增加新的属性和方法,组合出新的控件,这些都是可以的。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐