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() << "信号与槽已断开";}