widget.cpp
#include "widget.h"
#include<QDebug>
//实现槽函数
void Widget::login1()
{
QString user=username_input->text();
QString pass=password_input->text();
//如果不勾选无法登入
if(!check->isChecked()){
qDebug()<<"xxx"<<endl;
return;
}
if("123"==user&&"123"==pass){
qDebug()<<"登入成功";
this->close();
}else{
//错误清空
password_input->setText("");
}
}
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->resize(468,657);
//创建头像标签
avatar=new QLabel(this);
//移动位置
avatar->resize(114,114);
avatar->setStyleSheet(" border-radius: 50px;");
avatar->move((this->width()-avatar->width())/2,95);
//加载图片
avatar->setPixmap(QPixmap("C:\\Users\\xzq\\Desktop\\ava.png"));
avatar->setScaledContents(true);
//添加输入框
username_input=new QLineEdit(this);
//设置大小
username_input->resize(371,60);
username_input->setStyleSheet(" border-radius: 10px;");
//设置占位文本
username_input->setPlaceholderText("请输入QQ账号");
//设置位置
username_input->move((this->width()-username_input->width())/2,avatar->y()+avatar->height()+30);
//设置文本大小居中
username_input->setFont(QFont("黑体",20,5));
username_input->setAlignment(Qt::AlignmentFlag::AlignHCenter);
password_input=new QLineEdit(this);
password_input->resize(371,60);
password_input->setStyleSheet(" border-radius: 10px;");
password_input->move((this->width()-username_input->width())/2,avatar->y()+avatar->height()+30+80);
password_input->setPlaceholderText("请输入QQ密码");
password_input->setFont(QFont("黑体",10,5));
password_input->setAlignment(Qt::AlignmentFlag::AlignHCenter);
password_input->setEchoMode(QLineEdit::Password);
//复选框
check=new QCheckBox("已阅并同意",this);
//check->resize(373,26);
check->setStyleSheet( "QCheckBox::indicator {"
" width: 16px;"
" height: 16px;"
" border-radius: 8px;"
" border: 1px solid gray;"
"}"
"QCheckBox::indicator:checked {"
" background-color: blue;"
"}"
);
check->move((this->width()-check->width())/2,(password_input->y()+password_input->height())+10);
//登入按钮
login_btn=new QPushButton("登入",this);
login_btn->resize(371,60);
login_btn->setStyleSheet( "QPushButton {"
" background-color: #0099FF;" // 正常状态背景颜色
" color: white;" // 文字颜色
" border: none;" // 无边框
" padding: 10px 20px;" // 内边距
"border-radius:10px;"
"}"
"QPushButton:pressed {"
" background-color: #97D6FF;" // 按下状态背景颜色
"}"
);
login_btn->setFont(QFont("黑体",20,5));
//移动
login_btn->move(password_input->x(),check->y()+check->height()+20);
//链接
QObject::connect(login_btn,&QPushButton::clicked,this,&Widget::login1);
}
Widget::~Widget()
{
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QLabel>
#include<QLineEdit>
#include<QRadioButton>
#include<QPushButton>
#include<QCheckBox>
class Widget : public QWidget
{
Q_OBJECT
public slots:
//登入定义槽函数
void login1();
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
QLabel *avatar;//头像
QLineEdit *username_input;//QQ号
QLineEdit *password_input;//密码
QPushButton *login_btn;//登入
QCheckBox *check;//协议
};
#endif // WIDGET_H
修仙笔记
一、对象树模型
1.1 对象树的构建
Qt中,每个QObject
或其派生类对象都能有一个父对象和多个子对象。在创建对象时,如果指定了父对象,该对象会自动被添加到父对象的子对象列表中。这种父子关系形成了一种树形结构,父对象处于树的顶端,子对象在其下方,并且子对象还可以拥有自己的子对象。例如,在一个图形界面应用中,窗口可以作为父对象,而按钮、文本框等控件则是其子对象。
1.2 对象树的自动管理
这一特性是对象树模型的一大亮点。当父对象被销毁时,Qt会自动递归地销毁其所有子对象。这意味着开发者无需手动释放子对象的内存,大大简化了内存管理的过程,有效减少了内存泄漏的风险。在实际开发中,这一机制能让开发者更专注于业务逻辑的实现,而无需过多担心对象的生命周期管理。
1.3 对象树的遍历
在开发过程中,经常需要查找或遍历对象树中的子对象。Qt提供了findChild
和findChildren
方法,通过这两个方法,可以按名称或类型查找子对象。另外,使用children
方法能够获取所有子对象的列表,方便进行遍历操作。比如,想要获取窗口中所有的按钮控件,就可以利用这些方法来实现。
1.4 对象树的事件传递
Qt的事件系统借助对象树来传递事件。事件通常从子对象向父对象传递,直到事件被处理或者到达根对象。同时,父对象还可以通过eventFilter
方法拦截并处理子对象的事件。这一机制在实现一些全局的事件处理逻辑时非常有用,例如在一个包含多个输入框的窗口中,统一处理所有输入框的焦点变化事件。
1.5 对象树的动态修改
对象树支持动态修改,既可以通过setParent
方法,也可以在构造函数中指定父对象来动态添加子对象。如果想要移除子对象,可以使用setParent(nullptr)
将其从树中移除,但此时需要手动管理该子对象的生命周期。
二、信号与槽机制
2.1 信号
信号是类中的特殊成员函数,用于组件向外界传递信息。它定义在类体内的signals
权限下,只有声明,没有函数体实现,返回值为void
类型,参数可有可无。在程序需要的地方,通过emit
关键字来手动发射信号。例如,一个按钮被点击时,就可以发射一个信号来通知其他组件。
2.2 槽
槽是用于接收其他组件发射的信号并执行相应逻辑的特殊成员函数,定义在类体内的slots
权限下,是一个完整的函数,既有声明也有定义。槽函数不仅可以接收信号,还能当作普通成员函数被调用,但普通成员函数不能当作槽函数使用。其返回值类型通常为void
,参数用于接收信号函数传递过来的数据。槽函数需要与信号函数进行连接,当信号发射时,与之连接的槽函数会自动执行。
2.3 一个包含了信号与槽的类的定义
class Widget : public QWidget
{
Q_OBJECT //信号与槽机制的元对象
signals:
void my_signal(); //定义一个信号函数
public slots:
void my_slot(); //自定义的槽函数
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
//自定义槽函数的实现
void Widget::my_slot()
{
// 这里编写槽函数的具体逻辑
}
2.4 信号与槽的连接
- 基于ui界面的连接:可以直接使用系统默认提供的组件信号与槽函数进行连接。
- 右键转到槽:在ui界面中,通过右键转到槽的方式,信号函数由系统提供,开发者可以自己实现槽函数的逻辑,此时槽函数会自动生成。
- 手动实现QT4版本的连接:这种连接方式不太友好,需要使用
SIGNAL()
和SLOT()
两个宏函数来转换信号函数和槽函数的函数名(因为它们实际是函数指针类型,而参数要求是字符串类型)。
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)));
- QT5版本的连接:相比QT4版本,QT5的连接方式更加简洁,直接使用信号函数和槽函数的地址进行连接。
QObject::connect(lineEdit, &QLineEdit::textChanged,
label, &QLabel::setText);
- 使用仿函数作为信号的接收者:接收信号后的处理逻辑可以是全局函数、仿函数或者Lambda表达式。
2.5 信号与槽的断开连接
如果需要断开信号与槽的连接,只需将连接函数connect
改为disconnect
,并根据不同的连接方式提供相应的参数即可。
void disconnectSlots() {
QObject::disconnect(this, &MyWidget::customSignal, this, &MyWidget::customSlot);
qDebug() << "信号与槽已断开";
}