【Qt】常用控件

news2024/12/23 15:07:25

文章目录

  • QWidget
    • enabled
    • geometry
    • window frame
    • windowTitle
    • windowIcon
    • qrc资源管理
    • windowOpacity
    • cursor
    • font
    • toolTip
    • focusPolicy
    • styleSheet
  • 按钮类
    • PushButton
    • RadioButton
    • CheckBox
    • Signals
  • 显示类
    • Label
    • LCDNumber
    • ProgressBar
    • Calendar
  • 输入类
    • LineEdit
    • TextEdit
    • ComboBox
    • SpinBox
    • DateTimeEdit
    • Dial
    • Slider
    • 快捷键
  • 多元素控件
    • ListWidget
    • TableWidget
    • TreeWidget
  • 容器类控件
    • GroupBox
    • TabWidget
  • 布局管理器
    • 垂直布局
    • 水平布局
    • 网格布局
    • 表单布局


QWidget

所有控件的父类

enabled

APIIntro
isEnabled()返回控件是否可用,可用为true,不可用为false
setEnable(bool)设置控件的可用状态,可用为true,不可用为false

geometry

位置与尺寸,位置指的是控件在父控件中的坐标。

  • x 横坐标
  • y 纵坐标
  • width 宽度
  • height 高度

image-20240627094751437

APIIntro
geometry()获取到控件的位置和尺寸,返回结果是⼀个QRect
setGeometry(QRect)使用QRect对象,设置控件的位置和尺寸
setGeometry(int x,int y, int width,int height)分四个属性设置控件的位置和尺寸

QRect: 保存位置和尺寸的对象,包含了x, y, width, height,其中x, y是控件左上⻆的坐标。其接口setX(), setY()只是修改控件左上角点的坐标,width和height会随之改变。

示例:点击操控某个控件的尺寸不变,上下左右移动

void Widget::on_pushButton_up_clicked()
{
    QRect rect = ui->target->geometry();
    ui->target->setGeometry(rect.x(), rect.y()-20, rect.width(), rect.height());
}

void Widget::on_pushButton_down_clicked()
{
    QRect rect = ui->target->geometry();
    ui->target->setGeometry(rect.x(), rect.y()+20, rect.width(), rect.height());
}

void Widget::on_pushButton_left_clicked()
{
    QRect rect = ui->target->geometry();
    ui->target->setGeometry(rect.x()-20, rect.y(), rect.width(), rect.height());
}

void Widget::on_pushButton_right_clicked()
{
    QRect rect = ui->target->geometry();
    ui->target->setGeometry(rect.x()+20, rect.y(), rect.width(), rect.height());
}

window frame

image-20240626115139429

  • 如果widget作为⼀个窗⼝(带有标题栏,最⼩化,最⼤化,关闭按钮),那么在计算尺⼨和坐标的
    时候就有两种算法.包含windowframe和不包含windowframe.
  • 其中x(),y(),frameGeometry(),pos(),move()都是按照包含windowframe的⽅式来计算
    的.
  • 其中geometry(),width(),height(),rect(),size()则是按照不包含windowframe的⽅式来计
    算的.
  • 当然,如果⼀个不是作为窗⼝的widget,上述两类⽅式得到的结果是⼀致的.

windowTitle

控件的窗口标题

APIIntro
windowTitle()获取控件的窗口标题
setWindowTitle(const QString& title)设置控件的窗口标题

上述设置操作针对不同的widget可能会有不同的⾏为。如果是顶层widget(独⽴窗⼝),这个操作才会有效。

windowIcon

控件的窗口图标

APIIntro
windowIcon()获取控件的窗口图标,返回QIcon对象
setWindowIcon(const QIcon& icon)设置控件的窗口图标

同windowTitle,上述操作仅针对顶层widget有效

对于自定义图标,可用先创建一个QPixmap对象,导入自定义图片(qrc),再用该对象创建QIcon

qrc资源管理

  1. 右键项⽬,创建⼀个QtResourceFile(qrc⽂件),⽂件名随意起(不要带中⽂),此处叫做resource.qrc。在qrc编辑器中,添加前缀,表示图片在Qt项目中的相对路径,供代码中使用。添加资源文件,添加的⽂件必须是在qrc⽂件的同级⽬录,或者同级目录的子目录。

image-20240626113223036

  1. 将图片导入qrc后,在build构建目录中debug文件夹会生成一个qrc_resource.cpp文件,图片转化成cpp代码(一个保存二进制数据的数组)。最后项目编译时,会将这些代码编译到exe文件中,后续⽆论exe被复制到哪个⽬录下,都确保能够访问到该图片资源。

image-20240626113056667

image-20240626113109744

  1. 在Qt代码中使用来自qrc的资源
QPixmap pixmap(":/add.png");
  • : 表示从qrc中获取资源
  • / 是在qrc中已添加的(虚拟 )资源文件目录前缀
  • add.png 是资源文件名

qrc资源管理方案的优缺点

  • 优点:确保了图⽚,字体,声⾳等资源能够真正做到"目录⽆关",⽆论如何都不会出现资源丢失的情况。

  • 缺点:不适合管理体积⼤的资源。如果资源比较⼤(⽐如是⼏个MB的⽂件),或者资源特别多,⽣成的最终的exe体积就会⽐较⼤,程序运⾏消耗的内存也会增⼤,程序编译的时间也会显著增加。

windowOpacity

控件的透明度。但事实上是不透明的程度,用浮点数表示,数值越大,控件越不透明。

APIIntro
windowOpacity()获取到控件的不透明数值,返回float,取值为[0.0, 1.0]。其中0.0表示全透明,1.0表示完全不透明
setWindowOpacity(level)设置控件的不透明度,level最大值为1,大于1自动转换为1。

cursor

控件的悬停光标样式

APIIntro
cursor()获取当前控件的光标样式,返回QCursor对象
setCursor(const QCursor& cursor)设置控件的光标样式,仅在⿏标停留在该控件上时⽣效

QCursor是表示光标样式的对象,可以使用Qt内置的,也可以自定义。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
	//使用内置光标
    this->setCursor(Qt::WaitCursor);

    //创建一个pixmap对象,加载自定义光标图像(来自qrc)
    QPixmap pixmap(":/add.png");
    //可以对pixmap进行缩放,scaled返回的是缩放后的图像副本
    pixmap = pixmap.scaled(30, 30);
    //通过pixmap创建一个cursor对象,可以设置热点(光标点击生效的点)坐标
    QCursor cursor(pixmap, 15, 15);
    //设置光标
    ui->pushButton_add_opacity->setCursor(cursor);
}

font

字体属性

APIIntro
font()获取控件的字体信息,返回QFont对象
setFont()设置控件的字体信息

