Qt——常用控件
QLCDNumber中有value (double类型)和 intValue两个属性表示值,且他们是联动的,比如value为1.5,inValue就为2。QlineEdit中的inputMask元素上面我们已经使用过了,但是他只能进行简单的验证,正则表达式验证才是经常被使用的输入框数据验证方法。,QApplication对象在main函数调用exec函数后,主线程开始时间循环,依此处理对界面的修改
目录
按钮类控件
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种关于按钮点击后发出的信号,他们的含义分别是:
- clicked():鼠标点击按钮又松开后触发
- clicked(bool):这个一般是选项按钮使用,鼠标点击按钮又松开后触发,还会把点击后选项的状态(是否选中)作为参数传给槽
- pressed():鼠标点击按钮并在松开之前松开就触发
- released():鼠标点击按钮在松开之后触发
- 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);
}

布局管理器
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
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中内置的类,我们可以通过继承者这些类,增加新的属性和方法,组合出新的控件,这些都是可以的。
更多推荐


所有评论(0)