如何删除用户菜单中重复的T_CODE

本文介绍如何通过SM30配置SSM_CUST以实现菜单项的精简及去除重复事务代码等功能。只需简单几步即可完成设置。

1、sm30
2、选择 “表/视图”: “SSM_CUST”,点击“维护”
3、点击 “新条目”,添加“CONDENSE_MENU :YES ”
“ DELETE_DOUBLE_TCODES:YES ”
“ SORT_USER_MENU:NO”
4、保存即可生效

一般只需要 CONDENSE_MENU :YES 即可

编译无问题,但存在段错误,检测并修改错误函数,将修改后的完整函数写出来: #include "lvgl/lvgl.h" #include "lvgl/demos/lv_demos.h" #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "game.h" // 定义颜色常量 #define PRIMARY_COLOR lv_color_hex(0x1a1a2e) #define SECONDARY_COLOR lv_color_hex(0x16213e) #define ACCENT_COLOR lv_color_hex(0x0f3460) #define HIGHLIGHT_COLOR lv_color_hex(0xe94560) #define TEXT_COLOR lv_color_hex(0xffffff) // 用户结构体 typedef struct { char username[20]; char password[20]; int high_score; } User; // 游戏结构体 typedef struct { int x[100]; int y[100]; int length; int direction; int food_x; int food_y; int score; int speed; int game_over; } SnakeGame; // 全局变量 static lv_obj_t *login_scr; static lv_obj_t *register_scr; static lv_obj_t *main_menu_scr; static lv_obj_t *game_scr; static lv_obj_t *scoreboard_scr; static SnakeGame game; static User current_user; static User users[10]; static int user_count = 0; static lv_timer_t *game_timer; static void game_timer_cb(lv_timer_t *timer); static lv_obj_t *game_container = NULL; static lv_obj_t *overlay = NULL; static lv_obj_t *score_label_game = NULL; // 函数原型声明 void save_users(); void load_users(); int find_user(const char *username); void register_user(const char *username, const char *password); int login_user(const char *username, const char *password); void update_user_score(int score); void init_game(); void generate_food(); void move_snake(); void check_collision(); void create_login_screen(); void create_register_screen(); void create_main_menu(); void create_game_screen(); void create_scoreboard_screen(); void switch_screen(lv_obj_t *new_screen); // 用户管理函数 void save_users() { FILE *file = fopen("users.dat", "wb"); if (file) { fwrite(&user_count, sizeof(int), 1, file); fwrite(users, sizeof(User), user_count, file); fclose(file); } } void load_users() { FILE *file = fopen("users.dat", "rb"); if (file) { size_t read_count = fread(&user_count, sizeof(int), 1, file); if (read_count == 1 && user_count > 0 && user_count <= 10) { fread(users, sizeof(User), user_count, file); } else { user_count = 0; } fclose(file); } else { user_count = 0; // 初始化用户数量 } } int find_user(const char *username) { for (int i = 0; i < user_count; i++) { if (strcmp(users[i].username, username) == 0) { return i; } } return -1; } void register_user(const char *username, const char *password) { if (user_count >= 10) return; if (find_user(username) != -1) return; strcpy(users[user_count].username, username); strcpy(users[user_count].password, password); users[user_count].high_score = 0; user_count++; save_users(); } int login_user(const char *username, const char *password) { int idx = find_user(username); if (idx == -1) return 0; if (strcmp(users[idx].password, password) != 0) return 0; current_user = users[idx]; return 1; } void update_user_score(int score) { if (score > current_user.high_score) { current_user.high_score = score; } int idx = find_user(current_user.username); if (idx != -1) { users[idx] = current_user; save_users(); } } // 游戏初始化 void init_game() { srand(time(NULL)); game.length = 3; game.direction = 2; // 初始向右移动 game.score = 0; game.speed = 150; game.game_over = 0; // 初始化蛇身位置 - 修改这里 for (int i = 0; i < game.length; i++) { // 蛇头在中间,蛇身向右延伸 game.x[i] = 10 + i; // 初始位置 (10,10), (11,10), (12,10) game.y[i] = 10; } // 生成食物 generate_food(); } void generate_food() { int valid = 0; // 修复:声明valid变量 int attempts = 0; while (!valid && attempts < 100) { game.food_x = rand() % 20; game.food_y = rand() % 20; valid = 1; for (int i = 0; i < game.length; i++) { if (game.x[i] == game.food_x && game.y[i] == game.food_y) { valid = 0; break; } } attempts++; } if (!valid) { // 设置安全位置作为后备 game.food_x = 10; // 中间位置 game.food_y = 10; // 确保这个位置没有蛇身 for (int i = 0; i < game.length; i++) { if (game.x[i] == 10 && game.y[i] == 10) { game.food_x = 11; // 如果中间有蛇,使用旁边位置 game.food_y = 10; break; } } } } void move_snake() { if (game.game_over) return; // 保存蛇尾位置(用于绘制) int prev_x = game.x[game.length-1]; int prev_y = game.y[game.length-1]; // 移动蛇身 for (int i = game.length-1; i > 0; i--) { game.x[i] = game.x[i-1]; game.y[i] = game.y[i-1]; } // 移动蛇头 switch (game.direction) { case 0: game.y[0]--; break; // 上 case 1: game.y[0]++; break; // 下 case 2: game.x[0]++; break; // 右 case 3: game.x[0]--; break; // 左 } // 检查是否吃到食物 if (game.x[0] == game.food_x && game.y[0] == game.food_y) { // 只在吃到食物时才增加长度 if (game.length < 100) { // 检查长度限制 game.length++; // 增加蛇身 game.x[game.length-1] = prev_x; game.y[game.length-1] = prev_y; } else { // 处理达到最大长度的情况 game.game_over = 1; } // 生成新食物 generate_food(); // 增加速度 if (game.speed > 50) { game.speed -= 5; lv_timer_set_period(game_timer, game.speed); } } // 检查碰撞 check_collision(); } void check_collision() { // 检查墙壁碰撞 if (game.x[0] < 0 || game.x[0] >= 20 || game.y[0] < 0 || game.y[0] >= 20) { game.game_over = 1; return; } // 检查自身碰撞 for (int i = 1; i < game.length; i++) { if (game.x[0] == game.x[i] && game.y[0] == game.y[i]) { game.game_over = 1; return; } } } // 修改后的 switch_screen 函数 void switch_screen(lv_obj_t *new_screen) { lv_disp_t *disp = lv_disp_get_default(); lv_disp_load_scr(new_screen); } // 定时器回调辅助函数 static void timer_callback(lv_timer_t *t) { lv_obj_del(t->user_data); lv_timer_del(t); } // 登录回调函数 static void login_btn_cb(lv_event_t *e) { lv_obj_t *username_ta = lv_obj_get_child(login_scr, 1); lv_obj_t *password_ta = lv_obj_get_child(login_scr, 3); const char *username = lv_textarea_get_text(username_ta); const char *password = lv_textarea_get_text(password_ta); if (login_user(username, password)) { switch_screen(main_menu_scr); } else { lv_obj_t *error_label = lv_label_create(login_scr); lv_label_set_text(error_label, "用户名或密码错误"); lv_obj_set_style_text_color(error_label, lv_color_hex(0xff0000), 0); lv_obj_align(error_label, LV_ALIGN_BOTTOM_MID, 0, -20); lv_timer_t *timer = lv_timer_create(timer_callback, 2000, error_label); } } // 注册回调函数 static void register_btn_cb(lv_event_t *e) { lv_obj_t *username_ta = lv_obj_get_child(register_scr, 1); lv_obj_t *password_ta = lv_obj_get_child(register_scr, 3); lv_obj_t *confirm_ta = lv_obj_get_child(register_scr, 5); const char *username = lv_textarea_get_text(username_ta); const char *password = lv_textarea_get_text(password_ta); const char *confirm = lv_textarea_get_text(confirm_ta); if (strlen(username) < 3) { lv_obj_t *error_label = lv_label_create(register_scr); lv_label_set_text(error_label, "用户名至少3个字符"); lv_obj_set_style_text_color(error_label, lv_color_hex(0xff0000), 0); lv_obj_align(error_label, LV_ALIGN_BOTTOM_MID, 0, -20); lv_timer_t *timer = lv_timer_create(timer_callback, 2000, error_label); return; } if (strcmp(password, confirm) != 0) { lv_obj_t *error_label = lv_label_create(register_scr); lv_label_set_text(error_label, "两次输入的密码不一致"); lv_obj_set_style_text_color(error_label, lv_color_hex(0xff0000), 0); lv_obj_align(error_label, LV_ALIGN_BOTTOM_MID, 0, -20); lv_timer_t *timer = lv_timer_create(timer_callback, 2000, error_label); return; } register_user(username, password); switch_screen(login_scr); } // 菜单按钮回调 static void menu_btn_cb(lv_event_t *e) { if (e->code == LV_EVENT_CLICKED) { switch_screen(main_menu_scr); } } // 注册按钮回调 static void register_btn_handler(lv_event_t *e) { if (e->code == LV_EVENT_CLICKED) { switch_screen(register_scr); } } // 返回登录回调 static void back_to_login_cb(lv_event_t *e) { if (e->code == LV_EVENT_CLICKED) { switch_screen(login_scr); } } // 开始游戏回调 static void play_game_cb(lv_event_t *e) { // 清除之前的定时器 if (game_timer) { lv_timer_del(game_timer); game_timer = NULL; } // 清除之前的覆盖层 if (overlay) { lv_obj_del(overlay); overlay = NULL; } init_game(); switch_screen(game_scr); if (score_label_game) { lv_label_set_text(score_label_game, "分数: 0"); } game_timer = lv_timer_create(game_timer_cb, game.speed, NULL); } // 排行榜回调 static void show_scoreboard_cb(lv_event_t *e) { if (e->code == LV_EVENT_CLICKED) { switch_screen(scoreboard_scr); } } // 退出登录回调 static void logout_cb(lv_event_t *e) { if (e->code == LV_EVENT_CLICKED) { switch_screen(login_scr); } } // 返回主菜单回调 static void back_to_menu_cb(lv_event_t *e) { if (e->code == LV_EVENT_CLICKED) { switch_screen(main_menu_scr); } } // 游戏控制回调 static void game_timer_cb(lv_timer_t *timer) { // 检查容器是否有效 - 使用全局变量 if (!game_container) { return; } move_snake(); // 更新UI - 使用全局分数标签 if (score_label_game) { lv_label_set_text_fmt(score_label_game, "分数: %d", game.score); } // 清除之前的绘制 lv_obj_clean(game_container); // 绘制食物 (添加有效性检查) if (game.food_x >= 0 && game.food_y >= 0) { // 修复:移除重复的变量声明 lv_obj_t *food = lv_obj_create(game_container); lv_obj_set_size(food, 15, 15); // 每个格子15x15像素 lv_obj_set_pos(food, game.food_x * 15, game.food_y * 15); lv_obj_set_style_bg_color(food, HIGHLIGHT_COLOR, 0); lv_obj_set_style_radius(food, LV_RADIUS_CIRCLE, 0); lv_obj_set_style_border_width(food, 0, 0); } // 绘制蛇身 for (int i = 0; i < game.length; i++) { lv_obj_t *snake_part = lv_obj_create(game_container); lv_obj_set_size(snake_part, 15, 15); lv_obj_set_pos(snake_part, game.x[i] * 15, game.y[i] * 15); if (i == 0) { // 蛇头 lv_obj_set_style_bg_color(snake_part, HIGHLIGHT_COLOR, 0); } else { // 蛇身 lv_obj_set_style_bg_color(snake_part, lv_color_hex(0x00ff00), 0); } lv_obj_set_style_border_width(snake_part, 0, 0); } lv_obj_invalidate(game_scr); if (game.game_over) { lv_timer_del(game_timer); // 显示游戏结束画面 overlay = lv_obj_create(game_scr); lv_obj_set_size(overlay, lv_pct(100), lv_pct(100)); lv_obj_set_style_bg_color(overlay, lv_color_hex(0x000000), 0); lv_obj_set_style_bg_opa(overlay, LV_OPA_50, 0); lv_obj_set_style_radius(overlay, 0, 0); lv_obj_t *game_over_label = lv_label_create(overlay); lv_label_set_text(game_over_label, "游戏结束!"); lv_obj_set_style_text_font(game_over_label, &lv_font_montserrat_28, 0); lv_obj_set_style_text_color(game_over_label, HIGHLIGHT_COLOR, 0); lv_obj_align(game_over_label, LV_ALIGN_CENTER, 0, -40); // 修复:使用正确的变量名 final_score_label lv_obj_t *final_score_label = lv_label_create(overlay); lv_label_set_text_fmt(final_score_label, "最终分数: %d", game.score); lv_obj_set_style_text_font(final_score_label, &lv_font_montserrat_24, 0); lv_obj_set_style_text_color(final_score_label, TEXT_COLOR, 0); lv_obj_align(final_score_label, LV_ALIGN_CENTER, 0, 0); update_user_score(game.score); lv_obj_t *menu_btn = lv_btn_create(overlay); lv_obj_set_size(menu_btn, 150, 50); lv_obj_align(menu_btn, LV_ALIGN_CENTER, 0, 60); lv_obj_set_style_bg_color(menu_btn, HIGHLIGHT_COLOR, 0); lv_obj_t *btn_label = lv_label_create(menu_btn); lv_label_set_text(btn_label, "返回主菜单"); lv_obj_center(btn_label); lv_obj_add_event_cb(menu_btn, menu_btn_cb, LV_EVENT_CLICKED, NULL); } } // 键盘输入回调 static void game_input_cb(lv_event_t *e) { lv_event_code_t code = lv_event_get_code(e); if (code == LV_EVENT_KEY) { uint32_t key = lv_event_get_key(e); // 防止180度转向 if (key == LV_KEY_UP && game.direction != 1) game.direction = 0; else if (key == LV_KEY_DOWN && game.direction != 0) game.direction = 1; else if (key == LV_KEY_RIGHT && game.direction != 3) game.direction = 2; else if (key == LV_KEY_LEFT && game.direction != 2) game.direction = 3; } } // 创建登录界面 void create_login_screen() { login_scr = lv_obj_create(NULL); lv_obj_set_style_bg_color(login_scr, PRIMARY_COLOR, 0); lv_obj_set_style_pad_all(login_scr, 20, 0); // 标题 lv_obj_t *title = lv_label_create(login_scr); lv_label_set_text(title, "贪吃蛇游戏"); lv_obj_set_style_text_font(title, &lv_font_montserrat_36, 0); lv_obj_set_style_text_color(title, HIGHLIGHT_COLOR, 0); lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 30); // 用户名标签 lv_obj_t *user_label = lv_label_create(login_scr); lv_label_set_text(user_label, "用户名:"); lv_obj_set_style_text_color(user_label, TEXT_COLOR, 0); lv_obj_align(user_label, LV_ALIGN_TOP_MID, -80, 100); // 用户名输入框 lv_obj_t *user_ta = lv_textarea_create(login_scr); lv_obj_set_size(user_ta, 200, 40); lv_obj_align(user_ta, LV_ALIGN_TOP_MID, 40, 100); lv_textarea_set_placeholder_text(user_ta, "输入用户名"); lv_obj_set_style_bg_color(user_ta, SECONDARY_COLOR, 0); // 密码标签 lv_obj_t *pass_label = lv_label_create(login_scr); lv_label_set_text(pass_label, "密码:"); lv_obj_set_style_text_color(pass_label, TEXT_COLOR, 0); lv_obj_align(pass_label, LV_ALIGN_TOP_MID, -80, 160); // 密码输入框 lv_obj_t *pass_ta = lv_textarea_create(login_scr); lv_obj_set_size(pass_ta, 200, 40); lv_obj_align(pass_ta, LV_ALIGN_TOP_MID, 40, 160); lv_textarea_set_placeholder_text(pass_ta, "输入密码"); lv_textarea_set_password_mode(pass_ta, true); lv_obj_set_style_bg_color(pass_ta, SECONDARY_COLOR, 0); // 登录按钮 lv_obj_t *login_btn = lv_btn_create(login_scr); lv_obj_set_size(login_btn, 180, 50); lv_obj_align(login_btn, LV_ALIGN_TOP_MID, 0, 230); lv_obj_set_style_bg_color(login_btn, HIGHLIGHT_COLOR, 0); lv_obj_t *login_label = lv_label_create(login_btn); lv_label_set_text(login_label, "登录"); lv_obj_center(login_label); lv_obj_add_event_cb(login_btn, login_btn_cb, LV_EVENT_CLICKED, NULL); // 注册按钮 lv_obj_t *register_btn = lv_btn_create(login_scr); lv_obj_set_size(register_btn, 180, 40); lv_obj_align(register_btn, LV_ALIGN_TOP_MID, 0, 290); lv_obj_set_style_bg_color(register_btn, ACCENT_COLOR, 0); lv_obj_t *register_label = lv_label_create(register_btn); lv_label_set_text(register_label, "没有账号? 注册"); lv_obj_center(register_label); lv_obj_add_event_cb(register_btn, register_btn_handler, LV_EVENT_CLICKED, NULL); } // 创建注册界面 void create_register_screen() { register_scr = lv_obj_create(NULL); lv_obj_set_style_bg_color(register_scr, PRIMARY_COLOR, 0); lv_obj_set_style_pad_all(register_scr, 20, 0); // 标题 lv_obj_t *title = lv_label_create(register_scr); lv_label_set_text(title, "注册新账号"); lv_obj_set_style_text_font(title, &lv_font_montserrat_28, 0); lv_obj_set_style_text_color(title, HIGHLIGHT_COLOR, 0); lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 30); // 用户名标签 lv_obj_t *user_label = lv_label_create(register_scr); lv_label_set_text(user_label, "用户名:"); lv_obj_set_style_text_color(user_label, TEXT_COLOR, 0); lv_obj_align(user_label, LV_ALIGN_TOP_MID, -80, 100); // 用户名输入框 lv_obj_t *user_ta = lv_textarea_create(register_scr); lv_obj_set_size(user_ta, 200, 40); lv_obj_align(user_ta, LV_ALIGN_TOP_MID, 40, 100); lv_textarea_set_placeholder_text(user_ta, "输入用户名"); lv_obj_set_style_bg_color(user_ta, SECONDARY_COLOR, 0); // 密码标签 lv_obj_t *pass_label = lv_label_create(register_scr); lv_label_set_text(pass_label, "密码:"); lv_obj_set_style_text_color(pass_label, TEXT_COLOR, 0); lv_obj_align(pass_label, LV_ALIGN_TOP_MID, -80, 160); // 密码输入框 lv_obj_t *pass_ta = lv_textarea_create(register_scr); lv_obj_set_size(pass_ta, 200, 40); lv_obj_align(pass_ta, LV_ALIGN_TOP_MID, 40, 160); lv_textarea_set_placeholder_text(pass_ta, "输入密码"); lv_textarea_set_password_mode(pass_ta, true); lv_obj_set_style_bg_color(pass_ta, SECONDARY_COLOR, 0); // 确认密码标签 lv_obj_t *confirm_label = lv_label_create(register_scr); lv_label_set_text(confirm_label, "确认密码:"); lv_obj_set_style_text_color(confirm_label, TEXT_COLOR, 0); lv_obj_align(confirm_label, LV_ALIGN_TOP_MID, -80, 220); // 确认密码输入框 lv_obj_t *confirm_ta = lv_textarea_create(register_scr); lv_obj_set_size(confirm_ta, 200, 40); lv_obj_align(confirm_ta, LV_ALIGN_TOP_MID, 40, 220); lv_textarea_set_placeholder_text(confirm_ta, "再次输入密码"); lv_textarea_set_password_mode(confirm_ta, true); lv_obj_set_style_bg_color(confirm_ta, SECONDARY_COLOR, 0); // 注册按钮 lv_obj_t *register_btn = lv_btn_create(register_scr); lv_obj_set_size(register_btn, 180, 50); lv_obj_align(register_btn, LV_ALIGN_TOP_MID, 0, 290); lv_obj_set_style_bg_color(register_btn, HIGHLIGHT_COLOR, 0); lv_obj_t *register_label = lv_label_create(register_btn); lv_label_set_text(register_label, "注册"); lv_obj_center(register_label); lv_obj_add_event_cb(register_btn, register_btn_cb, LV_EVENT_CLICKED, NULL); // 返回登录按钮 lv_obj_t *back_btn = lv_btn_create(register_scr); lv_obj_set_size(back_btn, 180, 40); lv_obj_align(back_btn, LV_ALIGN_TOP_MID, 0, 350); lv_obj_set_style_bg_color(back_btn, ACCENT_COLOR, 0); lv_obj_t *back_label = lv_label_create(back_btn); lv_label_set_text(back_label, "返回登录"); lv_obj_center(back_label); lv_obj_add_event_cb(back_btn, back_to_login_cb, LV_EVENT_CLICKED, NULL); } // 创建主菜单 void create_main_menu() { main_menu_scr = lv_obj_create(NULL); lv_obj_set_style_bg_color(main_menu_scr, PRIMARY_COLOR, 0); // 欢迎标题 lv_obj_t *welcome_label = lv_label_create(main_menu_scr); lv_label_set_text_fmt(welcome_label, "欢迎, %s!", current_user.username); lv_obj_set_style_text_font(welcome_label, &lv_font_montserrat_24, 0); lv_obj_set_style_text_color(welcome_label, TEXT_COLOR, 0); lv_obj_align(welcome_label, LV_ALIGN_TOP_MID, 0, 30); // 最高分 lv_obj_t *score_label = lv_label_create(main_menu_scr); lv_label_set_text_fmt(score_label, "最高分: %d", current_user.high_score); lv_obj_set_style_text_color(score_label, HIGHLIGHT_COLOR, 0); lv_obj_align(score_label, LV_ALIGN_TOP_MID, 0, 70); // 开始游戏按钮 lv_obj_t *play_btn = lv_btn_create(main_menu_scr); lv_obj_set_size(play_btn, 220, 60); lv_obj_align(play_btn, LV_ALIGN_CENTER, 0, -50); lv_obj_set_style_bg_color(play_btn, HIGHLIGHT_COLOR, 0); lv_obj_t *play_label = lv_label_create(play_btn); lv_label_set_text(play_label, "开始游戏"); lv_obj_center(play_label); lv_obj_set_style_text_font(play_label, &lv_font_montserrat_24, 0); lv_obj_add_event_cb(play_btn, play_game_cb, LV_EVENT_CLICKED, NULL); // 排行榜按钮 lv_obj_t *scoreboard_btn = lv_btn_create(main_menu_scr); lv_obj_set_size(scoreboard_btn, 220, 50); lv_obj_align(scoreboard_btn, LV_ALIGN_CENTER, 0, 30); lv_obj_set_style_bg_color(scoreboard_btn, ACCENT_COLOR, 0); lv_obj_t *scoreboard_label = lv_label_create(scoreboard_btn); lv_label_set_text(scoreboard_label, "排行榜"); lv_obj_center(scoreboard_label); lv_obj_add_event_cb(scoreboard_btn, show_scoreboard_cb, LV_EVENT_CLICKED, NULL); // 退出按钮 lv_obj_t *exit_btn = lv_btn_create(main_menu_scr); lv_obj_set_size(exit_btn, 220, 50); lv_obj_align(exit_btn, LV_ALIGN_CENTER, 0, 100); lv_obj_set_style_bg_color(exit_btn, ACCENT_COLOR, 0); lv_obj_t *exit_label = lv_label_create(exit_btn); lv_label_set_text(exit_label, "退出登录"); lv_obj_center(exit_label); lv_obj_add_event_cb(exit_btn, logout_cb, LV_EVENT_CLICKED, NULL); } // 创建游戏界面 void create_game_screen() { game_scr = lv_obj_create(NULL); lv_obj_set_style_bg_color(game_scr, PRIMARY_COLOR, 0); // 分数显示 score_label_game = lv_label_create(game_scr); // 使用全局变量 lv_label_set_text(score_label_game, "分数: 0"); // 修复:全部使用 score_label_game lv_obj_set_style_text_font(score_label_game, &lv_font_montserrat_20, 0); lv_obj_set_style_text_color(score_label_game, TEXT_COLOR, 0); lv_obj_align(score_label_game, LV_ALIGN_TOP_LEFT, 10, 10); // 游戏区域容器 game_container = lv_obj_create(game_scr); // 赋值给全局变量 lv_obj_set_size(game_container, 300, 300); lv_obj_align(game_container, LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_bg_color(game_container, PRIMARY_COLOR, 0); lv_obj_set_style_border_width(game_container, 0, 0); // 键盘输入支持 lv_obj_add_flag(game_container, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_flag(game_container, LV_OBJ_FLAG_SCROLLABLE); lv_obj_add_event_cb(game_container, game_input_cb, LV_EVENT_KEY, NULL); lv_group_t *group = lv_group_create(); lv_group_add_obj(group, game_container); lv_group_focus_obj(game_container); } // 创建排行榜界面 void create_scoreboard_screen() { scoreboard_scr = lv_obj_create(NULL); lv_obj_set_style_bg_color(scoreboard_scr, PRIMARY_COLOR, 0); // 标题 lv_obj_t *title = lv_label_create(scoreboard_scr); lv_label_set_text(title, "玩家排行榜"); lv_obj_set_style_text_font(title, &lv_font_montserrat_28, 0); lv_obj_set_style_text_color(title, HIGHLIGHT_COLOR, 0); lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 20); // 排行榜容器 lv_obj_t *container = lv_obj_create(scoreboard_scr); lv_obj_set_size(container, 300, 350); lv_obj_align(container, LV_ALIGN_CENTER, 0, 20); lv_obj_set_style_bg_color(container, SECONDARY_COLOR, 0); lv_obj_set_style_border_width(container, 0, 0); lv_obj_set_flex_flow(container, LV_FLEX_FLOW_COLUMN); lv_obj_set_flex_align(container, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); // 表头 lv_obj_t *header = lv_obj_create(container); lv_obj_set_size(header, lv_pct(100), 40); lv_obj_set_style_bg_color(header, ACCENT_COLOR, 0); lv_obj_set_style_border_width(header, 0, 0); lv_obj_set_flex_flow(header, LV_FLEX_FLOW_ROW); lv_obj_t *rank_label = lv_label_create(header); lv_label_set_text(rank_label, "排名"); lv_obj_set_style_text_font(rank_label, &lv_font_montserrat_18, 0); lv_obj_set_width(rank_label, 60); lv_obj_set_style_pad_left(rank_label, 10, 0); lv_obj_t *name_label = lv_label_create(header); lv_label_set_text(name_label, "玩家"); lv_obj_set_style_text_font(name_label, &lv_font_montserrat_18, 0); lv_obj_set_width(name_label, 150); lv_obj_t *score_label = lv_label_create(header); lv_label_set_text(score_label, "最高分"); lv_obj_set_style_text_font(score_label, &lv_font_montserrat_18, 0); lv_obj_set_width(score_label, 80); // 添加玩家分数 for (int i = 0; i < user_count && i < 5; i++) { lv_obj_t *row = lv_obj_create(container); lv_obj_set_size(row, lv_pct(100), 50); lv_obj_set_style_border_width(row, 0, 0); lv_obj_set_flex_flow(row, LV_FLEX_FLOW_ROW); lv_obj_t *rank = lv_label_create(row); lv_label_set_text_fmt(rank, "%d", i+1); lv_obj_set_style_text_font(rank, &lv_font_montserrat_18, 0); lv_obj_set_width(rank, 60); lv_obj_set_style_pad_left(rank, 10, 0); lv_obj_t *name = lv_label_create(row); lv_label_set_text(name, users[i].username); lv_obj_set_style_text_font(name, &lv_font_montserrat_18, 0); lv_obj_set_width(name, 150); lv_obj_t *score = lv_label_create(row); lv_label_set_text_fmt(score, "%d", users[i].high_score); lv_obj_set_style_text_font(score, &lv_font_montserrat_18, 0); lv_obj_set_width(score, 80); // 高亮当前用户 if (strcmp(users[i].username, current_user.username) == 0) { lv_obj_set_style_bg_color(row, lv_color_hex(0x4a5568), 0); } } // 返回按钮 lv_obj_t *back_btn = lv_btn_create(scoreboard_scr); lv_obj_set_size(back_btn, 150, 50); lv_obj_align(back_btn, LV_ALIGN_BOTTOM_MID, 0, -20); lv_obj_set_style_bg_color(back_btn, HIGHLIGHT_COLOR, 0); lv_obj_t *back_label = lv_label_create(back_btn); lv_label_set_text(back_label, "返回"); lv_obj_center(back_label); lv_obj_add_event_cb(back_btn, back_to_menu_cb, LV_EVENT_CLICKED, NULL); } // 主函数 int main(void) { // 初始化LVGL lv_init(); // 初始化显示驱动和输入设备 // (根据GEC6818开发板具体实现) // 加载用户数据 load_users(); // 创建各个界面 create_login_screen(); create_register_screen(); create_main_menu(); create_game_screen(); create_scoreboard_screen(); // 设置初始屏幕 lv_disp_load_scr(login_scr); // 主循环 while (1) { lv_timer_handler(); usleep(5000); } return 0; }
06-18
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <errno.h> #include “include/aip_common.h” #include “include/dynamic_array.h” #include “include/search_functions.h” #define BUFFER_SIZE 512 /===================================================================================================================================/ /* Function Name: v_s_main_print_int / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Prints an integer element from void pointer / / Arguments: VDP vdp_a_elem : Void pointer to integer element / / Return: void / /===================================================================================================================================*/ static void v_s_main_print_int(VDP vdp_a_elem) { printf(“%d”, *(S4 *)vdp_a_elem); } /===================================================================================================================================/ /* Function Name: v_s_main_print_float / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Prints a float element from void pointer / / Arguments: VDP vdp_a_elem : Void pointer to float element / / Return: void / /===================================================================================================================================*/ static void v_s_main_print_float(VDP vdp_a_elem) { printf(“%.2f”, *(float *)vdp_a_elem); } /===================================================================================================================================/ /* Function Name: v_s_main_print_char / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Prints a character element from void pointer / / Arguments: VDP vdp_a_elem : Void pointer to character element / / Return: void / /===================================================================================================================================*/ static void v_s_main_print_char(VDP vdp_a_elem) { printf(“‘%c’”, *(S1 *)vdp_a_elem); } /===================================================================================================================================/ /* Function Name: v_s_main_print_array / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Prints contents of dynamic array / / Arguments: const ST_DA_ARRAY *stp_a_arr : Pointer to dynamic array structure / / void (vfp_a_print_element)(VDP) : Function pointer for element printing / / Return: void / /===================================================================================================================================/ static void v_s_main_print_array(const ST_DA_ARRAY *stp_a_arr, void (*vfp_a_print_element)(VDP)) { U4 u4_t_main_index; VDP vdp_t_main_elem; vdp_t_main_elem = NULL; printf("["); for (u4_t_main_index = U4_MIN; u4_t_main_index < stp_a_arr->u4_s_size; u4_t_main_index++) { vdp_t_main_elem = stp_a_arr->vdp_a_data + u4_t_main_index * stp_a_arr->u4_s_elem_size; vfp_a_print_element(vdp_t_main_elem); if (u4_t_main_index < stp_a_arr->u4_s_size - 1) { printf(", "); } } printf("]\n"); } /===================================================================================================================================/ /* Function Name: v_s_main_parse_int_array / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Parses integer input into dynamic array with strict validation / / Arguments: ST_DA_ARRAY stp_a_arr : Pointer to dynamic array structure / / Return: void / /===================================================================================================================================/ static void v_s_main_parse_int_array(ST_DA_ARRAY *stp_a_arr) { S1 s1p_t_main_buffer[BUFFER_SIZE]; S1P s1p_t_main_token; U1 u1_t_main_valid_line = FALSE; S1P s1p_t_main_end; S4 s4_t_main_value; U4 u4_t_main_values[BUFFER_SIZE/2]; // 临时存储有效整数 U4 u4_t_main_count = 0; do { printf("Enter integers separated by spaces: "); if (fgets(s1p_t_main_buffer, BUFFER_SIZE, stdin) == NULL) { printf(" [!] Input error. Please try again.\n"); continue; } // 移除换行符 S1P s1p_t_main_newline = strchr(s1p_t_main_buffer, '\n'); if (s1p_t_main_newline != NULL) *s1p_t_main_newline = '\0'; u1_t_main_valid_line = TRUE; u4_t_main_count = 0; s1p_t_main_token = strtok(s1p_t_main_buffer, " "); while (s1p_t_main_token != NULL) { s4_t_main_value = strtol(s1p_t_main_token, (char **)&s1p_t_main_end, 10); // 严格验证:必须是纯整数 if (*s1p_t_main_end != '\0' || s1p_t_main_end == s1p_t_main_token) { printf(" [!] Invalid input: '%s'. Only integers allowed.\n", s1p_t_main_token); u1_t_main_valid_line = FALSE; break; } // 范围验证 if (s4_t_main_value > INT_MAX || s4_t_main_value < INT_MIN) { printf(" [!] Integer out of range: '%s'\n", s1p_t_main_token); u1_t_main_valid_line = FALSE; break; } // 暂存有效值 u4_t_main_values[u4_t_main_count++] = (U4)s4_t_main_value; s1p_t_main_token = strtok(NULL, " "); } // 整行有效时添加到数组 if (u1_t_main_valid_line && u4_t_main_count > 0) { for (U4 i = 0; i < u4_t_main_count; i++) { v_g_da_push_back(stp_a_arr, &u4_t_main_values[i]); } } else if (u1_t_main_valid_line) { printf(" [!] No valid integers entered. Please try again.\n"); } else { printf(" [!] Invalid input detected. Please enter integers only.\n"); } } while (stp_a_arr->u4_s_size == 0); // 直到有有效输入 } /===================================================================================================================================/ /* Function Name: v_s_main_parse_float_array / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Parses float input into dynamic array with strict validation / / Arguments: ST_DA_ARRAY stp_a_arr : Pointer to dynamic array structure / / Return: void / /===================================================================================================================================/ static void v_s_main_parse_float_array(ST_DA_ARRAY *stp_a_arr) { S1 s1p_t_main_buffer[BUFFER_SIZE]; S1P s1p_t_main_token; U1 u1_t_main_valid_line = FALSE; S1P s1p_t_main_end; float f_t_main_value; float f_t_main_values[BUFFER_SIZE/2]; // 临时存储有效浮点数 U4 u4_t_main_count = 0; do { printf("Enter floating-point numbers separated by spaces: "); if (fgets(s1p_t_main_buffer, BUFFER_SIZE, stdin) == NULL) { printf(" [!] Input error. Please try again.\n"); continue; } // 移除换行符 S1P s1p_t_main_newline = strchr(s1p_t_main_buffer, '\n'); if (s1p_t_main_newline != NULL) *s1p_t_main_newline = '\0'; u1_t_main_valid_line = TRUE; u4_t_main_count = 0; s1p_t_main_token = strtok(s1p_t_main_buffer, " "); while (s1p_t_main_token != NULL) { f_t_main_value = strtof(s1p_t_main_token, (char **)&s1p_t_main_end); // 严格验证:必须是纯浮点数 if (*s1p_t_main_end != '\0' || s1p_t_main_end == s1p_t_main_token) { printf(" [!] Invalid input: '%s'. Only floats allowed.\n", s1p_t_main_token); u1_t_main_valid_line = FALSE; break; } // 暂存有效值 f_t_main_values[u4_t_main_count++] = f_t_main_value; s1p_t_main_token = strtok(NULL, " "); } // 整行有效时添加到数组 if (u1_t_main_valid_line && u4_t_main_count > 0) { for (U4 i = 0; i < u4_t_main_count; i++) { v_g_da_push_back(stp_a_arr, &f_t_main_values[i]); } } else if (u1_t_main_valid_line) { printf(" [!] No valid floats entered. Please try again.\n"); } else { printf(" [!] Invalid input detected. Please enter floats only.\n"); } } while (stp_a_arr->u4_s_size == 0); // 直到有有效输入 } /===================================================================================================================================/ /* Function Name: v_s_main_parse_char_array / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Parses character input into dynamic array with strict validation / / Arguments: ST_DA_ARRAY stp_a_arr : Pointer to dynamic array structure / / Return: void / /===================================================================================================================================/ static void v_s_main_parse_char_array(ST_DA_ARRAY *stp_a_arr) { S1 s1p_t_main_buffer[BUFFER_SIZE]; U4 u4_t_main_index; U1 u1_t_main_valid_input = FALSE; do { printf("Enter characters without spaces: "); if (fgets(s1p_t_main_buffer, BUFFER_SIZE, stdin) == NULL) { printf(" [!] Input error. Please try again.\n"); continue; } // 移除换行符 S1P s1p_t_main_newline = strchr(s1p_t_main_buffer, '\n'); if (s1p_t_main_newline != NULL) *s1p_t_main_newline = '\0'; u1_t_main_valid_input = FALSE; for (u4_t_main_index = 0; s1p_t_main_buffer[u4_t_main_index] != '\0'; u4_t_main_index++) { S1 s1_t_main_value = s1p_t_main_buffer[u4_t_main_index]; // 手动验证字符:允许可打印字符(ASCII 33-126),排除空格(32)和控制字符 if (s1_t_main_value >= 33 && s1_t_main_value <= 126) { v_g_da_push_back(stp_a_arr, &s1_t_main_value); u1_t_main_valid_input = TRUE; } // 空格处理:跳过不报错 else if (s1_t_main_value == 32) { // 静默跳过空格 } // 其他无效字符 else { printf(" [!] Invalid character: ASCII code %d (0x%02X)\n", s1_t_main_value, s1_t_main_value); v_g_da_free(stp_a_arr); // 清除部分输入 u1_t_main_valid_input = FALSE; break; } } if (!u1_t_main_valid_input) { printf(" [!] No valid characters entered. Please enter printable non-space characters.\n"); } } while (!u1_t_main_valid_input); } /===================================================================================================================================/ /* Function Name: u1_s_main_get_menu_choice / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: 获取用户菜单选择并验证 / / Arguments: void / / Return: U1 : 用户选择(1-4) / /===================================================================================================================================*/ static U1 u1_s_main_get_menu_choice(void) { S1 s1p_t_buffer[BUFFER_SIZE]; S4 s4_t_choice = 0; while (1) { printf("\n===== Dynamic Array Program =====\n"); printf("1. Integer Sorting and Binary Search\n"); printf("2. Float Sorting and Binary Search\n"); printf("3. Character Sorting and Binary Search\n"); printf("4. Exit Program\n"); printf("Please select an option (1-4): "); if (fgets(s1p_t_buffer, BUFFER_SIZE, stdin) == NULL) { printf(" [!] Input error. Please try again.\n"); continue; } char *newline = strchr(s1p_t_buffer, '\n'); if (newline) *newline = '\0'; char *end_ptr; errno = 0; s4_t_choice = strtol(s1p_t_buffer, &end_ptr, 10); if (end_ptr == s1p_t_buffer || *end_ptr != '\0' || errno == ERANGE) { printf(" [!] Invalid menu choice. Please enter a number 1-4.\n"); continue; } if (s4_t_choice >= 1 && s4_t_choice <= 4) { return (U1)s4_t_choice; } printf(" [!] Invalid choice. Please select 1-4.\n"); } } /===================================================================================================================================/ /* Function Name: v_s_main_init_array_context / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: 根据选择初始化数组上下文 / / Arguments: U1 u1_a_choice : 用户选择(1-3) /* ST_DA_ARRAY stp_a_arr : 动态数组指针 / void (*vfp_a_print_element)(VDP) : 元素打印函数指针 / S4 (*s4fp_a_compare)(const VDP, const VDP) : 比较函数指针 / void (**vfp_a_parse_array)(ST_DA_ARRAY ) : 数组解析函数指针 / / Return: void / /===================================================================================================================================/ static void v_s_main_init_array_context(U1 u1_a_choice, ST_DA_ARRAY *stp_a_arr, void (**vfp_a_print_element)(VDP), S4 (**s4fp_a_compare)(const VDP, const VDP), void (**vfp_a_parse_array)(ST_DA_ARRAY *)) { switch (u1_a_choice) { case 1: v_g_da_init(stp_a_arr, sizeof(S4)); *vfp_a_print_element = v_s_main_print_int; *s4fp_a_compare = s4_g_comp_int; *vfp_a_parse_array = v_s_main_parse_int_array; break; case 2: v_g_da_init(stp_a_arr, sizeof(float)); *vfp_a_print_element = v_s_main_print_float; *s4fp_a_compare = s4_g_comp_float; *vfp_a_parse_array = v_s_main_parse_float_array; break; case 3: v_g_da_init(stp_a_arr, sizeof(S1)); *vfp_a_print_element = v_s_main_print_char; *s4fp_a_compare = s4_g_comp_char; *vfp_a_parse_array = v_s_main_parse_char_array; break; default: // 不应执行到此 printf(" [!] Internal error: Invalid choice in context init\n"); break; } } /===================================================================================================================================/ /* Function Name: v_s_main_process_array / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: 处理数组的排序、打印和搜索 / / Arguments: ST_DA_ARRAY stp_a_arr : 动态数组指针 / void (vfp_a_print_element)(VDP) : 元素打印函数 / S4 (s4fp_a_compare)(const VDP, const VDP) : 比较函数 / / Return: void / /===================================================================================================================================/ static void v_s_main_process_array(ST_DA_ARRAY *stp_a_arr, void (*vfp_a_print_element)(VDP), S4 (s4fp_a_compare)(const VDP, const VDP)) { / 空数组检查 */ if (stp_a_arr->u4_s_size == 0) { printf(" [!] Array is empty. Operation skipped.\n"); return; } printf("Original array: "); v_s_main_print_array(stp_a_arr, vfp_a_print_element); printf("Sorting the array...\n"); v_g_da_bubble_sort(stp_a_arr, s4fp_a_compare); printf("Sorted array: "); v_s_main_print_array(stp_a_arr, vfp_a_print_element); } /===================================================================================================================================/ /* Function Name: u1_s_main_get_search_value / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: 获取并验证搜索值 / / Arguments: U1 u1_a_type : 数据类型(1=整数, 2=浮点, 3=字符) /* const ST_DA_ARRAY stp_a_arr : 动态数组指针(用于搜索) / S4 (s4fp_a_compare)(const VDP, const VDP) : 比较函数 / VDP vdp_a_value : 存储搜索值的指针 / / Return: U1 : 搜索是否成功 / /===================================================================================================================================*/ static U1 u1_s_main_get_search_value(U1 u1_a_type, const ST_DA_ARRAY *stp_a_arr, S4 (*s4fp_a_compare)(const VDP, const VDP), VDP vdp_a_value) { S1 s1p_t_buffer[BUFFER_SIZE]; while (1) { printf("Enter the value to search: "); if (fgets(s1p_t_buffer, BUFFER_SIZE, stdin) == NULL) { printf(" [!] Input error. Please try again.\n"); continue; } // 移除换行符 char *newline = strchr(s1p_t_buffer, '\n'); if (newline) *newline = '\0'; if (u1_a_type == 1) { // 整数 char *end_ptr = NULL; errno = 0; long target = strtol(s1p_t_buffer, &end_ptr, 10); if (end_ptr == s1p_t_buffer) { printf(" [!] No digits found. Please enter an integer.\n"); } else if (*end_ptr != '\0') { printf(" [!] Trailing characters: '%s'. Only integers allowed.\n", end_ptr); } else if (errno == ERANGE) { printf(" [!] Integer out of range for long type.\n"); } else if (target < INT_MIN || target > INT_MAX) { printf(" [!] Integer out of range [%d, %d].\n", INT_MIN, INT_MAX); } else { *(S4 *)vdp_a_value = (S4)target; return TRUE; } } else if (u1_a_type == 2) { // 浮点数 char *end_ptr = NULL; errno = 0; float target = strtof(s1p_t_buffer, &end_ptr); if (end_ptr == s1p_t_buffer) { printf(" [!] No digits found. Please enter a float.\n"); } else if (*end_ptr != '\0') { printf(" [!] Trailing characters: '%s'. Only floats allowed.\n", end_ptr); } else if (errno == ERANGE) { printf(" [!] Float out of representable range.\n"); } else { *(float *)vdp_a_value = target; return TRUE; } } else if (u1_a_type == 3) { // 字符 size_t len = strlen(s1p_t_buffer); if (len == 0) { printf(" [!] No character entered. Please try again.\n"); } else { if (len > 1) { printf(" [!] Multiple characters entered. Using first character: '%c'\n", s1p_t_buffer[0]); } *(S1 *)vdp_a_value = s1p_t_buffer[0]; return TRUE; } } } } /===================================================================================================================================/ /* Function Name: main / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: 主函数入口 / / Arguments: void / / Return: S4 : 程序退出状态 / /===================================================================================================================================*/ S4 main(void) { while (1) { U1 u1_t_choice = u1_s_main_get_menu_choice(); // 退出处理 if (u1_t_choice == 4) { printf("Exiting program.\n"); break; } // 初始化数组上下文 ST_DA_ARRAY st_t_array; void (*vfp_t_print_element)(VDP) = NULL; S4 (*s4fp_t_compare)(const VDP, const VDP) = NULL; void (*vfp_t_parse_array)(ST_DA_ARRAY *) = NULL; v_s_main_init_array_context(u1_t_choice, &st_t_array, &vfp_t_print_element, &s4fp_t_compare, &vfp_t_parse_array); // 解析用户输入数据 vfp_t_parse_array(&st_t_array); // 处理数组(排序和打印) v_s_main_process_array(&st_t_array, vfp_t_print_element, s4fp_t_compare); // 搜索处理 if (st_t_array.u4_s_size > 0) { union { S4 s4_val; float f_val; S1 s1_val; } u_t_search_value; if (u1_s_main_get_search_value(u1_t_choice, &st_t_array, s4fp_t_compare, (VDP)&u_t_search_value)) { U1 u1_t_found = u4_g_search_binary(&st_t_array, &u_t_search_value, s4fp_t_compare); printf("Value %s in the array!\n", u1_t_found ? "found" : "not found"); } } // 清理资源 v_g_da_free(&st_t_array); } return 0; } 进行编码规范: 进行编码规范: 1、标准变量类型 禁止使用C语言的标准变量类型。 请使用共通头文件“aip_common.h”中定义了标准类型,如下: #ifndef AIP_COMMON_H #define AIP_COMMON_H typedef unsigned char U1; typedef unsigned short U2; typedef unsigned int U4; typedef long unsigned int U8; typedef signed char S1; typedef signed short S2; typedef signed long S4; typedef signed long long S8; typedef U1* U1P; typedef U2* U2P; typedef U4* U4P; typedef U8* U8P; typedef S1* S1P; typedef S2* S2P; typedef S4* S4P; typedef S8* S8P; typedef void* VDP; #define U1_MAX 0xFFU #define U1_MIN 0x00U #define S1_MAX 0x7F #define S1_MIN 0x80 #define U2_MAX 0xFFFFU #define U2_MIN 0x0000U #define S2_MAX 0x7FFF #define S2_MIN 0x8000 #define U4_MAX 0xFFFFFFFFUL #define U4_MIN 0x00000000UL #define S4_MAX 0x7FFFFFFFL #define S4_MIN 0x80000000L #define U8_MAX 0xFFFFFFFFFFFFFFFFULL #define U8_MIN 0x0000000000000000ULL #define S8_MAX 0x7FFFFFFFFFFFFFFFLL #define S8_MIN 0x8000000000000000LL #define TRUE 1 #define FALSE 0 #define ST struct #define EN enum #endif /* AIP_COMMON_H */ 2、变量: Format type [dt][s][a][module][variable]; Length of Identifier 最多32个字符 [dt]变量类型 标准类型 u1, u2, u4, u8, s1, s2, s4, s8 结构体类型 st 枚举类型 en 共用体类型 MISRA-C中禁止使用 函数指针类型 fp 变量指针类型 u1p, u2p, u4p, s1p, s2p, s4p, s8p, stp 空指针类型 vdp [s]作用域 ※ 函数域内的自动变量 t 函数阈内的参数变量 a 文件阈内的static变量 s 文件域内外的extern变量 g [a]数组 ※ 维数=0 无修饰字符 维数=1 p 维数=n p[n] [module]模块名[variable]变量名 有const修饰 只能使用大写字母 无const修饰 只能使用小写字母 3、函数 Format type [dt][s]_[module]function; Length of Identifier 最多32个字节 [dt]返回值类型 标准类型 u1, u2, u4, u8, s1, s2, s4, s8 结构体类型 st 枚举类型 en 共用体类型 MISRA-C中禁止使用 变量指针类型 u1p, u2p, u4p, s1p, s2p, s4p, s8p, stp 空指针类型 vdp [s]作用域 static函数仅在文件内 s extern函数在文件内外 g [module]模块名 [function]函数名 大小写字母均可使用 [parameter]形参名 3.3. 命名规则:遵从定义变量的命名格式 ※:函数原型声明时,必须定义形参。 ※函数内不会修改的参数,必须加上“const”修饰符。 4、注释必须是英文,不要使用“//”注释,不要跨行使用注释。在每一行,分别使用“/”和“/”来注释“/”后面和“/”的前面,插入空格 每个函数前面都要加注释,形如: /===================================================================================================================================/ /* Function Name: v_g_SYMBOL_saveFile / / --------------------------------------------------------------------------------------------------------------------------------- / / Description: Saves user-defined symbol pairs to Symbol.txt file after validation / / Arguments: const U2 *u2p_g_FILE_folder_path_p : Folder path / / const U2 u2p_a_SYMBOL_user_input : User input symbols / / Return: void / /===================================================================================================================================/ 5、{每个左大括号都要另起一行 6、所有判断语句,if while等只能是判断语句,不能嵌套函数 7、每个函数最多一个出口 8、返回值是一个变量,或者直接写一个值,不要写公式 9、结构体: Format typedef struct{ [member] … }ST_[module]_[variable]; Length of Identifier 最多32个字符 [module]模块名 [variable]变量名 只能使用大写字母 [member] 成员名称需要按照3.3. 变量的规定。 禁止使用位域类型定义。 不过,Micro Controller Vendor提供的Micro-Controller的控制寄存器定义除外。 10、不要用常数,用魔法数字,如果是全是常数的公式,可以在宏里面定义
09-11
# ======================================== # ✅ 功能函数定义 # ======================================== def refresh_material_list(filter_text=""): """刷新表格数据,支持搜索过滤""" for row in tree.get_children(): tree.delete(row) try: if filter_text.strip(): like_filter = f"%{filter_text}%" query = """ SELECT material_code, name, CustomerRef, OtherRef, OtherRef2 FROM material_master WHERE material_code LIKE %s OR name LIKE %s OR CustomerRef LIKE %s OR OtherRef LIKE %s OR OtherRef2 LIKE %s """ params = (like_filter,) * 5 cursor.execute(query, params) else: cursor.execute(""" SELECT material_code, name, CustomerRef, OtherRef, OtherRef2 FROM material_master """) for row in cursor.fetchall(): values = [str(cell).strip() if cell is not None else "" for cell in row] tree.insert("", tk.END, values=values) except Exception as e: messagebox.showerror("读取失败", f"无法加载物料数据:\n{e}") def add_material(): """添加新物料""" code = code_var.get().strip() name = name_var_local.get().strip() customer_ref = customer_ref_var.get().strip() other_ref = other_ref_var.get().strip() other_ref2 = other_ref2_var.get().strip() if not code or not name: messagebox.showwarning("提示", "请输入完整的物料编号和名称") return try: cursor.execute(""" INSERT INTO material_master (material_code, name, CustomerRef, OtherRef, OtherRef2, created_at) VALUES (%s, %s, %s, %s, %s, %s) """, (code, name, customer_ref, other_ref, other_ref2, datetime.now())) conn.commit() messagebox.showinfo("成功", "✅ 物料已添加") # 清空输入框 code_var.set("") name_var_local.set("") customer_ref_var.set("") other_ref_var.set("") other_ref2_var.set("") refresh_material_list() except pyodbc.IntegrityError: messagebox.showerror("重复", "该物料编号已存在,请更换编号。") except Exception as e: conn.rollback() messagebox.showerror("错误", f"添加失败:\n{e}") def delete_material(): """删除选中物料""" selected = tree.selection() if not selected: messagebox.showwarning("提示", "请先选择要删除的物料") return item = tree.item(selected[0]) code = item['values'][0] name = item['values'][1] if messagebox.askyesno("确认删除", f"确定要删除?\n编号:{code}\n名称:{name}"): try: cursor.execute("DELETE FROM material_master WHERE material_code = %s", (code,)) conn.commit() messagebox.showinfo("成功", "🗑️ 物料已删除") refresh_material_list() except Exception as e: conn.rollback() messagebox.showerror("错误", f"删除失败:\n{e}") def on_double_click(event): """双击编辑物料""" selected = tree.selection() if not selected: return item = tree.item(selected[0]) code, name, customer_ref, other_ref, other_ref2 = item['values'] edit_window = tk.Toplevel(master_window) edit_window.title("编辑物料") edit_window.geometry("450x380") new_code_var = tk.StringVar(value=code) new_name_var = tk.StringVar(value=name) new_customer_ref_var = tk.StringVar(value=customer_ref) new_other_ref_var = tk.StringVar(value=other_ref) new_other_ref2_var = tk.StringVar(value=other_ref2) ttk.Label(edit_window, text="物料编号").grid(row=0, column=0, padx=15, pady=8, sticky='e') ttk.Entry(edit_window, textvariable=new_code_var, width=28).grid(row=0, column=1, padx=15, pady=8, sticky='w') ttk.Label(edit_window, text="物料名称").grid(row=1, column=0, padx=15, pady=8, sticky='e') ttk.Entry(edit_window, textvariable=new_name_var, width=28).grid(row=1, column=1, padx=15, pady=8, sticky='w') ttk.Label(edit_window, text="客户参考").grid(row=2, column=0, padx=15, pady=8, sticky='e') ttk.Entry(edit_window, textvariable=new_customer_ref_var, width=28).grid(row=2, column=1, padx=15, pady=8, sticky='w') ttk.Label(edit_window, text="其他参考1").grid(row=3, column=0, padx=15, pady=8, sticky='e') ttk.Entry(edit_window, textvariable=new_other_ref_var, width=28).grid(row=3, column=1, padx=15, pady=8, sticky='w') ttk.Label(edit_window, text="其他参考2").grid(row=4, column=0, padx=15, pady=8, sticky='e') ttk.Entry(edit_window, textvariable=new_other_ref2_var, width=28).grid(row=4, column=1, padx=15, pady=8, sticky='w') def save_changes(): new_code = new_code_var.get().strip() new_name = new_name_var.get().strip() new_customer_ref = new_customer_ref_var.get().strip() new_other_ref = new_other_ref_var.get().strip() new_other_ref2 = new_other_ref2_var.get().strip() if not new_code or not new_name: messagebox.showwarning("提示", "请输入完整信息") return try: cursor.execute(""" UPDATE material_master SET material_code = %s, name = %s, CustomerRef = %s, OtherRef = %s, OtherRef2 = %s WHERE material_code = %s """, (new_code, new_name, new_customer_ref, new_other_ref, new_other_ref2, code)) conn.commit() messagebox.showinfo("成功", "💾 修改已保存") edit_window.destroy() refresh_material_list() master_window.lift() except pyodbc.IntegrityError: conn.rollback() messagebox.showerror("错误", "目标编号已存在,无法修改。") except Exception as e: conn.rollback() messagebox.showerror("错误", f"更新失败:\n{e}") ttk.Button(edit_window, text="保存修改", command=save_changes).grid(row=5, column=0, columnspan=2, pady=20) def copy_selected_item(): """复制选中行内容到剪贴板""" selected = tree.selection() if not selected: return values = tree.item(selected[0])['values'] text = '\t'.join(str(v) for v in values) master_window.clipboard_clear() master_window.clipboard_append(text) def show_popup(event): """右键弹出菜单""" if tree.identify_row(event.y): tree.selection_set(tree.identify_row(event.y)) popup_menu.post(event.x_root, event.y_root) 修复以上代码,提供完整结果
最新发布
09-29
# ======================================== # 🔧 物料主数据管理窗口(防重复打开)✅ 已适配当前上下文 # ======================================== material_master_open = False def open_material_master(): if not cursor: messagebox.showwarning("警告", "数据库未连接,无法管理物料") return global material_master_open if material_master_open: messagebox.showwarning("提示", "物料管理窗口已打开。") return material_master_open = True master_window = tk.Toplevel(root) master_window.title("物料主数据管理") master_window.geometry("800x600") code_var = tk.StringVar() name_var_local = tk.StringVar() customer_ref_var = tk.StringVar() search_var = tk.StringVar() # ======================================== # ✅ 功能函数定义(必须放在使用前) # ======================================== def refresh_material_list(filter_text=""): """刷新表格数据,支持搜索过滤""" for row in tree.get_children(): tree.delete(row) try: if filter_text.strip(): like_filter = f"%{filter_text}%" query = """ SELECT material_code, name, CustomerRef ,OtherRef ,OtherRef2 FROM [material_master] WHERE material_code LIKE ? OR name LIKE ? OR CustomerRef LIKE ? """ cursor.execute(query, (like_filter, like_filter, like_filter, like_filter, like_filter)) else: cursor.execute("SELECT material_code, name, CustomerRef,OtherRef ,OtherRef2 FROM [material_master]") for row in cursor.fetchall(): tree.insert("", tk.END, values=[str(cell).strip() for cell in row]) except Exception as e: messagebox.showerror("读取失败", f"无法加载物料数据:\n{e}") def add_material(): """添加新物料""" code = code_var.get().strip() name = name_var_local.get().strip() customer_ref = customer_ref_var.get().strip() if not code or not name: messagebox.showwarning("提示", "请输入完整的物料编号和名称") return try: cursor.execute( "INSERT INTO [material_master] (material_code, name, CustomerRef,OtherRef ,OtherRef2, created_at) VALUES (?, ?, ?,?,?, ?)", (code, name, customer_ref,OtherRef ,OtherRef2, datetime.now()) ) conn.commit() messagebox.showinfo("成功", "✅ 物料已添加") code_var.set("") name_var_local.set("") customer_ref_var.set("") refresh_material_list() except pyodbc.IntegrityError: messagebox.showerror("重复", "该物料编号已存在,请更换编号。") except Exception as e: conn.rollback() messagebox.showerror("错误", f"添加失败:\n{e}") def delete_material(): """删除选中物料""" selected = tree.selection() if not selected: messagebox.showwarning("提示", "请先选择要删除的物料") return item = tree.item(selected[0]) code = item['values'][0] name = item['values'][1] if messagebox.askyesno("确认删除", f"确定要删除?\n编号:{code}\n名称:{name}"): try: cursor.execute("DELETE FROM [material_master] WHERE material_code = ?", (code,)) conn.commit() messagebox.showinfo("成功", "🗑️ 物料已删除") refresh_material_list() except Exception as e: conn.rollback() messagebox.showerror("错误", f"删除失败:\n{e}") def on_double_click(event): """双击编辑物料""" selected = tree.selection() if not selected: return item = tree.item(selected[0]) code, name, customer_ref = item['values'] edit_window = tk.Toplevel(master_window) edit_window.title("编辑物料") edit_window.geometry("400x250") new_code_var = tk.StringVar(value=code) new_name_var = tk.StringVar(value=name) new_customer_ref_var = tk.StringVar(value=customer_ref) ttk.Label(edit_window, text="物料编号").grid(row=0, column=0, padx=10, pady=5, sticky='e') ttk.Entry(edit_window, textvariable=new_code_var).grid(row=0, column=1, padx=10, pady=5, sticky='w') ttk.Label(edit_window, text="物料名称").grid(row=1, column=0, padx=10, pady=5, sticky='e') ttk.Entry(edit_window, textvariable=new_name_var).grid(row=1, column=1, padx=10, pady=5, sticky='w') ttk.Label(edit_window, text="客户参考").grid(row=2, column=0, padx=10, pady=5, sticky='e') ttk.Entry(edit_window, textvariable=new_customer_ref_var).grid(row=2, column=1, padx=10, pady=5, sticky='w') def save_changes(): new_code = new_code_var.get().strip() new_name = new_name_var.get().strip() new_customer_ref = new_customer_ref_var.get().strip() if not new_code or not new_name: messagebox.showwarning("提示", "请输入完整信息") return try: cursor.execute(""" UPDATE [material_master] SET material_code = ?, name = ?, CustomerRef = ? WHERE material_code = ? """, (new_code, new_name, new_customer_ref, code)) conn.commit() messagebox.showinfo("成功", "💾 修改已保存") edit_window.destroy() refresh_material_list() master_window.lift() except pyodbc.IntegrityError: conn.rollback() messagebox.showerror("错误", "目标编号已存在,无法修改。") except Exception as e: conn.rollback() messagebox.showerror("错误", f"更新失败:\n{e}") ttk.Button(edit_window, text="保存修改", command=save_changes).grid(row=3, column=0, columnspan=2, pady=15) def copy_selected_item(): """复制选中行内容到剪贴板""" selected = tree.selection() if selected: values = tree.item(selected[0])['values'] text = '\t'.join(str(v) for v in values) master_window.clipboard_clear() master_window.clipboard_append(text) # messagebox.showinfo("已复制", "已复制到剪贴板:" + text) def show_popup(event): """右键弹出菜单""" if tree.identify_row(event.y): tree.selection_set(tree.identify_row(event.y)) popup_menu.post(event.x_root, event.y_root) # ======================================== # ✅ 新增功能:从 Excel 导入并覆盖主数据 # 必须放在 Button 创建之前! # ======================================== def import_material_from_excel(): filepath = filedialog.askopenfilename( title="选择物料主数据Excel文件", filetypes=[("Excel 文件", "*.xlsx"), ("所有文件", "*.*")] ) if not filepath: return # 用户取消 if not messagebox.askyesno("⚠️ 确认操作", "此操作将删除当前所有主数据,\n并用Excel中的数据完全替换。\n\n是否继续?"): return try: df = pd.read_excel(filepath) required_columns = {'material_code', 'name', 'CustomerRef'} missing = required_columns - set(df.columns) if missing: messagebox.showerror("格式错误", f"❌ 缺少必要列:{missing}\n请确保包含以下列:\n{required_columns}") return # 清理数据 df['material_code'] = df['material_code'].astype(str).str.strip() df['name'] = df['name'].astype(str).str.strip() df['CustomerRef'] = df['CustomerRef'].astype(str).str.strip() # 过滤无效行 df.dropna(subset=['material_code', 'name'], inplace=True) df = df[(df['material_code'] != 'nan') & (df['name'] != 'nan')] if df.empty: messagebox.showwarning("无有效数据", "Excel 中没有可导入的有效数据行。") return # 开始事务:清空旧数据 cursor.execute("DELETE FROM [material_master]") inserted_count = 0 for _, row in df.iterrows(): cursor.execute(""" INSERT INTO [material_master] (material_code, name, CustomerRef, created_at) VALUES (?, ?, ?, ?) """, ( row['material_code'], row['name'], row['CustomerRef'], datetime.now() )) inserted_count += 1 conn.commit() messagebox.showinfo("导入成功", f"✅ 已成功导入 {inserted_count} 条物料数据!") refresh_material_list() # 刷新界面 except Exception as e: conn.rollback() messagebox.showerror("导入失败", f"发生错误:\n{str(e)}") print(f"❌ Excel导入错误:{e}") # ======================================== # UI 布局部分 # ======================================== # --- 表单输入区 --- ttk.Label(master_window, text="物料编号").grid(row=0, column=0, padx=10, pady=5, sticky='e') ttk.Entry(master_window, textvariable=code_var, width=25).grid(row=0, column=1, padx=10, pady=5, sticky='w') ttk.Label(master_window, text="物料名称").grid(row=1, column=0, padx=10, pady=5, sticky='e') ttk.Entry(master_window, textvariable=name_var_local, width=25).grid(row=1, column=1, padx=10, pady=5, sticky='w') ttk.Label(master_window, text="客户参考").grid(row=2, column=0, padx=10, pady=5, sticky='e') ttk.Entry(master_window, textvariable=customer_ref_var, width=25).grid(row=2, column=1, padx=10, pady=5, sticky='w') # --- 按钮区 --- ttk.Button(master_window, text="➕ 添加物料", command=add_material).grid( row=3, column=0, pady=10, padx=10, sticky='e') ttk.Button(master_window, text="🗑️ 删除选中物料", command=delete_material).grid( row=3, column=1, pady=10, padx=10, sticky='w') ttk.Button(master_window, text="🔄 从Excel导入并覆盖", command=import_material_from_excel).grid( row=3, column=2, padx=20, pady=10, sticky='w') # --- 搜索框 --- ttk.Label(master_window, text="🔍 搜索").grid(row=4, column=0, padx=10, pady=5, sticky='e') search_entry = ttk.Entry(master_window, textvariable=search_var, width=25) search_entry.grid(row=4, column=1, padx=10, pady=5, sticky='w') search_var.trace_add("write", lambda *args: refresh_material_list(search_var.get())) # --- 数据表格 --- tree = ttk.Treeview(master_window, columns=("编号", "名称", "客户参考"), show="headings", height=20) tree.heading("编号", text="物料编号") tree.heading("名称", text="物料名称") tree.heading("客户参考", text="客户参考") tree.column("编号", width=180) tree.column("名称", width=250) tree.column("客户参考", width=200) tree.grid(row=5, column=0, columnspan=3, padx=10, pady=10, sticky="nsew") # --- 右键菜单 --- popup_menu = Menu(master_window, tearoff=0) popup_menu.add_command(label="📋 复制", command=copy_selected_item) tree.bind("<Button-3>", show_popup) # --- 双击编辑 --- tree.bind("<Double-1>", on_double_click) # --- 初始化数据 --- refresh_material_list() # --- 窗口关闭事件 --- def on_close(): global material_master_open material_master_open = False master_window.destroy() master_window.protocol("WM_DELETE_WINDOW", on_close) # --- 布局权重设置 --- master_window.grid_rowconfigure(5, weight=1) master_window.grid_columnconfigure(1, weight=1)提供完整修改后的代码
09-25
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值