QFont用于表示字体的各种属性信息。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    QLabel *label = new QLabel(this);
    label->setText("Hello World!");

    QFont font;
    //设置字体家族
    font.setFamily("Consola");
    //设置字体大小
    font.setPointSize(20);
    //设置字体加粗
    font.setBold(true);
    //设置字体倾斜
    font.setItalic(true);
    //设置下划线
    font.setUnderline(true);
    //设置删除线
    font.setStrikeOut(true);
    //将字体信息设置到文本上
    label->setFont(font);
}

toolTip

鼠标悬停在控件上时,提示用户一些信息(一般是该控件的功能、属性等)

APIIntro
setToolTip(const QString& )设置toolTip,鼠标悬停时的提示说明
setToolTipDuration(int msec)提示的时间,单位是ms,时间一到toolTip自动消失
this->setToolTip("Hello");
this->setToolTipDuration(2000);

focusPolicy

控件获取到焦点的策略。控件获取到焦点意味着接下来的操作都对此控件进行(常用于多个输入栏的切换)。

APIIntro
focusPolicy()获取控件获取焦点的策略,返回Qt::FocusPolicy
setFocusPolicy()设置控件获取焦点的策略

Qt::FocusPolicy是Qt内置的枚举类型,取值如下:

namespace Qt{
    	//...
        enum FocusPolicy {
        NoFocus = 0, 								//不会获取焦点
        TabFocus = 0x1,								//控件可通过Tab键获取到焦点
        ClickFocus = 0x2,							//控件可通过鼠标点击获取到焦点
        StrongFocus = TabFocus | ClickFocus | 0x8,	//Tab和数据点击接受焦点(默认值)
        WheelFocus = StrongFocus | 0x4				//类似于Qt::StrongFocus,同时控件也通过⿏标滚轮获取到焦点
    };
}
//设置focusPolicy的方法
widget->setFocusPolicy(Qt::NoFocus);

styleSheet

层叠样式表 QSS

设置样式的格式——键值对

按钮类

image-20240627110507279

按钮都继承自QAbstractButton类,按钮的很多关键的属性都来自这个基类。

属性 (from QAbstractButton)说明
text按钮中的文本
icon按钮中的图标
iconSize图标尺寸
shortCut按钮的快捷键
autoRepeat (true or false)按钮是否会重复触发,即鼠标左键按住不放时,是否“连发”
autoRepeatDelay重复触发的延时时间,即按住按钮多久后,开始“连发”
autoRepeatInterval重复触发的周期
checkable是否可被选中
checked是否已被选中,checkable是checked的前提条件

PushButton

设置按钮的快捷键

void setShortcut(const QKeySequence &key);

QKeySequence:用于保存快捷键序列的对象,因为快捷键可以是单个,也可以是多个键的组合。对于QKeySequence对象的构造,可用表示按键的字符串,如QKeySequence("w");也可用Qt内置的表示按键的宏,如下:

ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_Up));//单个快捷键
ui->pushButton_up->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up));//组合快捷键

按钮设置快捷键后,按下一次快捷键,发出的信号是clicked(按下了就触发,而不是按下后释放再触发),相当于鼠标点击一次按钮(press + released)。所以当你按住快捷键时,是会重复触发clicked的(不停在按下)。

样例:上下左右方向键,控制飞机的移动

79086ad1-23ea-45b8-a0ae-e8d6cc48f2d7
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
	
    
    QIcon icon(":/image/plane.png");
    ui->plane->setIcon(icon);//设置飞机图标
    ui->plane->setIconSize(QSize(50, 50));//设置图标尺寸

    //设置方向键图标
    ui->pushButton_up->setIcon(QIcon(":/image/up.png"));
    ui->pushButton_down->setIcon(QIcon(":/image/down.png"));
    ui->pushButton_left->setIcon(QIcon(":/image/left.png"));
    ui->pushButton_right->setIcon(QIcon(":/image/right.png"));

    //设置方向键快捷键
    ui->pushButton_up->setShortcut(QKeySequence(Qt::Key_Up));//组合快捷键
    ui->pushButton_down->setShortcut(QKeySequence(Qt::Key_Down));
    ui->pushButton_left->setShortcut(QKeySequence(Qt::Key_Left));
    ui->pushButton_right->setShortcut(QKeySequence(Qt::Key_Right));
    
    //开启重复触发
    ui->pushButton_up->setAutoRepeat(true);
}

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

void Widget::on_pushButton_up_clicked()
{
    QRect rect = ui->plane->geometry();
    ui->plane->setGeometry(rect.x(), rect.y() - 5, rect.width(), rect.height());
}
void Widget::on_pushButton_down_clicked()
{
    QRect rect = ui->plane->geometry();
    ui->plane->setGeometry(rect.x(), rect.y() + 5, rect.width(), rect.height());
}
void Widget::on_pushButton_left_clicked()
{
    QRect rect = ui->plane->geometry();
    ui->plane->setGeometry(rect.x() - 5, rect.y(), rect.width(), rect.height());
}
void Widget::on_pushButton_right_clicked()
{
    QRect rect = ui->plane->geometry();
    ui->plane->setGeometry(rect.x() + 5, rect.y(), rect.width(), rect.height());
}

RadioButton

QRadioButton单选按钮,按钮之间具有“排他性”,即一组单选按钮中只能选中其中一个。

QAbstractButton中与QRadioButton较为相关的属性

属性说明
checkable是否可被选中
checked是否已被选中,checkable是checked的前提条件
autoExclusive是否“排他”,对于QRadioButton默认是“排他”的

通常情况下需要为RadioButton分组,以满足不同分类的选择,否则整个页面的单选按钮都有“排他性”,因为它们默认在一个组内。如下是一个简单的点餐菜单,我们想要实现的是每个类型中的选择唯一性,因此必须进行分组。

image-20240627143404353

Qt中提供了QButtonGroup类以实现按钮的分组

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

    //创建按钮组
    QButtonGroup* groupStaple = new QButtonGroup(this);
    QButtonGroup* groupDrink = new QButtonGroup(this);
    QButtonGroup* groupSnack = new QButtonGroup(this);
    
    //为按钮组添加按钮
    groupStaple->addButton(ui->radioButton);
    groupStaple->addButton(ui->radioButton_2);
    groupStaple->addButton(ui->radioButton_3);

    groupDrink->addButton(ui->radioButton_5);
    groupDrink->addButton(ui->radioButton_6);
    groupDrink->addButton(ui->radioButton_7);

    
    groupSnack->addButton(ui->radioButton_8);
    groupSnack->addButton(ui->radioButton_9);
}

“排他性”意味着用户无法多选或取消选中,若想要取消选中,要先暂时地取消“排他性”。如下示例,点餐(这里只点了主食)提交后,实现重置(清除)所有选中。

