分离edit_profile,降低耦合

This commit is contained in:
冯佳
2025-07-31 10:17:36 +08:00
parent ed4f610708
commit 627aa51235
5 changed files with 217 additions and 183 deletions

View File

@ -1,3 +1,3 @@
User,User_pass,Wifi_SSID,Modbus_IP,Modbus_Port,NFC,Reserve
User,User_pass,Wifi_SSID,Modbus_IP,Modbus_Port,NFC_ID,Reserve
测试用户,0000,zhizhan-2,10.10.100.254,8899,0000,0000
正式用户,0000,USR-DR404_3EB0,10.10.100.254,8899,0000,0000

1 User User_pass Wifi_SSID Modbus_IP Modbus_Port NFC NFC_ID Reserve
2 测试用户 0000 zhizhan-2 10.10.100.254 8899 0000 0000 0000
3 正式用户 0000 USR-DR404_3EB0 10.10.100.254 8899 0000 0000 0000

183
kv/app.kv
View File

@ -591,7 +591,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
IconLeftWidget:
icon: "email-outline"
OneLineIconListItem:
id : profile_prn
id : profile_modbus_ip
text: ""
IconLeftWidget:
icon: "dialpad"
@ -760,7 +760,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
app.secure_profile()
MDLabel:
text: "Name"
text: "User"
color: rgba(0, 0, 0, 255)
font_name: "BPoppins"
font_size: '15sp'
@ -768,7 +768,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
size_hint_x: None
width: dp(335)
MDLabel:
text: "PRN"
text: "User_pass"
color: rgba(0, 0, 0, 255)
font_name: "BPoppins"
font_size: '15sp'
@ -776,7 +776,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
size_hint_x: None
width: dp(335)
MDLabel:
text: "Email"
text: "Wifi_SSID"
color: rgba(0, 0, 0, 255)
font_name: "BPoppins"
font_size: '15sp'
@ -784,7 +784,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
size_hint_x: None
width: dp(335)
MDLabel:
text: "Phone Number"
text: "Modbus_IP"
color: rgba(0, 0, 0, 255)
font_name: "BPoppins"
font_size: '15sp'
@ -792,7 +792,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
size_hint_x: None
width: dp(335)
MDLabel:
text: "Branch"
text: "Modbus_Port"
color: rgba(0, 0, 0, 255)
font_name: "BPoppins"
font_size: '15sp'
@ -800,7 +800,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
size_hint_x: None
width: dp(335)
MDLabel:
text: "Semester"
text: "Reserve"
color: rgba(0, 0, 0, 255)
font_name: "BPoppins"
font_size: '15sp'
@ -1043,105 +1043,194 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其
app.on_press_back_arrow() # 执行返回操作
ScrollView: # 可滚动区域
id: real_time_scroll_view
size_hint: 1, None
height: self.parent.height - dp(150)
pos_hint: {'top':0.895}
MDList:
# id : image_label_grid
id: real_time_md_list
padding: "20dp", "40dp", "12dp", "17dp"
spacing: "50dp"
# MDLabel:
# text: "测试"
# font_name: "BPoppins"
# font_size: "24sp"
# pos_hint: {'center_x': 0.45}
# halign: 'center'
# bold: True
# color: rgba(0, 0, 0, 255)
# MDLabel:
# text: "曲线"
# font_name: "BPoppins"
# font_size: "24sp"
# size_hint_x: None
# width: dp(400)
# padding: "12dp"
# pos_hint: {'center_x': 0.5, 'center_y': 0.9}
# color: rgba(0, 0, 59, 255)
BoxLayout:
orientation: 'horizontal'
size_hint_x: None
width: dp(400)
pos_hint: {'center_x': 0.5, 'center_y': 0.85}
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 0:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: None
width: dp(120)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_0
comm_address: 0
unit: "倍数"
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: None
width: dp(120)
halign: "right"
size_hint_x: 0.6
input_filter: "int"
on_focus:if not self.focus: app.update_register_display(0)
on_text_validate: app.modify_register(self, self.text)
MDLabel:
text: "倍数"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: 0.4
halign: "right"
BoxLayout:
orientation: 'horizontal'
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 1:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: None
width: dp(120)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_1
comm_address: 1
unit: "A"
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: None
width: dp(120)
halign: "right"
size_hint_x: 0.6
input_filter: "int"
on_focus:if not self.focus: app.update_register_display(0)
on_text_validate: app.modify_register(self, self.text)
BoxLayout:
orientation: 'horizontal'
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 2:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: None
width: dp(120)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_2
comm_address: 2
unit: "A"
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: None
width: dp(120)
halign: "right"
size_hint_x: 0.6
input_filter: "int"
on_focus:if not self.focus: app.update_register_display(0)
on_text_validate: app.modify_register(self, self.text)
BoxLayout:
orientation: 'horizontal'
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 3:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_3
comm_address: 3
unit: "A"
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: 0.6
input_filter: "int"
on_text_validate: app.modify_register(self, self.text)
BoxLayout:
orientation: 'horizontal'
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 4:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_4
comm_address: 4
unit: "A"
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: 0.6
input_filter: "int"
on_text_validate: app.modify_register(self, self.text)
BoxLayout:
orientation: 'horizontal'
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 5:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_5
comm_address: 5
unit: "A"
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: 0.6
input_filter: "int"
on_text_validate: app.modify_register(self, self.text)
BoxLayout:
orientation: 'horizontal'
spacing: dp(10)
size_hint_y: None
height: dp(60)
MDLabel:
text: "寄存器 6:"
font_name: "MPoppins"
font_size: "18sp"
color: (135/255, 133/255, 193/255, 1)
size_hint_x: 0.4
halign: "left"
MDTextField:
id: register_value_field_6
comm_address: 6
text: ""
font_name: "MPoppins"
font_size: "18sp"
size_hint_x: 0.6
input_filter: "int"
on_text_validate: app.modify_register(self, self.text)
# CurveWidget:
# size_hint_y: None
# height: dp(300)

