好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 bloodfog 于 2024-6-19 15:27 编辑
闲来无聊写个简易的html娱乐用的计分器
[HTML] 纯文本查看 复制代码 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QP计分器</title>
<style>
body {
font-family: "仿宋";
background-color: #f0f0f0;
margin: 0;
padding: 20px;
font-size: 12px;
}
.container {
max-width: 98%;
margin: 0 auto;
background-color: #fff;
padding: 5px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
overflow-x: auto; /* 添加水平滚动条 */
}
.controls {
text-align: center;
margin-bottom: 5px;
font-size:12px;
}
.controls input, .controls button {
padding: 5px;
margin: 5px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
height: 32px;
line-height: 22px;
}
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed; /* 表格宽度固定 */
}
th, td {
border: 1px solid #ddd;
padding: 5px;
text-align: center;
white-space: nowrap;
}
th {
background-color: #f4f4f4;
}
.delete-btn {
color: red;
cursor: pointer;
}
input[type=number] {
width: 100%;
border: none;
text-align: center;
box-sizing: border-box;
}
input[type=number]:focus {
border: 1px solid #ccc; /* 输入状态时的边框颜色为淡灰色 */
outline: none;
}
tbody tr:nth-child(odd) {
background-color: #d8eafc; /* 奇数行背景淡蓝色 */
}
tbody tr:nth-child(even) {
background-color: #d0f0c0; /* 偶数行背景淡绿色 */
}
tbody tr:nth-child(odd) input[type=number] {
background-color: #d8eafc; /* 奇数行背景淡蓝色 */
border: 1px solid #d8eafc;
}
tbody tr:nth-child(even) input[type=number] {
background-color: #d0f0c0; /* 偶数行背景淡绿色 */
border: 1px solid #d0f0c0;
}
.alert-box {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
border-radius: 10px;
text-align: center;
}
.alert-box h2 {
margin: 0 0 10px 0;
}
.alert-box p {
margin: 0 0 20px 0;
}
</style>
</head>
<body>
<div class="container">
<div class="controls">
<input type="text" id="username" placeholder="输入玩家昵称" style="height:20px; width:90px; line-height:20px; padding:5px; font-size:14px;" autocomplete="off">
<button>新玩家</button>
<button>添加一局</button>
<button>重置</button>
</div>
<table id="scoreTable">
<thead>
<tr>
<th style="width:70px; height:25px; line-height:25px;">玩家</th>
<th style="width:60px;">合计</th>
<th style="width:60px;">操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script>
let users = JSON.parse(localStorage.getItem('users')) || [];
let rounds = parseInt(localStorage.getItem('rounds')) || 0;
function saveData() {
localStorage.setItem('users', JSON.stringify(users));
localStorage.setItem('rounds', rounds.toString());
}
function loadData() {
if (users.length > 0) {
for (let i = 0; i < rounds; i++) {
addRoundHeader(i);
}
users.forEach(user => addUserToTable(user.username, user.scores));
}
}
function addUser() {
const username = document.getElementById('username').value;
if (!username) {
showAlert("请先输入玩家昵称");
return;
}
if (username && !users.find(user => user.username === username)) {
const user = { username: username, scores: Array(rounds).fill(0) };
users.push(user);
addUserToTable(username, user.scores);
saveData();
document.getElementById('username').value = '';
}
}
function addUserToTable(username, scores = []) {
const table = document.getElementById('scoreTable').getElementsByTagName('tbody')[0];
const row = table.insertRow();
row.setAttribute('data-username', username);
const cell1 = row.insertCell(0);
cell1.textContent = username;
const totalCell = row.insertCell(1);
totalCell.textContent = scores.reduce((a, b) => a + b, 0);
scores.forEach(score => {
const scoreCell = row.insertCell(-1);
scoreCell.innerHTML = `<input type="number" value="${score}">`;
});
const cell2 = row.insertCell(-1);
cell2.innerHTML = '<span class="delete-btn">移除</span>';
}
function confirmDeleteUser(element) {
showConfirm("确定要移除此玩家吗?", () => {
const row = element.parentNode.parentNode;
const username = row.getAttribute('data-username');
users = users.filter(user => user.username !== username);
row.remove();
saveData();
});
}
function addRound() {
rounds++;
users.forEach(user => user.scores.unshift(0));
addRoundHeader(rounds - 1);
saveData();
}
function addRoundHeader(roundIndex) {
const table = document.getElementById('scoreTable');
const th = document.createElement('th');
th.textContent = '第 ' + (roundIndex + 1) + ' 局';
th.style.width = '60px'; // 固定宽度为60px
const headerRow = table.getElementsByTagName('thead')[0].rows[0];
headerRow.insertBefore(th, headerRow.cells[2]);
const tbody = table.getElementsByTagName('tbody')[0];
Array.from(tbody.rows).forEach((row) => {
const cell = row.insertCell(2);
cell.innerHTML = `<input type="number" value="0">`;
});
}
function updateScore(element) {
const row = element.parentNode.parentNode;
const username = row.getAttribute('data-username');
const user = users.find(user => user.username === username);
const index = Array.from(row.cells).indexOf(element.parentNode) - 2;
user.scores[index] = Number(element.value);
row.cells[1].textContent = user.scores.reduce((a, b) => a + b, 0);
saveData();
}
function resetData() {
showConfirm("确定要重置全部数据吗?", () => {
users = [];
rounds = 0;
saveData();
document.getElementById('scoreTable').getElementsByTagName('tbody')[0].innerHTML = '';
document.getElementById('scoreTable').getElementsByTagName('thead')[0].innerHTML = '<tr><th style="width:70px;">玩家</th><th style="width:60px;">合计</th><th style="width:60px;">操作</th></tr>';
});
}
function showAlert(message) {
const alertDiv = document.createElement('div');
alertDiv.className = 'alert-box';
alertDiv.innerHTML = `
<h2>温馨提示</h2>
<p>${message}</p>
<button>明白了</button>
`;
document.body.appendChild(alertDiv);
}
function showConfirm(message, onConfirm) {
const confirmDiv = document.createElement('div');
confirmDiv.className = 'alert-box';
confirmDiv.innerHTML = `
<h2>温馨提示</h2>
<p>${message}</p>
<button id="confirm-yes">确定</button>
<button>取消</button>
`;
document.body.appendChild(confirmDiv);
document.getElementById('confirm-yes').addEventListener('click', function () {
onConfirm();
confirmDiv.remove();
});
}
document.addEventListener('DOMContentLoaded', loadData);
</script>
</body>
</html>
python版本
[Python] 纯文本查看 复制代码 import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import json
import os
import sys
from PIL import Image, ImageTk
def resource_path(relative_path):
""" 获取资源文件的绝对路径 """
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
class ScoreKeeper:
def __init__(self, root):
self.root = root
self.root.title("计分器")
self.root.geometry("800x400")
# 更换程序图标
icon_path = resource_path('head.ico')
print(f"Icon path: {icon_path}") # 打印图标路径
try:
self.root.iconbitmap(icon_path) # 设置窗口图标
except Exception as e:
print(f"Error setting icon: {e}")
# 使用PIL加载图标并设置
try:
icon = Image.open(icon_path)
icon = ImageTk.PhotoImage(icon)
self.root.iconphoto(False, icon)
except FileNotFoundError:
print("Icon file not found. Please ensure 'head.ico' is in the correct directory.")
self.users = []
self.rounds = 0
self.load_data()
self.controls_frame = tk.Frame(root, padx=5, pady=5)
self.controls_frame.pack(fill=tk.X)
self.username_entry = tk.Entry(self.controls_frame, font=("仿宋", 14))
self.username_entry.grid(row=0, column=0, padx=5, pady=5)
self.username_entry.config(width=10)
self.add_user_btn = tk.Button(self.controls_frame, text="新玩家", command=self.add_user, font=("仿宋", 12))
self.add_user_btn.grid(row=0, column=1, padx=5, pady=5)
self.add_round_btn = tk.Button(self.controls_frame, text="添加一局", command=self.add_round, font=("仿宋", 12))
self.add_round_btn.grid(row=0, column=2, padx=5, pady=5)
self.reset_btn = tk.Button(self.controls_frame, text="重置", command=self.reset_data, font=("仿宋", 12))
self.reset_btn.grid(row=0, column=3, padx=5, pady=5)
self.table_frame = tk.Frame(root, padx=5, pady=5)
self.table_frame.pack(fill=tk.BOTH, expand=True)
self.scrollbar_x = ttk.Scrollbar(self.table_frame, orient="horizontal")
self.scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)
self.scrollbar_y = ttk.Scrollbar(self.table_frame, orient="vertical")
self.scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)
self.table = ttk.Treeview(self.table_frame, columns=[], show="headings", selectmode="browse",
xscrollcommand=self.scrollbar_x.set, yscrollcommand=self.scrollbar_y.set)
self.scrollbar_x.config(command=self.table.xview)
self.scrollbar_y.config(command=self.table.yview)
self.table.pack(fill=tk.BOTH, expand=True)
self.table.bind("<Button-1>", self.handle_click)
self.render_table()
def save_data(self):
data = {"users": self.users, "rounds": self.rounds}
with open("data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=4)
def load_data(self):
try:
with open("data.json", "r", encoding="utf-8") as f:
data = json.load(f)
self.users = data.get("users", [])
self.rounds = data.get("rounds", 0)
except FileNotFoundError:
self.users = []
self.rounds = 0
def add_user(self):
username = self.username_entry.get()
if not username:
messagebox.showinfo("温馨提示", "请先输入玩家昵称")
return
if username and not any(user['username'] == username for user in self.users):
user = {"username": username, "scores": [0] * self.rounds}
self.users.append(user)
self.render_table()
self.save_data()
self.username_entry.delete(0, tk.END)
def add_round(self):
self.rounds += 1
for user in self.users:
user['scores'].append(0)
self.render_table()
self.save_data()
def update_score(self, user_index, round_index, score):
self.users[user_index]['scores'][round_index] = score
self.render_table()
self.save_data()
def delete_user(self, user_index):
confirm = messagebox.askyesno("温馨提示", "确定要移除此玩家吗?")
if confirm:
del self.users[user_index]
self.render_table()
self.save_data()
def reset_data(self):
confirm = messagebox.askyesno("温馨提示", "确定要重置全部数据吗?")
if confirm:
self.users = []
self.rounds = 0
self.save_data()
self.render_table()
def render_table(self):
for i in self.table.get_children():
self.table.delete(i)
columns = ["username", "total"] + [f"round_{i+1}" for i in range(self.rounds)][::-1] + ["actions"]
self.table["columns"] = columns
self.table.heading("username", text="玩家")
self.table.heading("total", text="合计")
for i in range(self.rounds):
self.table.heading(f"round_{i+1}", text=f"第{i+1}局")
self.table.heading("actions", text="操作")
self.table.column("username", width=80, anchor=tk.CENTER, minwidth=80)
self.table.column("total", width=80, anchor=tk.CENTER, minwidth=80)
for i in range(self.rounds):
self.table.column(f"round_{i+1}", width=80, anchor=tk.CENTER, minwidth=80)
self.table.column("actions", width=80, anchor=tk.CENTER, minwidth=80)
for user_index, user in enumerate(self.users):
total_score = sum(user['scores'])
values = [user['username'], total_score] + user['scores'][::-1] + ["移除"]
tag = 'evenrow' if user_index % 2 == 0 else 'oddrow'
self.table.insert("", "end", values=values, tags=(tag,))
# 添加样式使内容居中对齐
style = ttk.Style()
style.configure("Treeview.Heading", anchor="center")
style.configure("Treeview", rowheight=25)
style.configure("Treeview", highlightthickness=1, bd=1, relief="solid")
# 添加表格边框线
style.map("Treeview", background=[("selected", "#0099FF")], foreground=[("selected", "white")])
style.configure("Treeview", highlightthickness=1, bd=1, relief="solid")
style.layout("Treeview", [('Treeview.treearea', {'sticky': 'nswe'})])
# 添加列之间的边框线
style.configure("Treeview", bordercolor="black", borderwidth=1, relief="solid")
# 添加行之间的背景颜色交替
self.table.tag_configure('oddrow', background='white')
self.table.tag_configure('evenrow', background='lightgrey')
# 确保滚动条在添加新列后仍然有效
self.table.update_idletasks()
def handle_click(self, event):
region = self.table.identify_region(event.x, event.y)
if region == "cell":
row_id = self.table.identify_row(event.y)
column = self.table.identify_column(event.x)
col_num = int(column.replace("#", "")) - 1
if col_num == len(self.users[0]["scores"]) + 2: # 操作列
user_index = self.table.index(row_id)
self.delete_user(user_index)
elif 2 <= col_num <= len(self.users[0]["scores"]) + 1: # 分数列
user_index = self.table.index(row_id)
round_index = len(self.users[0]["scores"]) - (col_num - 2) - 1 # 修正索引计算
new_score_str = simpledialog.askstring("更新分数", f"请输入 {self.users[user_index]['username']} 的第 {round_index + 1} 局分数:")
if new_score_str is not None:
try:
new_score = int(new_score_str)
self.update_score(user_index, round_index, new_score)
except ValueError:
messagebox.showerror("输入错误", "请输入有效的整数分数")
if __name__ == "__main__":
root = tk.Tk()
app = ScoreKeeper(root)
root.mainloop()
|
-
python版本
-
计分器
-
-
score.zip
2.6 KB, 下载次数: 17, 下载积分: 吾爱币 -1 CB
免费评分
-
查看全部评分
|