void Widget::on_pushButton_clicked()
{
    QButtonGroup* groupStaple = findChild<QButtonGroup*>("groupStaple");//获取按钮组

    if (groupStaple)
    {
        QList<QAbstractButton*> buttons = groupStaple->buttons();
        groupStaple->setExclusive(false);  // 取消排他性 (按钮组的排他性,决定该组中的按钮之间是否互斥)
        foreach(QAbstractButton *button, buttons)//遍历groupStaple中所有单选按钮
        {
            button->setChecked(false);// 取消groupStaple中所有单选按钮的选中状态
        }
        groupStaple->setExclusive(true);  // 恢复排他性
    }
    else
    {
        qDebug() << "groupStaple not found";
    }
}

CheckBox

QCheckBox 复选按钮,支持多选,和 QCheckBox 最相关的属性也是 checkablechecked , 都是继承⾃QAbstractButton

image-20240627151051965

Signals

image-20240627150547907

clicked有带参数和不带参数的两种类型:

  • clicked():点击“按钮”(按下+释放),不提供按钮状态信息。

  • clicked(bool checked):适用于可切换按钮,提供按钮的选中状态信息。

  • pressed():“按下”按钮

  • released(): “释放”按钮

  • toggled(bool checked): 按钮状态切换时

示例:

void Widget::on_checkBox_clicked(bool checked)
{
    //复选按钮被选中时 checked == true
    //复选按钮取消选中时 checked == false
    qDebug() << "clicked(bool)" << checked;
}
void Widget::on_radioButton_4_toggled(bool checked)
{
    //切换状态时触发: 
    //被选中 checked == true
    //未选中 checked == false
    qDebug() << "toggled(bool)" << checked;
}

显示类

Label

Qlabel可以显示文字和图片

文本格式

QLabel属性说明
textQlabel中的文本
textFormat文本的格式:纯文本、富文本、markdown,通过Qt自带的宏设置
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    ui->label->setText("<b>这是一段文本</b>");
    ui->label->setTextFormat(Qt::PlainText);//纯文本

    ui->label_2->setText("<b>这是一段文本</b>");
    ui->label_2->setTextFormat(Qt::RichText);//富文本

    ui->label_3->setText("# 这是一段文本");
    ui->label_3->setTextFormat(Qt::MarkdownText);//markdown

    ui->label_4->setText("<i>这是一段文本</i>");
    ui->label_4->setTextFormat(Qt::AutoText);//根据文本内容自动决定格式
}

image-20240627183727102

设置图片

属性说明
pixmaplabel中的图片 (QPixmap)
scaledContents设为true表示自动拉伸内容(仅对图片有效),填充Qlabel;设为false则不会自动拉伸
ui->label_image->setPixmap(QPixmap(":/cat.png"));//设置QLabel的图片
ui->label_image->setScaledContents(true);//自动伸缩填满QLabel

文本控制(对齐、自动换行、缩进、边距)

属性说明
alignment对齐方式,由Qt内置宏提供,可以选中一种对齐方式,也可以多种组合
wordWrap设为 true 内部的文本会自动换行,防止文本长度过长,设为 false不会自动换行
indent设置文本缩进,水平和垂直方向都生效
margin内部⽂本和Qlabel边框之间的边距,上下左右四个方向同时生效

伙伴

属性说明
buddy给 QLabel 关联⼀个 “伙伴” , 这样触发QLabel时就能激活对应的伙伴,这里的“触发”一般是为QLabel设置一个快捷键
ui->label_buddy->setText("快捷键: &A");//QLabel文本中,'&'后的字符被定义为该QLabel的快捷键
ui->label_buddy->setBuddy(ui->radioButton);//将QLabel设置为单选按钮的伙伴

用户通过alt + 快捷键来触发QLabel,从而激活对应的伙伴。

image-20240627191432190

LCDNumber

QLCDNumber显示数字,效果类似于“老式计算器”。

image-20240630100959566

QLCDNumber的主要属性

属性说明
intValue显示数字的数值 (int整型)
value显示数字的数值 (double浮点型),intValue和value存在联系,如value设为3.14,intValue就是3。
digitCount显示几位数字(从右往左,少的显示空格)
mode显示数字的进制:十进制、十六进制、二进制、八进制。只有十进制能显示小数点后的数字
segmentStyle设置显示的风格

注:与以往不同,对于intValue和value的设置,api是display()(重载了int, double和QString三种类型参数的设置),而不是setintValue()setValue()

例:用QLCDNumber设计一个倒计时

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

    //设置初始值
    ui->lcdNumber->display(5);
    //创建一个定时器
    QTimer* timer = new QTimer(this);
    //将定时器的 timeout信号 绑定一个槽函数
    connect(timer, &QTimer::timeout, this, [this, timer](){
        //获取lcdNumber上的数字
        int value = this->ui->lcdNumber->intValue();
        if(value <= 0){
            //倒计时结束
            timer->stop();
            return;
        }
        this->ui->lcdNumber->display(value - 1);
    });
    //启动计时器,设置触发timeout的周期(单位是毫秒)
    timer->start(1000);
}

QTimer是Qt中提供的一个定时器。在GUI编程中,很多场景会用到计时的功能(如倒计时、进度条等),一般来说可以创建一个异步线程,结合sleep()接口,以实现计时功能。

但在Qt中又规定,Qt的界面由主线程维护,不允许其它线程对界面进行操作,以保证线程安全。因此,为了满足计时功能的需求,Qt提供了QTimer,其工作机制是:每个一段时间间隔interval,就发出一次timeout信号,它只负责计时,不负责实现“时间到”之后的具体逻辑。用户可以自定义interval和绑定槽函数,以实现不同的计时需求。而信号槽机制中,默认都是由主界面接收并处理信号,这样一来便很好地满足了GUI中的计时需求。

QTimer的主要接口

API说明
start(int msec)启动计时器,并设置触发timeout的周期(单位是毫秒)
stop()停止计时器

ProgressBar

QProgressBar进度条

image-20240630105856760

QProgressBar的主要属性

属性说明
minimum进度条最小值
maximum进度条最大值
value进度条当前值
format展示数字的格式:%p百分比、%v数值、%m剩余时间(毫秒)、%t总时间(毫秒)

例:进度条走完,关闭窗口

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

    int min = ui->progressBar->minimum();
    int max = ui->progressBar->maximum();
    ui->progressBar->setValue(min);
    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, [=](){
       int value = ui->progressBar->value();
       if(value >= max){
           timer->stop();
           this->close();
           return;
       }
       ui->progressBar->setValue(value + 1);
    });
    timer->start(100);
}

QProgressBarQLCDNumber相同,往往需要和定时器QTimer搭配使用。

使用QSS改变进度条的颜色:

image-20240630110823055

Calendar

QCalendarWidget是Qt中的日历控件

image-20240630111003585

QCalendarWidget的主要属性