174
main.py
View File

@ -161,6 +161,36 @@ class app(MDApp):
self.theme_cls.font_styles["Caption"] = ["BPoppins", 13, False, 0.15]
self.theme_cls.font_styles["Overline"] = ["BPoppins", 10, True, 1.5]
def on_text_field_focus(self, instance, value):
if value:
# 当MDTextField获得焦点时
# 获取ScrollView和MDList的引用
scroll_view = self.root.get_screen('modify_current_param').ids.real_time_scroll_view
md_list = self.root.get_screen('modify_current_param').ids.real_time_md_list
# 计算MDTextField在MDList中的相对位置
# instance.y 是MDTextField在父控件BoxLayout中的y坐标
# instance.parent.y 是BoxLayout在MDList中的y坐标
# 所以MDTextField在MDList中的y坐标是 instance.y + instance.parent.y
text_field_y_in_mdlist = instance.y + instance.parent.y
# 计算需要滚动的目标位置
# 目标是让MDTextField的底部与ScrollView的底部对齐或者至少在可见区域内
# scroll_view.height 是ScrollView的可见高度
# md_list.height 是MDList的总高度
# scroll_view.scroll_y 的范围是0到10表示底部1表示顶部
# 计算MDTextField相对于MDList顶部的距离
relative_y = md_list.height - text_field_y_in_mdlist - instance.height
# 将相对距离转换为scroll_y的值
# 确保不会滚动到超出范围
if md_list.height > scroll_view.height:
target_scroll_y = relative_y / (md_list.height - scroll_view.height)
# 限制target_scroll_y在0到1之间
target_scroll_y = max(0, min(1, target_scroll_y))
scroll_view.scroll_y = target_scroll_y
def build(self):
Builder.load_file('kv/app.kv')
screen_manager = ScreenManager()
@ -704,143 +734,21 @@ class app(MDApp):
threading.Thread(target=_connect_in_background, daemon=True).start()
###############################################SIGNUP Page Functions#####################################################
# signup Verification function "check_signup"
# def check_signup(self, name, prn, email, num, password, branch, sem, Wifi_SSID, modbus_ip, modbus_port):
# if name == "" or prn == "" or email == "" or num == "" or password == "" or branch == "" or sem == "":
# check = "Enter all required fields"
# return self.dialog1(check)
# else:
# status = "None"
# with open('data/Users.csv', "r") as file:
# csv_reader = csv.reader(file, delimiter=',')
# for line in csv_reader:
# try:
# if line[3] == num:
# status = "num"
# break
# if line[1] == prn:
# status = "prn"
# break
# if line[2] == email:
# status = "email"
# break
# else:
# status = False
# except IndexError:
# pass
# if status == "num":
# check = "Number already registered Please enter a new number"
# return self.dialog1(check)
# elif status == "prn":
# check = "PRN already registered Please enter a PRN"
# return self.dialog1(check)
# elif status == "email":
# check = "Email already registered Please enter a new email"
# return self.dialog1(check)
# else:
# self.root.current = "otp"
# self.send_otp(num)
# # 保存注册信息时包含Modbus信息
# self.signup_modbus_ip = modbus_ip
# self.signup_modbus_port = modbus_port
# check = "One Time Password has been shared on your registered Whatsapp No. Successful!."
# self.dialog1(check)
##################################################FORGOT PassWord Page##################################################
# # FORGOT PASSWORD page mobile number verification function 'verify_no'
# def verify_no(self):
# status = False
# if self.mobile_no.text == "":
# check = "Please enter your Mobile Number."
# return self.dialog1(check)
# else:
# with open('data/Users.csv', "r", encoding="utf-8") as file:
# csv_reader = csv.reader(file, delimiter=",")
# for line in csv_reader:
# try:
# if line[3] == self.mobile_no.text:
# status = True
# break
# else:
# status = False
# except IndexError:
# pass
# except Exception as e:
# print(e)
# if status:
# check = "One Time Password has been shared on your registered Whatsapp No. Successful!."
# self.root.current = "otp"
# self.send_otp(self.mobile_no.text)
# return self.dialog1(check)
# else:
# check = "Enter Registered Mobile Number."
# self.dialog1(check)
# def reset_password(self):
# if self.new_pass.text == "" or self.new_pass1.text == "":
# check = "Please enter your new password"
# return self.dialog1(check)
# elif not self.new_pass.text == self.new_pass1.text:
# check = "Password Does Not Match. \nPlease Re-check your password."
# return self.dialog1(check)
# else:
# with open('data/Users.csv', "r", encoding="utf-8") as file:
# csv_reader = csv.DictReader(file, delimiter=",")
# rows = [row for row in csv_reader]
# for row in rows:
# if row['Reserve'] == self.mobile_no.text:
# row['User_pass'] = self.new_pass.text
# break
# try:
# with open('data/Users.csv', "w", newline='', encoding="utf-8") as file:
# headers = ["User", "Reserve", "Student_Email", "Reserve", "User_pass",
# "Branch", "Semester"]
# csv_writer = csv.DictWriter(file, fieldnames=headers)
# csv_writer.writeheader()
# csv_writer.writerows(rows)
# check = "Password Updated Successfully!"
# self.root.current = "login"
# except Exception as e:
# print(e)
# check = "Something went wrong please try again."
# self.dialog1(check)
###############################################PROFILE & EDIT Profile Page##############################################
def edit_profile(self):
if self.edit_name.text == "" or self.edit_prn.text == "" or self.edit_email.text == "" or self.edit_number.text == "":
check = "Enter all required fields"
return self.dialog1(check)
else:
with open('data/Users.csv', "r", encoding="utf-8") as file:
csv_reader = csv.DictReader(file, delimiter=",")
rows = [row for row in csv_reader]
for row in rows:
if row['Wifi_SSID'] == self.profile_wifi_ssid.text:
row['User'] = self.edit_name.text
row['User_pass'] = self.edit_prn.text
row['Wifi_SSID'] = self.edit_email.text
row['Modbus_IP'] = self.edit_number.text
row['Modbus_Port'] = self.password.text
row['Reserve'] = self.edit_branch.text
row['Reserve'] = self.edit_semester.text
break
with open('data/Users.csv', newline="", mode="w", encoding="utf-8") as file:
header = ["User", "User_pass", "Wifi_SSID", "Modbus_IP", "Modbus_Port",
"Reserve", "Reserve"]
csv_writer = csv.DictWriter(file, fieldnames=header)
csv_writer.writeheader()
csv_writer.writerows(rows)
user_data = {
'User': self.edit_name.text,
'User_pass': self.edit_prn.text,
'Wifi_SSID': self.edit_email.text,
'Modbus_IP': self.edit_number.text,
'Modbus_Port': self.password.text,
'Reserve_branch': self.edit_branch.text,
'Reserve_semester': self.edit_semester.text
}
update_user_profile(user_data, self.profile_wifi_ssid.text)
self.verify(True)
self.root.current = "home"
@ -850,6 +758,8 @@ class app(MDApp):
self.profile_edit_screen.ids.edit_no.readonly = True
self.profile_edit_screen.ids.edit_private_credential_butn.disabled = False
from user_data_manager import update_user_profile
if __name__ == '__main__':
app().run()

