在搭建完开发环境之后,就可以开始进行功能模块的开发了。开发环境搭建详见:开发环境搭建 本篇博客将实现用户登陆模块、用户注册模块。
一 数据库建立
首先需要安装MariaDB数据库,下载链接为:MariaDB下载 然后打开文件进行安装就可以使用数据库了。
1.1 建立Library数据库
安装完成MariaDB数据库之后,打开客户端就可以看见如下界面,填入对应的信息,然后点击打开就可以进入数据库了。
1.2 新建user表
右键点击数据名,选择 创建新的->表
user表的结构如下:
表名 | 数据类型 | 数据长度 | 是否主键 |
---|---|---|---|
id | varchar | 128 | yes |
user_name | varchar | 128 | no |
passwrod | varchar | 128 | no |
role | INTEGER | 11 | no |
varchar | 128 | no | |
delete_flag | INTEGER | 11 | no |
create_time | TIMESTAMP | no | |
delete_time | TIMESTAMP | no |
user主要是用来存储用户信息的表,字段中包含以后邮箱,是为了防止用户忘记密码,修改密码所备用的。
二、登陆、注册UI界面搭建
1 页面搭建
1.1 登陆界面
打开QtDesigner,新建QWidget,按照下图进行登陆界面的搭建:
保存为ui文件之后,通过pyuic工具,将其转换为py文件,代码如下所示
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'LoginView.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(371, 264)
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(60, 10, 152, 25))
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label.setFont(font)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.widget = QtWidgets.QWidget(Form)
self.widget.setGeometry(QtCore.QRect(60, 50, 253, 166))
self.widget.setObjectName("widget")
self.gridLayout = QtWidgets.QGridLayout(self.widget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.label_2 = QtWidgets.QLabel(self.widget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.horizontalLayout_3.addWidget(self.label_2)
self.login_username_lineEdit = QtWidgets.QLineEdit(self.widget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.login_username_lineEdit.setFont(font)
self.login_username_lineEdit.setObjectName("login_username_lineEdit")
self.horizontalLayout_3.addWidget(self.login_username_lineEdit)
self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_3 = QtWidgets.QLabel(self.widget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.horizontalLayout_2.addWidget(self.label_3)
self.login_pwd_lineEdit = QtWidgets.QLineEdit(self.widget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.login_pwd_lineEdit.setFont(font)
self.login_pwd_lineEdit.setObjectName("login_pwd_lineEdit")
self.horizontalLayout_2.addWidget(self.login_pwd_lineEdit)
self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
self.checkBox = QtWidgets.QCheckBox(self.widget)
self.checkBox.setMaximumSize(QtCore.QSize(16777215, 25))
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.checkBox.setFont(font)
self.checkBox.setStyleSheet("color: rgb(255, 255, 255);")
self.checkBox.setObjectName("checkBox")
self.gridLayout.addWidget(self.checkBox, 2, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.login_pushButton = QtWidgets.QPushButton(self.widget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.login_pushButton.setFont(font)
self.login_pushButton.setObjectName("login_pushButton")
self.horizontalLayout.addWidget(self.login_pushButton)
self.cancel_pushButton = QtWidgets.QPushButton(self.widget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.cancel_pushButton.setFont(font)
self.cancel_pushButton.setObjectName("cancel_pushButton")
self.horizontalLayout.addWidget(self.cancel_pushButton)
self.gridLayout.addLayout(self.horizontalLayout, 3, 0, 1, 1)
self.line = QtWidgets.QFrame(Form)
self.line.setGeometry(QtCore.QRect(60, 40, 251, 16))
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line.setObjectName("line")
self.layoutWidget = QtWidgets.QWidget(Form)
self.layoutWidget.setGeometry(QtCore.QRect(80, 220, 212, 43))
self.layoutWidget.setObjectName("layoutWidget")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.layoutWidget)
self.horizontalLayout_4.setContentsMargins(9, 0, 9, 9)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_4 = QtWidgets.QLabel(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.horizontalLayout_4.addWidget(self.label_4)
self.register_pushButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.register_pushButton.setFont(font)
self.register_pushButton.setStyleSheet("color: rgb(64, 182, 255);")
self.register_pushButton.setObjectName("register_pushButton")
self.horizontalLayout_4.addWidget(self.register_pushButton)
self.widget1 = QtWidgets.QWidget(Form)
self.widget1.setGeometry(QtCore.QRect(310, 0, 61, 25))
self.widget1.setObjectName("widget1")
self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.widget1)
self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_5.setSpacing(0)
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.mini_pushButton = QtWidgets.QPushButton(self.widget1)
self.mini_pushButton.setMinimumSize(QtCore.QSize(25, 23))
self.mini_pushButton.setObjectName("mini_pushButton")
self.horizontalLayout_5.addWidget(self.mini_pushButton)
self.close_pushButton = QtWidgets.QPushButton(self.widget1)
self.close_pushButton.setMinimumSize(QtCore.QSize(25, 23))
self.close_pushButton.setObjectName("close_pushButton")
self.horizontalLayout_5.addWidget(self.close_pushButton)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "小型图书管理系统"))
self.label_2.setText(_translate("Form", "账户:"))
self.label_3.setText(_translate("Form", "密码:"))
self.checkBox.setText(_translate("Form", "记住我"))
self.login_pushButton.setText(_translate("Form", "登陆"))
self.cancel_pushButton.setText(_translate("Form", "取消"))
self.label_4.setText(_translate("Form", "还没有账号?"))
self.register_pushButton.setText(_translate("Form", "注册一个"))
self.mini_pushButton.setText(_translate("Form", "-"))
self.close_pushButton.setText(_translate("Form", "X"))
1.2 注册页面
创建完登陆界面之后,开始创建用户注册界面,新建一个QWidget,按照下图所示进行布局,
布局完成之后,保存为.ui文件,然后通过uic进行转换为.py文件,用户注册界面的代码如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'RegisterView.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.setWindowModality(QtCore.Qt.ApplicationModal)
Form.resize(323, 361)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setContentsMargins(-1, -1, -1, 0)
self.gridLayout.setObjectName("gridLayout")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QtWidgets.QLabel(Form)
self.label.setMinimumSize(QtCore.QSize(81, 0))
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label.setFont(font)
self.label.setStyleSheet("color: rgb(255, 255, 255);")
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.reg_username_lineEdit = QtWidgets.QLineEdit(Form)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.reg_username_lineEdit.setFont(font)
self.reg_username_lineEdit.setObjectName("reg_username_lineEdit")
self.horizontalLayout.addWidget(self.reg_username_lineEdit)
self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_2 = QtWidgets.QLabel(Form)
self.label_2.setMinimumSize(QtCore.QSize(81, 0))
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label_2.setFont(font)
self.label_2.setStyleSheet("color: rgb(255, 255, 255);")
self.label_2.setObjectName("label_2")
self.horizontalLayout_2.addWidget(self.label_2)
self.reg_pwd_lineEdit = QtWidgets.QLineEdit(Form)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.reg_pwd_lineEdit.setFont(font)
self.reg_pwd_lineEdit.setObjectName("reg_pwd_lineEdit")
self.horizontalLayout_2.addWidget(self.reg_pwd_lineEdit)
self.gridLayout.addLayout(self.horizontalLayout_2, 1, 0, 1, 1)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.label_3 = QtWidgets.QLabel(Form)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label_3.setFont(font)
self.label_3.setStyleSheet("color: rgb(255, 255, 255);")
self.label_3.setObjectName("label_3")
self.horizontalLayout_3.addWidget(self.label_3)
self.reg_pwd_cf_lineEdit = QtWidgets.QLineEdit(Form)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.reg_pwd_cf_lineEdit.setFont(font)
self.reg_pwd_cf_lineEdit.setObjectName("reg_pwd_cf_lineEdit")
self.horizontalLayout_3.addWidget(self.reg_pwd_cf_lineEdit)
self.gridLayout.addLayout(self.horizontalLayout_3, 2, 0, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_4 = QtWidgets.QLabel(Form)
self.label_4.setMinimumSize(QtCore.QSize(81, 0))
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.label_4.setFont(font)
self.label_4.setStyleSheet("color: rgb(255, 255, 255);")
self.label_4.setObjectName("label_4")
self.horizontalLayout_4.addWidget(self.label_4)
self.reg_mail_lineEdit = QtWidgets.QLineEdit(Form)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.reg_mail_lineEdit.setFont(font)
self.reg_mail_lineEdit.setObjectName("reg_mail_lineEdit")
self.horizontalLayout_4.addWidget(self.reg_mail_lineEdit)
self.gridLayout.addLayout(self.horizontalLayout_4, 3, 0, 1, 1)
self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
self.horizontalLayout_5.setSpacing(0)
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.reg_pushButton = QtWidgets.QPushButton(Form)
font = QtGui.QFont()
font.setFamily("微软雅黑 Light")
font.setPointSize(14)
self.reg_pushButton.setFont(font)
self.reg_pushButton.setObjectName("reg_pushButton")
self.horizontalLayout_5.addWidget(self.reg_pushButton)
self.gridLayout.addLayout(self.horizontalLayout_5, 4, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "用 户 名 :"))
self.reg_username_lineEdit.setPlaceholderText(_translate("Form", "请输入用户名"))
self.label_2.setText(_translate("Form", "密 码:"))
self.reg_pwd_lineEdit.setPlaceholderText(_translate("Form", "请输入密码"))
self.label_3.setText(_translate("Form", "确认密码:"))
self.reg_pwd_cf_lineEdit.setPlaceholderText(_translate("Form", "再次确认密码"))
self.label_4.setText(_translate("Form", "邮 箱:"))
self.reg_mail_lineEdit.setPlaceholderText(_translate("Form", "请输入邮箱"))
self.reg_pushButton.setText(_translate("Form", "注册"))
2 工具类以及函数编写
新建_util包,在该包中主要构建一些工具类以及模块。
2.1 数据库连接工具类
python中进行数据库操作方式可以通过ORM(对象映射关系)或者直接通过SQL语句进行数据库操作,
由于项目较小,直接通过SQL语句来操作数据库了。
安装pymysql包
pip install pymysql
在用户登陆以及注册界面,我们只需要查找用户信息,以及新增用户信息两种功能,因此现阶段编写两个增查函数就可以了。在_util包中新建databaseutil,py文件,插入如下代码:
import pymysql
class DBOperationClass(object):
instance = None
def __init__(self, host: str = '127.0.0.1', port: int = 3306, user: str = 'root',
pwd: str = 'root', database: str = 'Library', charset: str = 'utf8') -> None:
"""
database operation class
:param host: the database server host name
:param port: the database server port number
:param user: the database server user name
:param pwd: the database server key
:param database: the database name
:param charset: the encode of the database server
"""
self._conn = pymysql.connect(host=host, port=port, user=user, passwd=pwd, db=database, charset=charset)
self._cur = self._conn.cursor()
@classmethod
def get_instance(cls):
"""
get a class instance just only one.
:return:the class instance
"""
if cls.instance:
return cls.instance
else:
cls.instance = DBOperationClass()
return cls.instance
def insert_user_2_db(self, data):
sql = "INSERT INTO user(id ,user_name,password,mail,role,delete_flag,create_time,delete_time) VALUE(%s,%s," \
"%s,%s,%s,%s,%s,%s)"
self._cur.execute(sql, data)
self._conn.commit()
def query_super(self, table_name, *args):
sql = "select * from {} where {} = '{}' and {}='{}'".format(table_name, args[0], args[1], args[2], args[3])
count = self._cur.execute(sql)
ret = self._cur.fetchall()
return count, ret
2.2 CommontUtil工具模块编写
- 提示框函数
def hint_dialog(widget: QWidget, icon_path: str, title: str, content: str) -> None:
"""
display a dialog with choose button
:param widget: the dialog rely on the father window
:param icon_path: the dialog icon path
:param title: the dialog title word
:param content: the dialog content is used to hint user's
:return: None
"""
tip_box = QMessageBox(QMessageBox.Information, title, content)
tip_box.setWindowIcon(QIcon(icon_path))
submit = tip_box.addButton(widget.tr('确定'), QMessageBox.YesRole)
tip_box.setModal(True)
tip_box.exec_()
if tip_box.clickedButton() == submit:
pass
else:
return
- md5加密
由于密码一般都是采用密文进行验证的,因此采用比较简单的md5进行一个加密
def get_md5_str(content: str, encode_type: str, upper_or_lower: int) -> str:
"""
get md5 encrypt content
:param content: need to encrypt content
:param encode_type: the content encode type
:param upper_or_lower: return the encrypt content format, '1' means return upper string and another numbers means
return lower string.
:return: the encrypt content with md5
example:
>>get_md5_str('123', 'utf-8', 1)
>>202CB962AC59075B964B07152D234B70
>>get_md5_str('123', 'utf-8', 0)
>>202cb962ac59075b964b07152d234b70
"""
m = hashlib.md5()
content = content.encode(encode_type)
m.update(content)
if upper_or_lower == 1:
return m.hexdigest().upper()
else:
return m.hexdigest().lower()
- uuid字符串获取
user表中的id为主键,主键必须保证唯一性。
def get_uuid1() -> uuid:
"""
get the uuid str
:return: the uuid1 object
"""
return uuid.uuid1()
- 邮箱格式验证
通过正则表达式来验证邮箱的格式
def re_email(email):
if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', email):
return True
else:
return False
3 登陆注册页面类
3.1 注册页面
注册页面主要功能是用户注册功能,注册时需要做一些判定:
- 用户输入的信息不能为空;
- 两次密码的输入必须一致;
- 邮箱输入必须为正确的邮箱格式;
- 用户输入的用户名需要判断是否在数据库中存在;
在用户点击注册按钮时,需要进行如上的判定,Qt中有特殊的信号槽机制,基本工作流程如下图所示:
通过下面所示的代码就可以将按钮的点击信号连接到对应的槽函数上了
# 按钮在QT中有内置的点击信号clicked
reg_pushbutton.clicked.connect(self.reg_function)
1. 输入判断是否为空
for temp in self.le_ls:
if temp.text() == '':
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '请输入关键信息~')
return
其中temp为每个输入框,通过text来判断用户是否输入了信息。CommonUtil是编写的工具类,hint_dialog函数如下
2.判断两次输入密码是否一致
if self.reg_pwd_lineEdit.text() != self.reg_pwd_cf_lineEdit.text():
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '两次输入的密码不一致~')
return
3.邮箱输入必须为正确的邮箱格式
if not CommonUtil.re_email(self.reg_mail_lineEdit.text()):
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '请输入正确的邮箱~')
return
4. 用户名是否存在
if self.db_helper.query_super('user', 'user_name', self.reg_username_lineEdit.text(), 'delete_flag', 0)[0] \
!= 0:
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '用户已经存在~')
return
5. 将注册用户的信息插入到数据库user表中
pwd = CommonUtil.get_md5_str(self.reg_pwd_lineEdit.text(), 'utf-8', 1)
user_id = str(CommonUtil.get_uuid1())
user_data = [user_id, self.reg_username_lineEdit.text(), pwd, self.reg_mail_lineEdit.text(), 0, 0,
CommonUtil.get_current_time(), None]
self.db_helper.insert_user_2_db(user_data)
注册页面类所有代码
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QPalette, QPixmap, QBrush
from PyQt5.QtWidgets import QWidget, QApplication
from _ui.RegisterView import Ui_Form
from _util import CommonUtil, databaseutil
class RegisterWindow(QWidget, Ui_Form):
def __init__(self, *args, **kwargs):
super(RegisterWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
self.le_ls = [self.reg_username_lineEdit, self.reg_pwd_cf_lineEdit, self.reg_pwd_lineEdit,
self.reg_mail_lineEdit]
self.icon = [CommonUtil.SUPER_DIR + r'/_res/_img/user_icon.png',
CommonUtil.SUPER_DIR + r'/_res/_img/confirm.png',
CommonUtil.SUPER_DIR + r'/_res/_img/password.png',
CommonUtil.SUPER_DIR + r'/_res/_img/email.png']
self.db_helper = databaseutil.DBOperationClass.get_instance()
self.init_ui()
self.reg_pushButton.clicked.connect(self.register)
def init_ui(self):
self.setWindowIcon(QIcon(CommonUtil.SUPER_DIR + r'/_res/_img/register_icon.png'))
self.setWindowTitle('用户注册')
CommonUtil.set_lineedit_style(self.le_ls)
self.reg_pushButton.setStyleSheet(CommonUtil.CLEAR_CURRENT_SOP_FLOW_PUSHBUTTON_STYLE)
plt = QPalette()
plt.setBrush(QPalette.Background, QBrush(QPixmap(CommonUtil.SUPER_DIR + r'/_res/_img/sign_in _widget.jpg')))
self.setPalette(plt)
self.setWindowFlags(Qt.WindowCloseButtonHint)
CommonUtil.set_edit_icon(self.le_ls, self.icon)
def register(self):
try:
for temp in self.le_ls:
if temp.text() == '':
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '请输入关键信息~')
return
if self.db_helper.query_super('user', 'user_name', self.reg_username_lineEdit.text(), 'delete_flag', 0)[0] \
!= 0:
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '用户已经存在~')
return
if self.reg_pwd_lineEdit.text() != self.reg_pwd_cf_lineEdit.text():
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '两次输入的密码不一致~')
return
if not CommonUtil.re_email(self.reg_mail_lineEdit.text()):
CommonUtil.hint_dialog(self, CommonUtil.APP_ICON, '提示', '请输入正确的邮箱~')
return
pwd = CommonUtil.get_md5_str(self.reg_pwd_lineEdit.text(), 'utf-8', 1)
user_id = str(CommonUtil.get_uuid1())
user_data = [user_id, self.reg_username_lineEdit.text(), pwd, self.reg_mail_lineEdit.text(), 0, 0,
CommonUtil.get_current_time(), None]
self.db_helper.insert_user_2_db(user_data)
except Exception as e:
print(e.args)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = RegisterWindow()
win.show()
sys.exit(app.exec_())
3.2 注册测试
运行注册页面代码:
- 当有输入框为空时
- 两次输入密码不一致
- 邮箱格式不正确
- 用户已经存在
- 注册成功
所有场景全部测试通过,用户注册页面就完成了。
备注:注册页面已经做过了美化处理,所以与在QtDesigner页面中所看见的不一样。
项目的GitHub地址:项目代码仓库