属性说明
selectDate当前选中的日期(QDate
dateEditEnabled日期是否允许被编辑 (bool)
minimumDate最大日期(QDate
maximumDate最小日期(QDate

QCalendarWidget的主要信号

信号说明
selectionChanged(const QDate&)当选中的⽇期发⽣改变时发出
activated(constQDate&)当双击⼀个有效的⽇期或者按下回⻋键时发出,形参是⼀个QDate类型,保存 了选中的⽇期
currentPageChanged(int, int)当年份⽉份改变时发出,形参表⽰改变后的新年份和⽉份

输入类

LineEdit

QLineEdit是单行输入框,可以输入一行文本,不能换行。

QLineEdit的主要属性

属性说明
text输入框中的文本
inputMask输入内容的格式约束 (QString)
maxLength最大文本长度
echoMode显示方式:1.QLineEdit::Normal2.QLineEdit::Password 3.QLineEdit::NoEcho
readOnly是否为只读 (bool)
placeHolderText当输入框为空时的显示信息,一般作为提示
clearButtonEnabled当输入框不为空时,是否会显示清除按钮 (bool)

QLineEdit的主要信号

信号说明
void textChanged(const QString& text)当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。 代码对⽂本的修改能够触发这个信号
void textEdited(const QString& text)当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。 代码对⽂本的修改不能触发这个信号
  • 输入内容的格式约束

    inputMask可以实现输入内容的格式约束

    ui->lineEdit_phone->setInputMask("000-0000-0000");//其中'0'代表数字
    

    但在实际开发中,通常采用“正则表达式”来实现格式约束,Qt中提供验证器QValidator,其派生类QRegExpValidator为正则验证器,我们可以为QLineEdit设置一个正则验证器,以验证输入栏中的内容是否符合预期格式。

    例:学生输入学号,只有当输入学号合法时,才允许提交

    #include "widget.h"
    #include "ui_widget.h"
    #include <QRegExpValidator>
    #include <QDebug>
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
        , ui(new Ui::Widget)
    {
        ui->setupUi(this);
        ui->pushButton_submit->setEnabled(false);//当输入学号合法时,才允许提交
        ui->lineEdit_id->setPlaceholderText("请输入学号: 入学年份-学院号-个人号");
        ui->lineEdit_id->setClearButtonEnabled(true);
    
        //为lineEdit_id注册一个正则验证器,并为验证其设置正则表达式
        ui->lineEdit_id->setValidator(new QRegExpValidator(QRegExp("^20\\d{2}\\d{3}\\d{3}$")));
        //该正则表达式的含义
        //入学年份4位,且必须以 20 开头
        //学院号3位
        //个人号3位
    }
    void Widget::on_lineEdit_id_textEdited(const QString &arg1)
    {
        QString id = arg1;
        int pos = 0;
        //验证新输入学号的是否符合正则表达式的格式
        if(ui->lineEdit_id->validator()->validate(id, pos) == QValidator::Acceptable){
            //符合
            ui->pushButton_submit->setEnabled(true);
        }
        else{
            //不符合
            ui->pushButton_submit->setEnabled(false);
        }
    }
    void Widget::on_pushButton_submit_clicked()
    {
        qDebug() << ui->lineEdit_id->text();
    }
    

TextEdit

QTextEdit是多行输入框,可以输入多行文本。

主要属性

属性说明
markdown输入框中的内容支持markdown格式
html输入框中的内容支持html格式
placeHolderText当输入框为空时的显示信息,一般作为提示
undoRedoEnable是否触发 undo (ctrl + z) / redo (ctrl + y) 功能
verticalScrollBarPolicy垂直方向滚动条的出现策略,默认根据内容⾃动决定是否需要滚动条
horizontalScrollBarPolicy水平方向滚动条的出现策略,默认根据内容⾃动决定是否需要滚动条

主要方法

接口说明
QString toHtml()html格式获取输入框中的文本
QString toMarkdown()markdown格式获取输入框中的文本
void setHtml(const QString &text)设置输入框中的内容为一段html格式的文本,并且此后输入都是这种格式
void setMarkdown(const QString &text)设置输入框中的内容为一段markdown格式的文本,并且此后输入都是这种格式
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->label->setTextFormat(Qt::MarkdownText);
    ui->pushButton->setText("转化为html");
}

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

void Widget::on_textEdit_textChanged()
{
    ui->label->setText(ui->textEdit->toMarkdown());
}

void Widget::on_pushButton_clicked()
{
    ui->textEdit->setHtml("<b>你好</b>");
}

image-20240701110249291

输入markdown格式文本,在label中渲染成markdown

image-20240701110315117

转化为html后,再输入的内容都是预设的<b></b>格式。

主要信号

信号触发时机
textChanged输入框内容发生改变时
selectionChanged()选中的文本发生改变时
cursorPositionChanged()光标的位置发生改变时
undoAvailable(bool)undo功能可用状态切换时(内容不为空,undo就可用)
redoAvailable(bool)redo功能可用状态切换时(undo之后,redo就可用)
copyAvaiable(bool)⽂本被选中/取消选中时触发

QTextCursor表示文本光标,可获取选中的文本、光标的位置。通常和selectionChangedcursorPositionChanged信号搭配使用。

void Widget::on_textEdit_selectionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();//获取textEdit的光标
    ui->label->setText(cursor.selectedText());//获取被选中的文本
}

void Widget::on_textEdit_cursorPositionChanged()
{
    QTextCursor cursor = ui->textEdit->textCursor();//获取textEdit的光标
    qDebug() << "cursorPositionChanged()" << cursor.position();//获取光标位置
}
image-20240701112931800

ComboBox

QComboBox下拉列表,多个选项供用户选择

主要属性

属性说明
currentText当前选中条目的文本
currentIndex当前选中条目的下标(从0开始,无选中条目则为-1)
editable是否可编辑
iconSize下拉框图标(小三角)的大小
maxCount条目最大个数

主要方法

接口说明
addItem(const QString& )添加条目
currentText()获取当前选中条目的文本
currentIndex()获取当前选中条目的下标
setEditable(bool)设置是否可编辑

editable设为true, 用户确认编辑的条目后, 若该条目不存在, 则添加这个条目

ui->comboBox->addItem("战士");
ui->comboBox->addItem("法师");
ui->comboBox->addItem("坦克");
ui->comboBox->setEditable(true);//设下拉列表为可编辑
image-20240701120823891

主要信号

信号说明
currentIndexChanged(int)当前条目下标改变时触发, 传入参数为改变后的条目下标
currentIndexChanged(QString)当前条目下标改变时触发, 传入参数为改变后的条目文本
currentTextChanged(QString)当前条目文本改变时触发, 传入参数为改变后的条目文本
activated(int) / activated(QString)用户选中一个条目时触发 (不管该条目是否已选中)

SpinBox

QSpinBox微调框,对数字进行微调。QSpinBox针对整型,QDoubleSpinBox针对浮点数,用法基本相同。

主要属性

属性说明
value当前值
singleStep单次调整的步长
displayInterger数字的进制。例如displayInteger设为10,则是按照十进制表示,设为2则为二进制表示
minimum最小值
maximum最大值
suffix后缀
prefix前缀

setRange(int min, int max)可以调整最大值和最小值,即修改微调框可变的数值范围。

主要信号

信号触发时机
valueChanged(int)微调框的⽂本发⽣改变时触发,参数int表示当前的数值.
textChanged(QString)微调框的⽂本发⽣改变时触发,参数QString带有前缀和后缀

DateTimeEdit

QDateTimeEdit编辑日期与时间

主要属性

属性说明
dateTime日期时间的值 (QDateTime)
date日期 (QDate)
time时间 (QTime)
displayFormat时间日期格式。形如 yyyy/M/d H:mm
minimumDateTime最小日期时间
maximumDateTime最大日期时间
timeSpecQt::LocalTime:本地时间;Qt::UTC:显⽰协调世界时(UTC);Qt::OffsetFromUTC :显⽰相对于UTC的偏移量(时差)
setDateTimeRange(const QDateTime &min, const QDateTime &max)//设置日期时间的范围
  • 关于QDateTime

    Qt中用于表示日期时间的类是QDateTime,以下是QDateTime一些常用的接口,方便我们对日期时间进行操作

    接口说明
    daysTo(const QDateTime &other)thisother之间的天数。但有时会不符合预期,比如 2024/1/1 23:55 - 2024/1/2 0:05也会被算成一天。
    secsTo(const QDateTime &other)thisother之间的秒数
    QString toString(const QString &format)将日期时间转化成字符串,format是日期时间的字符串格式。

样例:日期计算器,计算两个日期之间的差值(几天几时)

#include "widget.h"
#include "ui_widget.h"

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

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

void Widget::on_pushButton_calc_clicked()
{
    //1.获取两个前后两个日期时间
    QDateTime former = ui->dateTimeEdit_former->dateTime();
    QDateTime later = ui->dateTimeEdit_later->dateTime();
    //2.计算两个日期时间差值
    int secs = former.secsTo(later);
    int days = secs / (3600 * 24);//总秒数 / 一天的秒数
    int hours = (secs / 3600) % 24;// 总秒数/一小时的秒数 = 总小时数
    ui->label_ret->setText(QString::number(days) + "天" + QString::number(hours) + "时");
}

void Widget::on_dateTimeEdit_later_dateTimeChanged(const QDateTime &later)
{
    //确保第一个时间在第二个时间之前
    QDateTime former = ui->dateTimeEdit_former->dateTime();
    if(later < former){
        ui->dateTimeEdit_former->setDateTime(later);
        ui->dateTimeEdit_later->setDateTime(former);
    }
}

image-20240701164425374

Dial

QDial表示一个旋钮,通过旋转改变数值

Slider

QSlider表示一个滑动条,通过滑动改变数值

快捷键

Qt中基于信号槽机制,提供了一种通用的设置快捷键的方法。QShortcut表示快捷键,用户可使用该类自定义快捷键。当相应的快捷键被激活时,触发QShortcut的信号activated,用户可自定义槽函数,完成快捷键被激活后的特定工作。

样例:设置快捷键-=控制旋钮,旋钮的功能是控制窗口的透明度

#include "widget.h"
#include "ui_widget.h"
#include <QShortcut>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //1.设置旋钮的属性
    ui->dial->setRange(0, 100);//旋钮数值范围(透明度范围)
    ui->dial->setValue(100);//旋钮初始值
    ui->dial->setWrapping(true);//允许循环转动
    ui->dial->setNotchesVisible(true);//显示刻度线

    //2.设置快捷键
    QShortcut* shortcutSub = new QShortcut(this);
    shortcutSub->setKey(QKeySequence("-"));
    QShortcut* shortcutAdd = new QShortcut(this);
    shortcutAdd->setKey(QKeySequence("="));
    
    //3.绑定快捷键的“激活”信号和槽函数
    connect(shortcutSub, &QShortcut::activated, this, [=](){
        if(this->ui->dial->value() > 0){
            this->ui->dial->setValue(this->ui->dial->value() - 5);
        }
    });

    connect(shortcutAdd, &QShortcut::activated, this, [=](){
        if(this->ui->dial->value() < 100){
            this->ui->dial->setValue(this->ui->dial->value() + 5);
        }
    });
}

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