View File

@ -15,7 +15,7 @@ class ModbusClient:
self.master = modbus_tcp.TcpMaster(host=ip, port=port)
self.master.set_timeout(5.0)
self.master.set_verbose(False)
# Test connection
self.master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1)
return {'success': True, 'msg': f"Modbus连接成功\nIP: {ip}\n端口: {port}"}
except modbus_tk.modbus.ModbusError as e:

35
user_data_manager.py Normal file
View File

@ -0,0 +1,35 @@
import csv
def update_user_profile(user_data, profile_wifi_ssid):
"""
Updates user profile information in the Users.csv file.
Args:
user_data (dict): A dictionary containing user profile data (e.g., 'User', 'User_pass', etc.).
profile_wifi_ssid (str): The Wifi_SSID of the user to update.
"""
with open('data/Users.csv', "r", encoding="utf-8") as file:
csv_reader = csv.DictReader(file, delimiter=",")
rows = [row for row in csv_reader]
for row in rows:
if row['Wifi_SSID'] == profile_wifi_ssid:
row['User'] = user_data['User']
row['User_pass'] = user_data['User_pass']
row['Wifi_SSID'] = user_data['Wifi_SSID']
row['Modbus_IP'] = user_data['Modbus_IP']
row['Modbus_Port'] = user_data['Modbus_Port']
# The original code had 'Reserve' overwritten twice. Assuming it's a single 'Reserve' column.
# If there are two distinct 'Reserve' fields (e.g., branch and semester), the CSV header and logic need clarification.
# For now, I'll use the last assigned value for 'Reserve' as per original logic.
row['Reserve'] = user_data['Reserve_branch'] # Assuming this is for branch
row['Reserve'] = user_data['Reserve_semester'] # This will overwrite the previous 'Reserve' value
break
with open('data/Users.csv', newline="", mode="w", encoding="utf-8") as file:
# The original header had two 'Reserve' columns. This is unusual for CSV and might be a typo.
# I will use a single 'Reserve' column as it's more common, or clarify if two are truly needed.
# Based on the original code, it seems like the second 'Reserve' assignment overwrites the first.
header = ["User", "User_pass", "Wifi_SSID", "Modbus_IP", "Modbus_Port", "Reserve"]
csv_writer = csv.DictWriter(file, fieldnames=header)
csv_writer.writeheader()
csv_writer.writerows(rows)