create my toolbox -- first commit

This commit is contained in:
2025-09-26 08:39:05 +08:00
parent 34c74bf3d0
commit bb3ae1e65a
273 changed files with 903 additions and 1052 deletions

View File

@@ -0,0 +1,238 @@
import sys
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QListWidget, QStackedWidget, QCheckBox, QSpinBox, QToolBox, QLineEdit, QTableWidget, QTreeWidget, QCalendarWidget, QMessageBox, QToolBar, QSizePolicy
from PySide6.QtCore import Qt, QTime, QSize, QRect,QEvent, QThread
from PySide6.QtGui import QCursor, QFont, QIcon, QImage, QPixmap, QShortcut
from codes.common import clibs, db_operation
from codes.common.secure_encrypt import PassCipher
from codes.ui import main_ui
class LoginWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
self.setup_slot()
self.predos()
self.le_username.setFocus()
def init_ui(self):
self.setMinimumSize(420, 200)
self.setMaximumSize(500, 240)
self.resize(480, 200)
self.setWindowTitle("登录")
self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
self.setFont(QFont("Consolas", 14))
self.layout_outter = QHBoxLayout()
self.lb_logo = QLabel()
self.lb_logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.lb_logo.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
self.lb_logo.setPixmap(QPixmap(f"{clibs.base_path}/assets/media/logo.png"))
self.lb_logo.setFixedSize(QSize(120, 120))
self.lb_logo.setScaledContents(True)
self.layout_outter.addWidget(self.lb_logo)
self.tabW_login = QTabWidget()
self.tab_login = QWidget()
self.tabW_login.addTab(self.tab_login, "登录")
self.tab_register = QWidget()
self.tabW_login.addTab(self.tab_register, "注册")
self.layout_outter.addWidget(self.tabW_login)
# 登陆页面
self.layout_H_username = QHBoxLayout()
self.lb_username = QLabel("账号")
self.lb_username.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout_H_username.addWidget(self.lb_username)
self.le_username = QLineEdit()
self.le_username.setFocus()
self.layout_H_username.addWidget(self.le_username)
self.layout_H_password = QHBoxLayout()
self.lb_password = QLabel("密码")
self.lb_password.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout_H_password.addWidget(self.lb_password)
self.le_password = QLineEdit()
self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
self.layout_H_password.addWidget(self.le_password)
self.layout_H_button = QHBoxLayout()
self.btn_login = QPushButton("登录")
self.btn_login.setAutoDefault(True)
self.btn_cancel = QPushButton("取消")
self.btn_cancel.setAutoDefault(True)
self.layout_H_button.addWidget(self.btn_login)
self.layout_H_button.addWidget(self.btn_cancel)
self.layout_V_user_pass = QVBoxLayout()
self.layout_V_user_pass.addLayout(self.layout_H_username)
self.layout_V_user_pass.addLayout(self.layout_H_password)
self.layout_V_user_pass.addLayout(self.layout_H_button)
self.tab_login.setLayout(self.layout_V_user_pass)
# 注册页面
self.layout_H_username_reg = QHBoxLayout()
self.lb_username_reg = QLabel("账号设定")
self.lb_username_reg.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout_H_username_reg.addWidget(self.lb_username_reg)
self.le_username_reg = QLineEdit()
self.le_username_reg.setFocus()
self.layout_H_username_reg.addWidget(self.le_username_reg)
self.layout_H_password_reg = QHBoxLayout()
self.lb_password_reg = QLabel("密码设定")
self.lb_password_reg.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout_H_password_reg.addWidget(self.lb_password_reg)
self.le_password_reg = QLineEdit()
self.le_password_reg.setEchoMode(QLineEdit.EchoMode.Password)
self.layout_H_password_reg.addWidget(self.le_password_reg)
self.layout_H_password_reg_confirm = QHBoxLayout()
self.lb_password_reg_confirm = QLabel("密码确认")
self.lb_password_reg_confirm.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.layout_H_password_reg_confirm.addWidget(self.lb_password_reg_confirm)
self.le_password_reg_confirm = QLineEdit()
self.le_password_reg_confirm.setEchoMode(QLineEdit.EchoMode.Password)
self.layout_H_password_reg_confirm.addWidget(self.le_password_reg_confirm)
self.layout_H_button_reg = QHBoxLayout()
self.btn_login_reg = QPushButton("确认")
self.btn_login_reg.setAutoDefault(True)
self.btn_cancel_reg = QPushButton("取消")
self.btn_cancel_reg.setAutoDefault(True)
self.layout_H_button_reg.addWidget(self.btn_login_reg)
self.layout_H_button_reg.addWidget(self.btn_cancel_reg)
self.layout_V_user_pass_reg = QVBoxLayout()
self.layout_V_user_pass_reg.addLayout(self.layout_H_username_reg)
self.layout_V_user_pass_reg.addLayout(self.layout_H_password_reg)
self.layout_V_user_pass_reg.addLayout(self.layout_H_password_reg_confirm)
self.layout_V_user_pass_reg.addLayout(self.layout_H_button_reg)
self.tab_register.setLayout(self.layout_V_user_pass_reg)
self.setLayout(self.layout_outter)
def setup_slot(self):
self.tabW_login.currentChanged.connect(self.onChange_tabW)
self.btn_login.clicked.connect(self.login_check)
self.btn_cancel.clicked.connect(self.close)
self.btn_login_reg.clicked.connect(self.register_check)
self.btn_cancel_reg.clicked.connect(self.close)
QShortcut("Esc", self).activated.connect(self.close)
self.le_password.returnPressed.connect(self.login_check)
self.le_password_reg_confirm.returnPressed.connect(self.register_check)
def predos(self):
db_file = clibs.base_path / "assets/database/toolbox.db"
if not db_file.exists():
db_operation.db_init(db_file)
def onChange_tabW(self):
text = self.tabW_login.tabText(self.tabW_login.currentIndex())
if text == "登录":
self.le_username.clear()
self.le_password.clear()
self.le_username.setFocus()
elif text == "注册":
self.le_username_reg.clear()
self.le_password_reg.clear()
self.le_password_reg_confirm.clear()
self.le_username_reg.setFocus()
else:
raise Exception(f"Unknown TabWidget Name: {text}")
def login_check(self):
def login_failed():
self.le_username.clear()
self.le_password.clear()
self.le_username.setFocus()
QMessageBox.critical(self, "错误", "账号或密码错误,请重新输入!")
def validate_login():
nonlocal username, password
conn, cursor = db_operation.db_conn()
cursor.execute(f""" SELECT * FROM users where username = "{username}" """)
record = cursor.fetchall()
if len(record) == 0:
login_failed()
elif len(record) == 1:
keys = ["id", "timestamp", "username", "password", "salt"]
login_info = dict(zip(keys, record[0]))
salt = PassCipher.gen_salt("@".join([username, password]))
cipher = PassCipher(salt)
# password_encrypt = cipher.encrypt("@".join([username, password]))
# print(f"password_encrypt = {password_encrypt}")
# exit()
try:
decrypt_password = cipher.decrypt(login_info["password"])
if password != decrypt_password:
login_failed()
return False
else:
self.mainWindow = main_ui.MainWindow()
self.mainWindow.show()
db_operation.db_close(conn, cursor)
clibs.username = username
clibs.password = password
self.close()
return True
except ValueError:
login_failed()
return False
else:
raise Exception(f"username duplicated: {username}")
username = self.le_username.text()
password = self.le_password.text()
validate_login()
def register_check(self):
def register_failed(flag: int = 0):
self.le_username_reg.clear()
self.le_password_reg.clear()
self.le_password_reg_confirm.clear()
self.le_username_reg.setFocus()
if flag == 0:
QMessageBox.critical(self, "错误", "账号已存在,或两次输入密码不一致,请重新输入!")
elif flag == 1:
QMessageBox.critical(self, "错误", "密码长度不符合要求,请重新输入!")
def validate_register():
nonlocal username, password, password_confirm, record, conn, cursor
if password != password_confirm:
register_failed()
return False
if len(password) < clibs.account["minimum_password_length"]:
register_failed(flag=1)
return False
if len(record) == 0:
salt = PassCipher.gen_salt("@".join([username, password]))
cipher = PassCipher(salt)
password_encrypted = cipher.encrypt(password)
cursor.execute("INSERT INTO users (username, password, salt) VALUES (?, ?, ?)", (username, password_encrypted, salt))
QMessageBox.information(self, "成功", "注册成功,切换至登录窗口进行登录!")
self.tabW_login.setCurrentIndex(self.tabW_login.indexOf(self.tab_login))
return True
elif len(record) == 1:
register_failed()
return False
else:
raise Exception(f"username duplicated: {username}")
username = self.le_username_reg.text()
password = self.le_password_reg.text()
password_confirm = self.le_password_reg_confirm.text()
conn, cursor = db_operation.db_conn()
cursor.execute(f""" SELECT * FROM users where username = "{username}" """)
record = cursor.fetchall()
validate_register()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = LoginWindow()
window.show()
sys.exit(app.exec())