void Widget::on_dial_valueChanged(int value)
{
    this->setWindowOpacity(value / 100.0);
}

多元素控件

ListWidget

QListWidget是一个纵向列表

主要属性

属性说明
currentRow当前被选中的是第几行(行的下标从0开始),若无选中,返回-1
count一共有多少行
sortingEnabled列表是否允许排序(若是,默认升序,可通过sortItems修改排序方式)

主要方法

接口说明
void addItem(const QString &label)
void addItem(QListWidgetItem *item)
添加列表元素
void insertItem(int row, QListWidgetItem *item)
void insertItem(int row, const QString &label)
在指定位置插入元素
QListWidgetItem *currentItem()
int currentRow()
返回当前选中的元素(指针或下标)
QListWidgetItem * takeItem(int row)删除并返回指定行的元素
QListWidgetItem * item(int row)返回指定行的元素
void setCurrentItem(QListWidgetItem *item)
void setCurrentRow(int row)
设置选中的元素(使用指针或下标)

注意,多元素控件QListWidget中,对于某一个元素,可以用行表示,也可以用QListWidgetItem指针表示。

QListWidgetItem是表示QListWidget中一个元素的类,本质是设置元素中的文本和图标,以及字体样式等。

样例:根据输入内容,新增列表的元素;删除指定列表中元素

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->lineEdit->setClearButtonEnabled(true);
    ui->listWidget->setSortingEnabled(true);
    ui->listWidget->addItem(new QListWidgetItem("初始"));//使用QListWidgetItem类添加元素
}

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


void Widget::on_pushButton_add_clicked()
{
    const QString& text = ui->lineEdit->text();
    if(!text.isEmpty()){
        ui->listWidget->addItem(text);
    }
}

void Widget::on_pushButton_del_clicked()
{
    qDebug() << ui->listWidget->currentItem()->text();//获取选中元素的文本
    int row = ui->listWidget->currentRow();
    if(row >= 0){
        ui->listWidget->takeItem(row);
    }
}
image-20240711171901668

主要信号

信号触发时机
currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)选中元素发生变化时(current变化后元素,previous变化前元素)
currentRowChanged(int currentRow)选中元素发生变化时(currentRow当前行)
itemClicked(QListWidgetItem*item)点击某个元素时触发
void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
    if(current) 
        qDebug() << "当前元素:" << current->text();
    if(previous) //若没有变化前没有选中元素,previous为nullptr
        qDebug() << "最近元素:" << previous->text();
}

TableWidget

QTableWidget是一个表格控件

主要属性

属性说明
columnCount列数
rowCount行数

主要方法

