from PyQt5.QtWidgets import (
QMainWindow, QVBoxLayout, QWidget, QTableWidget, QTableWidgetItem,
QPushButton, QMessageBox, QHeaderView, QLineEdit, QLabel, QFormLayout, QHBoxLayout, QSpacerItem, QSizePolicy
)
from PyQt5.QtCore import Qt, QPropertyAnimation, QPoint, QRect
from PyQt5.QtGui import QDesktopServices
import json
import os
class PasswordManagerWindow(QMainWindow):
def __init__(self, user_id):
super().__init__()
self.user_id = user_id
self.records = []
self.init_ui()
self.load_records()
def init_ui(self):
"""初始化界面"""
self.setWindowTitle(f"密码管理器 - 用户: {self.user_id}")
self.setGeometry(100, 100, 800, 600)
# 主布局
central_widget = QWidget()
self.setCentralWidget(central_widget)
self.main_layout = QVBoxLayout(central_widget)
##t添加按钮
# 添加按钮 (固定在最上方中间)
self.add_button = QPushButton("➕")
self.add_button.setFixedSize(34, 31) # 正方形按钮
self.add_button.clicked.connect(self.show_add_form)
self.add_button.setStyleSheet('''
QPushButton {
font-size: 16px;
padding: 0px;
border - radius: 90px;
}
''')
self.main_layout.addWidget(self.add_button, alignment=Qt.AlignHCenter)
##退出按钮
self.exit_button = QPushButton("❌") # 创建退出按钮
self.exit_button.setFixedSize(32, 30) # 设置按钮大小(正方形)
self.exit_button.clicked.connect(self.close_application) # 连接点击事件
self.exit_button.setStyleSheet('''
QPushButton {
font-size: 12px;
padding: 0px;
margin - right: 10px;
border - radius: 90px;
}
''')
botton_layout = QHBoxLayout() # 新建顶部水平布局
botton_layout.addItem(QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Minimum))
botton_layout.addWidget(self.exit_button) # 添加退出按钮
index = self.main_layout.count() # 当前布局中的子布局总数
self.main_layout.insertLayout(index, botton_layout) # 插入到主布局的最顶部
##退出按钮
# 状态栏容器 (初始隐藏)
self.status_bar_container = QWidget()
self.status_bar_container.setStyleSheet("background-color: #f0f0f0; border-radius: 5px;")
self.status_bar_layout = QFormLayout(self.status_bar_container)
# 网站地址输入
self.website_input = QLineEdit()
self.status_bar_layout.addRow("网站地址:", self.website_input)
# 用户名输入
self.username_input = QLineEdit()
self.status_bar_layout.addRow("用户名:", self.username_input)
# 密码输入
self.password_input = QLineEdit()
self.password_input.setEchoMode(QLineEdit.Password)
self.status_bar_layout.addRow("密码:", self.password_input)
# 按钮框
self.save_button = QPushButton("保存")
self.save_button.clicked.connect(self.save_record)
self.cancel_button = QPushButton("取消")
self.cancel_button.clicked.connect(self.hide_add_form)
button_layout = QVBoxLayout()
button_layout.addWidget(self.save_button)
button_layout.addWidget(self.cancel_button)
self.status_bar_layout.addRow(button_layout)
self.main_layout.addWidget(self.status_bar_container)
self.status_bar_container.hide() # 初始隐藏
# 表格显示记录
self.table = QTableWidget()
self.table.setColumnCount(3)
self.table.setHorizontalHeaderLabels(["网站地址", "用户名", "密码"])
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
self.table.doubleClicked.connect(self.on_item_double_clicked)
self.main_layout.addWidget(self.table)
def close_application(self):
self.close()
def load_records(self):
"""从JSON文件加载用户记录"""
try:
with open("passwords.json", "r", encoding="utf-8") as f:
all_records = json.load(f)
self.records = [record for record in all_records if record.get("user_id") == self.user_id]
self.refresh_table()
except FileNotFoundError:
QMessageBox.warning(self, "警告", "密码记录文件不存在!")
self.records = []
def refresh_table(self):
"""刷新表格显示"""
self.table.setRowCount(len(self.records))
for row, record in enumerate(self.records):
website_item = QTableWidgetItem(record.get("website", ""))
self.table.setItem(row, 0, website_item)
username_item = QTableWidgetItem(record.get("username", ""))
self.table.setItem(row, 1, username_item)
password_item = QTableWidgetItem("***")
password_item.setData(Qt.UserRole, record)
self.table.setItem(row, 2, password_item)
def show_add_form(self):
"""显示添加表单(状态栏下滑动画)"""
# 重置输入框
self.website_input.clear()
self.username_input.clear()
self.password_input.clear()
# 显示状态栏容器
self.status_bar_container.show()
# 执行下滑动画
self.animate_status_bar(show=True)
def hide_add_form(self):
"""隐藏添加表单(状态栏上滑动画)"""
self.animate_status_bar(show=False)
# 动画完成后隐藏容器
QTimer.singleShot(300, lambda: self.status_bar_container.hide())
def animate_status_bar(self, show=True):
"""状态栏下滑/上滑动画"""
start_pos = QPoint(0, -self.status_bar_container.height()) if show else QPoint(0, 0)
end_pos = QPoint(0, 0) if show else QPoint(0, -self.status_bar_container.height())
self.animation = QPropertyAnimation(self.status_bar_container, b"pos")
self.animation.setDuration(300)
self.animation.setStartValue(start_pos)
self.animation.setEndValue(end_pos)
self.animation.start()
def save_record(self):
"""保存新记录"""
website = self.website_input.text().strip()
username = self.username_input.text().strip()
password = self.password_input.text().strip()
if not website or not username or not password:
QMessageBox.warning(self, "警告", "所有字段都必须填写!")
return
# 创建新记录
new_record = {
"user_id": self.user_id,
"website": website,
"username": username,
"password": password
}
# 添加到记录列表
self.records.append(new_record)
# 保存到文件
self.save_records_to_file()
# 刷新表格
self.refresh_table()
# 隐藏添加表单
self.hide_add_form()
def save_records_to_file(self):
"""保存记录到JSON文件"""
try:
# 读取所有记录
all_records = []
if os.path.exists("passwords.json"):
with open("passwords.json", "r", encoding="utf-8") as f:
all_records = json.load(f)
# 添加新记录
all_records.append({
"user_id": self.user_id,
"website": self.website_input.text().strip(),
"username": self.username_input.text().strip(),
"password": self.password_input.text().strip()
})
# 写入文件
with open("passwords.json", "w", encoding="utf-8") as f:
json.dump(all_records, f, indent=4, ensure_ascii=False)
except Exception as e:
QMessageBox.critical(self, "错误", f"保存记录失败: {str(e)}")
def on_item_double_clicked(self, index):
"""双击表格项事件"""
item = self.table.item(index.row(), 0)
if item:
record = item.data(Qt.UserRole)
website = record.get("website", "")
if website:
QDesktopServices.openUrl(QUrl(website))
# 测试代码
if __name__ == "__main__":
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QTimer
import sys
app = QApplication(sys.argv)
window = PasswordManagerWindow(user_id="test_user")
window.show()
sys.exit(app.exec_())
哪里出了问题?相同记录有三条?