208
toolbox/codes/ui/main_ui.py Normal file
View File

@@ -0,0 +1,208 @@
import json
from math import lgamma
from shutil import copy
from random import choice
from pathlib import Path
import sys
import requests
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QListWidget, QStackedWidget, QCheckBox, QSpinBox, QToolBox, QLineEdit, QTableWidget, QTreeWidget, QCalendarWidget, QMessageBox, QToolBar, QSizePolicy, QMainWindow, QStatusBar
from PySide6.QtCore import Qt, QTime, QSize, QRect,QEvent, QThread
from PySide6.QtGui import QCursor, QFont, QIcon, QImage, QPixmap, QShortcut, QAction, QKeySequence, QResizeEvent
from codes.common import clibs, db_operation
from codes.ui.widget_bg_ui import WidgetWithBg
from codes.common.worker import Worker
from typing import Callable, Any
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.init_ui()
self.setup_slot()
self.predos()
def init_ui(self):
self.setMinimumSize(clibs.win_width, clibs.win_height)
self.resize(clibs.win_width, clibs.win_height)
self.setWindowTitle("Toolbox")
self.setWindowIcon(QIcon(f"{clibs.base_path}/assets/media/icon.ico"))
self.setFont(QFont("Consolas", 14))
# 任务栏/主窗口/状态栏
self.toolBar = QToolBar()
self.addToolBar(self.toolBar)
self.toolBar.setMovable(False)
self.centralW = QWidget()
self.setCentralWidget(self.centralW)
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
# toolbar
self.ac_homepage = QAction()
self.ac_homepage.setMenuRole(QAction.MenuRole.NoRole)
self.ac_homepage.setStatusTip("Go to homepage")
self.ac_homepage.setToolTip("Ctrl+Alt+H")
self.ac_homepage.setText("主页")
self.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
self.toolBar.addAction(self.ac_homepage)
def setup_slot(self):
self.ac_homepage.triggered.connect(self.ac_hp)
# QShortcut("Esc", self).activated.connect(self.close)
def predos(self):
self.home_overlay = None
db_operation.db_backup()
self.conn, self.cursor = db_operation.db_conn()
def ac_hp(self):
def get_files(dir_path):
folder = Path(dir_path)
files = [p for p in folder.rglob("*") if p.is_file()]
return choice(files), files
def del_repeat_proverb(proverbs: list):
_proverbs = []
for proverb in proverbs:
if proverb not in _proverbs:
_proverbs.append(proverb)
return _proverbs
def get_resources():
# background image
bing = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8"
req = requests.get(bing)
res = req.json()
_, files = get_files(f"{clibs.base_path}/assets/media/bg")
image_names = []
for file in files:
image_names.append(file.name.removesuffix(".jpg"))
for image in res["images"]:
startdate = image["startdate"]
if startdate in image_names:
continue
else:
image_url = f"""https://www.bing.com{image["url"]}"""
file = Path(f"{clibs.base_path}/assets/media/bg/{startdate}.jpg")
try:
req = requests.get(image_url, stream=True, timeout=10)
with open(file, "wb") as f:
for chunk in req.iter_content(chunk_size=8192):
f.write(chunk)
except Exception as e:
pass
# proverbs
hitokoto = "https://v1.hitokoto.cn/"
proverbs = []
try:
req = requests.get(hitokoto)
with open(f"{clibs.base_path}/assets/media/hitokoto.json", mode="rt", encoding="utf-8") as f:
proverbs = json.load(f)
proverbs.append(eval(req.text))
proverbs = del_repeat_proverb(proverbs)
with open(f"{clibs.base_path}/assets/media/hitokoto.json", mode="wt", encoding="utf-8") as f:
json.dump(proverbs, f, ensure_ascii=False)
except Exception as e:
pass
def change_resources():
# avatar
src, _ = get_files(f"{clibs.base_path}/assets/media/avatar")
dst = f"{clibs.base_path}/assets/media/avatar.jpg"
copy(src, dst)
# proverbs
with open(f"{clibs.base_path}/assets/media/hitokoto.json", mode="r", encoding="utf-8") as f:
proverbs = json.load(f)
res = choice(proverbs)
sentence = res["hitokoto"]
from_where = res["from"]
from_who = res["from_who"]
clibs.proverb = f"{sentence}\t\t※⌈{from_where}⌋ | {from_who}"
# bg
src, _ = get_files(f"{clibs.base_path}/assets/media/bg")
dst = f"{clibs.base_path}/assets/media/bg.jpg"
copy(src, dst)
def gen_page():
self.set_shortcuts(False)
self.home_overlay = WidgetWithBg(parent=self)
self.home_overlay.on_closed.connect(self.exit_overlay)
self.home_overlay.on_full_screen.connect(self.full_screen)
self.home_overlay.show()
width, height = self.width(), self.height()
if width > clibs.win_width:
self.resize(self.width()-1, self.height()-1)
else:
self.resize(clibs.win_width+1, clibs.win_height+1)
change_resources()
self.launch_get_resources(get_resources)
gen_page()
def full_screen(self, flag: bool):
if flag == 0:
if self.isFullScreen():
self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
self.show()
self.showMaximized()
else:
self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
self.showFullScreen()
elif flag == 1:
self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
self.show()
self.showMaximized()
def exit_overlay(self):
self.set_shortcuts(True)
if self.isFullScreen():
self.setWindowFlags(self.windowFlags() ^ Qt.WindowType.WindowStaysOnTopHint)
self.show()
self.showMaximized()
def set_shortcuts(self, stat: bool = True):
if stat:
self.ac_homepage.setShortcut(QKeySequence("Ctrl+Alt+H"))
# self.ac_settings.setShortcut(QKeySequence("Ctrl+Alt+S"))
# self.ac_logs.setShortcut(QKeySequence("Ctrl+Alt+L"))
# self.ac_about.setShortcut(QKeySequence("Ctrl+Alt+A"))
# self.ac_caging.setShortcut(QKeySequence("Ctrl+Alt+C"))
# self.ac_quit.setShortcut(QKeySequence("Ctrl+Alt+Q"))
else:
self.ac_homepage.setShortcut(QKeySequence())
# self.ac_settings.setShortcut(QKeySequence())
# self.ac_logs.setShortcut(QKeySequence())
# self.ac_about.setShortcut(QKeySequence())
# self.ac_caging.setShortcut(QKeySequence())
# self.ac_quit.setShortcut(QKeySequence())
def launch_get_resources(self, func, on_anything: Callable[..., Any] = None, *args, **kwargs):
self.td_get_resources = Worker(func, *args, **kwargs)
self.td_get_resources.started.connect(lambda: None)
self.td_get_resources.result.connect(lambda: None)
self.td_get_resources.error.connect(lambda: None)
self.td_get_resources.finished.connect(lambda: None)
self.td_get_resources.start()
def resizeEvent(self, event: QResizeEvent):
super().resizeEvent(event)
if self.home_overlay:
self.home_overlay.setGeometry(self.rect())
def closeEvent(self, event):
if self.isFullScreen():
event.ignore()
return
reply = QMessageBox.question(self, "退出", "\n程序可能在运行,确定要退出吗?")
if reply == QMessageBox.StandardButton.Yes:
db_operation.db_close(self.conn, self.cursor)
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>602</width>
<height>376</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>125</width>
<height>125</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>125</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>../../assets/media/avatar.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Manford Fan · Code Create Life</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Sunken</enum>
</property>
<property name="midLineWidth">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="frameShadow">
<enum>QFrame::Shadow::Sunken</enum>
</property>
<property name="text">
<string>memo</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,9">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>TextLabel</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,216 @@
import sys
from PySide6.QtWidgets import QWidget, QApplication, QSizePolicy, QVBoxLayout, QLabel, QFrame, QHBoxLayout, QLineEdit, QMessageBox
from PySide6.QtGui import QPixmap, QPainter, QFontDatabase, QFont, QBrush, QShortcut, QKeySequence, QColor
from PySide6.QtCore import Qt, QPoint, QDateTime, Signal, QTimer
from zhdate import ZhDate
from codes.common import clibs
class LunarClockLabel(QLabel):
def __init__(self, parent=None):
super().__init__(parent)
self.setMinimumWidth(350)
timer = QTimer(self)
timer.timeout.connect(self.update_time)
timer.start(1000)
self.update_time()
def update_time(self):
dt = QDateTime.currentDateTime()
g = dt.date()
z = ZhDate.today()
week = "一二三四五六日"[g.dayOfWeek() - 1]
text = f"{g.year()}{g.month()}{g.day()}{z.chinese()[5:]} 星期{week} {dt.toString('hh:mm:ss')}"
self.setText(text)
class DoubleClickLabel(QLabel):
doubleClicked = Signal()
def mouseDoubleClickEvent(self, event):
super().mouseDoubleClickEvent(event)
self.doubleClicked.emit()
class WidgetWithBg(QWidget):
on_closed = Signal()
on_full_screen = Signal(int)
def __init__(self, parent=None):
super().__init__(parent)
self.predos()
self.init_ui()
self.setup_slot()
def predos(self):
font_id = QFontDatabase.addApplicationFont(f"{clibs.base_path}/assets/media/font/OldEnglishTextMT/OldEnglishTextMT.ttf")
family = QFontDatabase.applicationFontFamilies(font_id)[0]
self.lb_font = QFont(family, 28, QFont.Weight.Medium)
self.background_pixmap = QPixmap(clibs.bg)
def init_ui(self):
layout_v = QVBoxLayout()
# 最上层的空白区
self.lb_empty_up = QLabel(self)
layout_v.addWidget(self.lb_empty_up)
# 头像区
self.lb_avatar = DoubleClickLabel(self)
self.lb_avatar.setAlignment(Qt.AlignmentFlag.AlignCenter)
avatar = QPixmap(clibs.avatar)
avatar = self.circle_pixmap(avatar, 200)
self.lb_avatar.setPixmap(avatar)
self.lb_avatar.setScaledContents(True)
self.lb_avatar.setFixedSize(144, 144)
layout_v.addWidget(self.lb_avatar, alignment=Qt.AlignmentFlag.AlignCenter)
# 艺术字区
self.lb_name = QLabel(self)
self.lb_name.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.lb_name.setText("Manford Fan · Code Create Life")
self.lb_name.setStyleSheet("color: rgba(255,255,255,255);")
self.lb_name.setFont(self.lb_font)
layout_v.addWidget(self.lb_name)
# 时间区-左横线
layout_h = QHBoxLayout()
self.line_left = QFrame(self)
self.line_left.setFrameShape(QFrame.Shape.HLine)
self.line_left.setFrameShadow(QFrame.Shadow.Plain)
self.line_left.setStyleSheet("""
QFrame {
border: none;
background-color: rgba(255, 255, 255, 40);
}
""")
policy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
self.line_left.setSizePolicy(policy)
self.line_left.setLineWidth(1)
self.line_left.setFixedWidth(100)
# 时间区-右横线
self.line_right = QFrame(self)
self.line_right.setFrameShape(QFrame.Shape.HLine)
self.line_right.setFrameShadow(QFrame.Shadow.Plain)
self.line_right.setStyleSheet("""
QFrame {
border: none;
background-color: rgba(255, 255, 255, 40);
}
""")
policy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
self.line_right.setSizePolicy(policy)
self.line_right.setLineWidth(1)
self.line_right.setFixedWidth(100)
# 时间区-时间
self.lb_time = LunarClockLabel(self)
self.lb_time.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.lb_time.setStyleSheet("color: rgba(255,255,255,255);")
self.lb_time.setFont(QFont("Consolas", 12, QFont.Weight.Bold))
layout_h.addStretch(1)
layout_h.addWidget(self.line_left)
layout_h.addWidget(self.lb_time)
layout_h.addWidget(self.line_right)
layout_h.addStretch(1)
layout_v.addLayout(layout_h)
# layout_v.addWidget(self.line, alignment=Qt.AlignmentFlag.AlignCenter)
self.lb_proverb = QLabel(self)
self.lb_proverb.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.lb_proverb.setText(clibs.proverb)
self.lb_proverb.setStyleSheet("color: rgba(255,255,255,255);")
self.lb_proverb.setFont(QFont("Consolas", 14, QFont.Weight.Bold))
layout_v.addWidget(self.lb_proverb)
self.le_password = QLineEdit(self)
self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
self.le_password.setFont(QFont("Consolas", 12, QFont.Weight.Normal))
self.le_password.setMinimumWidth(300)
self.le_password.setFixedHeight(30)
self.hide_le_password()
layout_v.addWidget(self.le_password, alignment=Qt.AlignmentFlag.AlignCenter)
self.lb_empty_down = QLabel(self)
layout_v.addWidget(self.lb_empty_down)
layout_v.setStretch(0, 2) # empty up
layout_v.setStretch(1, 2) # avatar
layout_v.setStretch(2, 1) # name
layout_v.setStretch(3, 2) # time
layout_v.setStretch(4, 1) # proverb
layout_v.setStretch(5, 1) # password
layout_v.setStretch(6, 2) # empty down
self.setLayout(layout_v)
def setup_slot(self):
self.lb_avatar.doubleClicked.connect(self.auth_show)
self.le_password.returnPressed.connect(self.validate_password)
QShortcut(QKeySequence("Ctrl+Alt+L"), self, self.auth_show)
QShortcut(QKeySequence("Ctrl+Alt+S"), self, lambda: self.on_full_screen.emit(0))
# QShortcut(QKeySequence("Esc"), self).activated.connect(lambda: self.on_full_screen.emit(1))
def auth_show(self):
if self.input_hide:
self.show_le_password()
else:
self.hide_le_password()
def show_le_password(self):
self.input_hide = False
self.le_password.clear()
self.le_password.setPlaceholderText("Password")
self.le_password.setStyleSheet("")
self.le_password.setDisabled(False)
self.le_password.setFocus()
def hide_le_password(self):
self.input_hide = True
self.le_password.clear()
self.le_password.setDisabled(True)
self.le_password.setPlaceholderText("")
self.le_password.setStyleSheet("background:transparent; color:rgba(0,0,0,0); border:none; ")
def validate_password(self):
password = self.le_password.text()
if password == clibs.password:
self.on_closed.emit()
self.close()
elif password == "":
self.hide_le_password()
return
else:
QMessageBox.critical(self, "错误", "密码不正确,请确认后重新输入!")
self.show_le_password()
@staticmethod
def circle_pixmap(src: QPixmap, diameter: int) -> QPixmap:
dst = QPixmap(diameter, diameter)
dst.fill(Qt.GlobalColor.transparent)
painter = QPainter(dst)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.setPen(Qt.PenStyle.NoPen)
painter.setBrush(QBrush(src))
painter.drawEllipse(dst.rect())
painter.end()
return dst
def paintEvent(self, event):
if not self.background_pixmap.isNull():
painter = QPainter(self)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
scaled_pixmap = self.background_pixmap.scaled(self.size(), Qt.AspectRatioMode.IgnoreAspectRatio, Qt.TransformationMode.SmoothTransformation)
x = (self.width() - scaled_pixmap.width()) // 2
y = (self.height() - scaled_pixmap.height()) // 2
painter.drawPixmap(QPoint(x, y), scaled_pixmap)
painter.setBrush(QColor(0, 0, 0, 144)) # 144 ≈ 50% 暗度,越大越暗
painter.setPen(Qt.PenStyle.NoPen)
painter.drawRect(self.rect())
painter.end()
super().paintEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
your_widget = WidgetWithBg()
your_widget.resize(1000, 450)
your_widget.show()
sys.exit(app.exec())