方法说明
QTableWidgetItem * item(int row, int column)根据行和列获取表格中某一元素
void setItem(int row, int column, QTableWidgetItem *item)根据行和列设置表格中某一元素
QTableWidgetItem * currentItem()返回被选中的元素
int currentRow() const返回被选中元素的行
int currentColumn() const返回被选中元素的列
setColumnCount(int)设置表格列数
setRowCount(int)设置表格行数
void setHorizontalHeaderItem(int column, QTableWidgetItem *item)设置列表头
void setVerticalHeaderItem(int column, QTableWidgetItem *item)设置行表头
void insertRow(int row)在指定位置插入新行
void insertColumn(int row)在指定位置插入新列
void removeRow(int row)删除指定行
void removeColumn(int column)删除指定列

QListWidget相同,在QTableWidget中,对于某一个元素,可以用行和列表示,也可以用QTableWidgetItem 指针表示。而QTableWidgetItem 除了设置文本图标样式,还有两个特殊的方法,可以获取元素所在单元格的行和列

QTableWidgetItem::方法说明
row()获取元素所在单元格的行
column()获取元素所在单元格的列

样例:通过输入内容,确定新增行或列,以及对应表头

void Widget::on_pushButton_row_clicked()
{
    int row = ui->tableWidget->rowCount();
    ui->tableWidget->insertRow(row);
    const QString& header = ui->lineEdit_row->text();
    if(!header.isEmpty()){
        ui->tableWidget->setVerticalHeaderItem(row, new QTableWidgetItem(header));
    }
}

void Widget::on_pushButton_col_clicked()
{
    int col = ui->tableWidget->columnCount();
    ui->tableWidget->insertColumn(col);
    const QString& header = ui->lineEdit_col->text();
    if(!header.isEmpty()){
        ui->tableWidget->setHorizontalHeaderItem(col, new QTableWidgetItem(header));
    }
}

主要信号

信号触发时机
cellClicked(int row,int column)点击单元格时
currentCellChanged(int row,int column,int previousRow,int previousColumn)选中单元格切换时
cellEntered(int row,int column)⿏标进⼊单元格时

TreeWidget

QTreeWidget是一个树形控件,类似于操作系统中的目录结构。QTreeWidget最上层没有根节点,而是由一系列的顶层节点(TopLevelItem)构成,然后再给顶层节点添加子节点,如此往复,最终形成树状结构。

QTreeWidget里的每个元素,都是⼀个 QTreeWidgetItem ,每个QTreeWidgetItem 可以包含多个⽂本和图标,每个⽂本/图标为⼀个列

image-20240712095358357

样例:

image-20240712104615348
void Widget::on_pushButton_topLevel_clicked()
{
    const QString& text = ui->lineEdit->text();
    if(!text.isEmpty()){
        QTreeWidgetItem* newItem = new QTreeWidgetItem();
        if(newItem){
            newItem->setText(0, text);
            ui->treeWidget->addTopLevelItem(newItem);
        }
    }
    // 可以不显式地为新创建的 QTreeWidgetItem 对象设置 parent 指针
    // 因为 addTopLevelItem 会自动将 newItem 的父指针设置为 treeWidget
}

void Widget::on_pushButton_cur_clicked()
{
    const QString& text = ui->lineEdit->text();
    if(!text.isEmpty()){
        QTreeWidgetItem* newItem = new QTreeWidgetItem();
        if(newItem){
            newItem->setText(0, text);
            ui->treeWidget->currentItem()->addChild(newItem);
        }
    }
}

void Widget::on_pushButton_del_clicked()
{
    QTreeWidgetItem* cur = ui->treeWidget->currentItem();
    QTreeWidgetItem* parent = cur->parent();
    if(parent == nullptr){
        //顶层节点
        int index = ui->treeWidget->indexOfTopLevelItem(cur);
        ui->treeWidget->takeTopLevelItem(index);
    }
    else{
        //非顶层节点
        parent->removeChild(cur);
    }
}

容器类控件

GroupBox

使⽤ QGroupBox 实现⼀个带有标题的分组框,可以把其他的控件放到里面作为⼀组,这样看起来能更好看⼀点。

TabWidget

QTabWidget实现一个带有标签页的控件,可以往标签页中设置新的widget,以实现通过切换标签页在不同的widget中跳转。注意,标签页的内容是设置在另外创建的QWidget对象中,QTabWidget只是提供标签页。

主要属性

属性说明
tabPosition标签所在位置
North 上方
South 下方
West 左侧
East 右侧
currentIndex当前选中标签页的下标(从0开始)
currentTabText当前选中标签页的文本
tabsCloseable标签页是否可以关闭
movable标签页是否可以移动

主要方法

方法说明
int addTab(QWidget *page, const QString &label)添加一个新的标签页,page是标签页本体,label是标签页的选项卡文本。返回值是新标签页的编号。
int count()获取标签页的数量
void setCurrentWidget(QWidget *widget)通过QWidget指针,设置当前标签页
void setCurrentIndex(int index)通过标签页编号,设置当前标签页
void removeTab(int index)根据标签页编号,删除标签页

主要信号

信号触发时机
currentChanged(int)标签页切换时,参数为切换后的标签页编号
tabBarClicked(int)点击选项卡的标签条的时候,参数为被点击的选项卡编号
tabCloseRequest(int)tabsCloseable == true时,点击关闭标签页按钮触发,参数为被关闭的标签页编号

样例:实现新增标签页按钮,和点击标签页关闭按钮关闭标签页

#include "widget.h"
#include "ui_widget.h"
#include <QLabel>

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

    QLabel* label = new QLabel(ui->tab);
    label->setText("这是第一个标签页");
    label->resize(150,60);

    QLabel* label_2 = new QLabel(ui->tab_2);
    label_2->setText("这是第二个标签页");
    label_2->resize(150,60);
}

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

void Widget::on_pushButton_clicked()
{
    //创建新标签页的Widget,还有标签页文本
    QWidget* page = new QWidget();
    int idx = ui->tabWidget->count() + 1;
    ui->tabWidget->addTab(page, "Tab" + QString::number(idx));

    //每次创建一个新标签页,自动选中它
    ui->tabWidget->setCurrentWidget(page);
}

void Widget::on_tabWidget_tabCloseRequested(int index)
{
    ui->tabWidget->removeTab(index);
}
image-20240712114514262

布局管理器

垂直布局

QVBoxLayout是垂直布局管理器。下面是设置垂直布局管理器的demo。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QVBoxLayout* layout = new QVBoxLayout();//创建一个垂直布局管理器
    this->setLayout(layout);//将layout设置为窗口的布局管理器

    layout->setContentsMargins(10,20,10,20);//设置布局的左、上、右、下间距
    layout->setSpacing(50);//设置相邻元素的间距

    //新建一些按钮
    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    QPushButton* button3 = new QPushButton("按钮3");
    
    //将按钮添加到布局管理器中
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
}
image-20240715112248092

水平布局

QHBoxLayout水平布局管理器。下面是设置垂直布局管理器的demo。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QHBoxLayout* layout = new QHBoxLayout();//创建一个垂直布局管理器
    this->setLayout(layout);//将layout设置为窗口的布局管理器

    layout->setContentsMargins(10,20,10,20);//设置布局的左、上、右、下间距
    layout->setSpacing(50);//设置相邻元素的间距

    //新建一些按钮
    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    QPushButton* button3 = new QPushButton("按钮3");

    //将按钮添加到布局管理器中
    layout->addWidget(button1);
    layout->addWidget(button2);
    layout->addWidget(button3);
    
    //设置拉伸系数,即在布局中所占的权重
    layout->setStretch(0, 1);
    layout->setStretch(1, 1);
    layout->setStretch(2, 2);
}
image-20240715112822430

每个控件(QWidget)只能有一个布局管理器(layout),在QtDesigner中在控件上创建多个layout,实际上内部为每个layout都新建了一个QWidget,再在新建的QWidget上设置layout。如果我们想在一个控件上创建多个layout,可以通过嵌套的方式实现。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QVBoxLayout* vlayout = new QVBoxLayout();//创建一个垂直布局管理器vlayout
    this->setLayout(vlayout);//将vlayout设置为窗口的布局管理器

    //新建一些按钮
    QPushButton* button1 = new QPushButton("按钮1");
    QPushButton* button2 = new QPushButton("按钮2");
    QPushButton* button3 = new QPushButton("按钮3");
    QPushButton* button4 = new QPushButton("按钮4");

    //新建水平布局
    QHBoxLayout* hlayout = new QHBoxLayout();
    hlayout->addWidget(button3);
    hlayout->addWidget(button4);

    //将按钮添加到布局管理器中
    vlayout->addWidget(button1);
    vlayout->addWidget(button2);
    //将水平布局嵌套到垂直布局中
    vlayout->addLayout(hlayout);
}
image-20240715113513857

网格布局

QGridLayout是网格布局,实现m * n的二维网格布局效果。

void addWidget(QWidget *, int row, int column)//在网格布局中添加控件

demo

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QGridLayout* glayout = new QGridLayout();//创建网格布局,视为2行3列
    this->setLayout(glayout);

    QPushButton* btn1 = new QPushButton("按钮1");
    QPushButton* btn2 = new QPushButton("按钮2");
    QPushButton* btn3 = new QPushButton("按钮3");
    QPushButton* btn4 = new QPushButton("按钮4");
    QPushButton* btn5 = new QPushButton("按钮5");
    QPushButton* btn6 = new QPushButton("按钮6");

    glayout->addWidget(btn1, 0, 0);
    glayout->addWidget(btn2, 0, 1);
    glayout->addWidget(btn3, 0, 2);
    glayout->addWidget(btn4, 1, 0);
    glayout->addWidget(btn5, 1, 1);
    glayout->addWidget(btn6, 1, 2);

    //设置列的拉伸系数
    glayout->setColumnStretch(0,1);
    glayout->setColumnStretch(1,2);
    glayout->setColumnStretch(2,1);
    
    //设置行的拉伸系数
    glayout->setRowStretch(0, 1);
    glayout->setRowStretch(1, 2);
}

image-20240715114704133

上述案例中,直接设置 setRowStretch 效果不明显,因为每个按钮的⾼度是固定的.需要把按钮的垂直⽅向的 sizePolicy 属性设置为 QSizePolicy::Expanding 尽可能填充满布局管理器,才能看到效果,如下:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QGridLayout* glayout = new QGridLayout();//创建网格布局,视为2行3列
    this->setLayout(glayout);

    QPushButton* btn1 = new QPushButton("按钮1");
    QPushButton* btn2 = new QPushButton("按钮2");
    QPushButton* btn3 = new QPushButton("按钮3");
    QPushButton* btn4 = new QPushButton("按钮4");
    QPushButton* btn5 = new QPushButton("按钮5");
    QPushButton* btn6 = new QPushButton("按钮6");
    //设置每个按钮的SizePolicy为 填充
    btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn4->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn5->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    btn6->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);


    glayout->addWidget(btn1, 0, 0);
    glayout->addWidget(btn2, 0, 1);
    glayout->addWidget(btn3, 0, 2);
    glayout->addWidget(btn4, 1, 0);
    glayout->addWidget(btn5, 1, 1);
    glayout->addWidget(btn6, 1, 2);

    //设置列的拉伸系数
    glayout->setColumnStretch(0,1);
    glayout->setColumnStretch(1,2);
    glayout->setColumnStretch(2,1);

    //设置行的拉伸系数
    glayout->setRowStretch(0, 1);
    glayout->setRowStretch(1, 3);
}
image-20240715114957928

表单布局

QFormLayout是表单布局管理器,网格布局的一种特殊情况。这种表单布局多用于让用户填写信息的场景,一般只有两列,左侧列为提示,右侧列为输⼊框。通过addRow(QWidget *label, QWidget *field)方法可以向表单布局中添加行。

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

    QLabel* label_name = new QLabel("姓名");
    QLabel* label_phone = new QLabel("电话");
    QLabel* label_addr = new QLabel("地址");
    QLineEdit* lineEdit_name = new QLineEdit();
    QLineEdit* lineEdit_phone = new QLineEdit();
    QLineEdit* lineEdit_addr = new QLineEdit();

    flayout->addRow(label_name, lineEdit_name);
    flayout->addRow(label_phone, lineEdit_phone);
    flayout->addRow(label_addr, lineEdit_addr);

    QPushButton* btn = new QPushButton("提交");
    flayout->addRow(nullptr, btn);
}
image-20240715115915612

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1937224.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

55 、mysql的存储引擎、备份恢复以及日志备份、恢复

一、数据库的存储引擎&#xff1a; 1.1、存储引擎的概念 概念&#xff1a;存储引擎&#xff0c;就是一种数据库存储数据的机制&#xff0c;索引的机制&#xff0c;索引的技巧&#xff0c;锁定水平。 存储的方式和存储的格式。 存储引擎也属于mysql当中的组件&#xff0c;实…

Python游戏开发之制作捕鱼达人游戏-附源码

制作一个简单的“捕鱼达人”游戏可以使用Python结合图形界面库&#xff0c;比如Pygame。Pygame是一个流行的Python库&#xff0c;用于创建视频游戏&#xff0c;它提供了图形、声音等多媒体的支持。以下是一个基础的“捕鱼达人”游戏框架&#xff0c;包括玩家控制一个炮台来射击…

小程序博客搭建分享,纯微信小程序原生实现

本项目代码已开源&#xff0c;具体见&#xff1a; 前端工程&#xff1a;vue3-ts-blog-frontend 后端工程&#xff1a;express-blog-backend 小程序源码&#xff1a;blog-weapp 数据库初始化脚本&#xff1a;关注公众号程序员白彬&#xff0c;回复关键字“博客数据库脚本”&…

【ML练习】决策树

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、决策树算法概述 二、代码实现 代码目标&#xff1a;我们希望通过鸢尾花数据&#xff0c;训练一个决策树模型&#xff0c;之后应用该模型&#xff0c;可以…

新的铸造厂通过 PROFIBUS 技术实现完全自动化

钢铁生产商某钢以其在厚钢板类别中极高的产品质量而闻名。其原材料&#xff08;板坯连铸机&#xff09;在钢铁厂本地生产&#xff0c;该厂最近新建了一座垂直连铸厂。该项目的一个主要目标是从一开始就完全自动化这座新工厂和整个铸造过程&#xff0c;以高成本效率实现最佳产品…

ue5 使用动画蒙太奇,混合上半身持枪姿势

ue5 使用动画蒙太奇 1.创建动画蒙太奇 添加上半身插槽&#xff0c;在添加持枪动画 搜索equip stand,t&#xff0c;添加进上半身插槽 2.设置动画蓝图 3.播放动画蒙太奇

AFAC2024-基于保险条款的问答 比赛日记 llamafactory qwen npu 910B1

AFAC2024: 基于保险条款的问答挑战——我的实战日记 概述 在最近的AFAC2024竞赛中&#xff0c;我参与了基于保险条款的问答赛道。这是一次深度学习与自然语言处理的实战演练&#xff0c;旨在提升模型在复杂保险文本理解与问答生成方面的能力。本文将分享我的参赛过程&#xf…

C语言 #字符指针

文章目录 前言 一、指针概念简述 二、字符指针 二、字符在内存中的存储 总结 前言 以例子为导向来分析字符指针的中存的是什么&#xff0c;以及常量字符串在内存中是如何存储的。 一、指针概念简述 想要详细地了解指针的概念可以戳此链接&#xff08;详细的万字讲解&#xff…

机器学习基础入门(1)

最近也在努力的想要学习些机器学习的知识&#xff0c;目前正在了解各个概念及术语&#xff0c;下面就把学习到的概念都列出来。 人工智能 (AI) Artificial intelligence 人工智能生成内容&#xff08;AIGC&#xff09; 机器学习&#xff08;ML&#xff09; Machine Learning …

《汇编语言 基于x86处理器》- 读书笔记 - Visual Studio 2019 配置 MASM环境

安装 Visual Studio 2019 配置 MASM环境 下载 Visual Studio Installer安装 Visual Studio 20191. 双击运行2. 自定义安装内容3. 修改 MSVC 工具集版本4. 设置主题&#xff08;可选&#xff09;5. 安装代码高亮插件 AsmDude&#xff08;可选&#xff09;6. 通义灵码&#xff08…

【AI学习】关于Scaling Law的相关学习

一、苦涩的教训 首先&#xff0c;学习一段重要话语&#xff1a; The biggest lesson that can be read from 70 years of AI research is that general methods that leverage computation are ultimately the most effective, and by a large margin. 从70年的人工智能研究中…

服务器借助笔记本热点WIFI上网

一、同一局域网环境 1、当前环境&#xff0c;已有交换机组网环境&#xff0c;服务器已配置IP信息。 设备ip服务器125.10.100.12交换机125.10.100.0/24笔记本125.10.100.39 2、拓扑图 #mermaid-svg-D4moqMym9i0eeRBm {font-family:"trebuchet ms",verdana,arial,sa…

FastAPI(六十五)实战开发《在线课程学习系统》基础架构的搭建

在之前三篇&#xff0c;我们分享的就是需求的分析&#xff0c;基本接口的整理&#xff0c;数据库链接的配置。这次我们分享项目的基本框架&#xff0c;目录结构大致如下&#xff1a; common目录&#xff1a; 通用目录&#xff0c;放一些通用的处理 models目录&#xf…

达梦数据库(一)mysql2dm

达梦数据库(一)mysql2dm 文章目录 达梦数据库(一)mysql2dm一、安装篇ForWindows二、数据库初始化篇三、数据迁移篇出现的问题找不到对应表或者视图 注意字符集模式迁移出错大小写敏感解决方案 四、 代码修改篇group_concatGROUP BY方法一方法二(最笨)方法补充 多表联查更新参考…

【AI资讯】7.19日凌晨OpenAI发布迷你AI模型GPT-4o mini

性价比最高的小模型 北京时间7月19日凌晨&#xff0c;美国OpenAI公司推出一款新的 AI 模型“GPT-4o mini”&#xff0c;即GPT-4o的更小参数量、简化版本。OpenAI表示&#xff0c;GPT-4o mini是目前功能最强大、性价比最高的小参数模型&#xff0c;性能逼近原版GPT-4&#xff0…

python--实验15 数据分析与可视化

目录 知识点 1 数据分析概述 1.1流程 1.2定义 1.3数据分析常用工具 2 科学计算 2.1numpy 2.1.1定义 2.1.2创建数组的方式 2.1.3np.random的随机数函数 3 数据可视化 3.1定义 3.2基本思想 3.3Matplotlib库 3.3.1模块 4 数据分析 4.1Pandas 4.2数据结构 4.3基…

RE学习7.16-17

[HDCTF 2023]买了些什么呢 是一个经典的算法题吧 物品的重量和价值为: | 物品编号 | 重量 | 价值 | | 1 | 2 | 8 | | 2 | 5 | 1 | | 3 | 10 | 5 | | 4 | 9 | 9 | | 5 | 3 | 5 | | 6 | 6 | 6 | | 7 | 2 | 8 | | 8 | 2 | 2 | | 9 | 6 | 3 | | 10 | 8 | 7 | | 11 | 2 | 5 | | 1…

在 PostgreSQL 中怎样进行数据库的容量规划?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 在 PostgreSQL 中怎样进行数据库的容量规划&#xff1f;一、为什么容量规划如此重要&#xff1f;二、影…

探索 JavaScript Polyfill:跨越浏览器兼容性的桥梁

&#x1f389; 博客主页&#xff1a;【剑九 六千里-CSDN博客】 &#x1f3a8; 上一篇文章&#xff1a;【构建高效Node.js中间层&#xff1a;探索请求合并转发的艺术】 &#x1f3a0; 系列专栏&#xff1a;【面试题-八股系列】 &#x1f496; 感谢大家点赞&#x1f44d;收藏⭐评…

【Linux系统化学习】数据链路层

目录 数据链路层解决的问题 以太网 认识局域网 以太网帧格式 两个问题 认识MAC地址 认识MTU ARP协议 ARP协议的作用 ARP数据报格式 ARP协议的工作流程 数据链路层解决的问题 对于TCP/IP四层协议来说&#xff0c;数据链路层才是真正从传送数据进行跑腿办事情的&…