Form_Form标准控件Folder开发解析(案列)

本文详细阐述了使用特定框架进行APP开发的过程,包括对象类的生成、数据块的创建、堆叠画布的应用以及触发器的编写等核心步骤,并介绍了如何在数据项数据块中配置特定文本项和按钮字段。此外,文章还涉及了创建Stackcanvas以放置不同组件的方法,以及在数据块中实现FOLDER_SWITCHER文本项的技巧。

2014-01-09 Created By BaoXinjian

1. 打开APPSTAND.fmb, 并加载程序库APPFLDR.pll. 

2. 基于APPSTAND.fmb生成Folder开发所需的对象子类,如下: 

  • a) Window 
    • i. FOLDER_AUTOSIZE , FOLDER_SORT_DATA ,FOLDER_TOOLS 
  • b) Canvas 
    • i. FOLDER_AUTOSIZE , FOLDER_SORT_DATA ,FOLDER_TOOLS 
  • c) Datablock 
    • i. FOLDER_TOOLS 
    • ii. FOLDER_CONTROL 
  • d) Objectset 
    • i. STANDARD FOLDER 

3. 建立基于表/视图的数据块,并设置记录指示器及滚动条.并设置对应画布及窗口. 

4. 建立堆叠画布,把数据字段全部放入此画布.并调整在普通画布上的位置. 

5. 删除所有数据字段的PROMPT. 

6. 创建非数据库数据块PROMPT,并在其中建立如下对象. 

  • a) 与数据字段名称一致的显示项字段,属性类为”FOLDER_PROMPT_MULTIROW” 
  • b) ORDER_BY1,ORDER_BY2,ORDER_BY3的按钮字段,属性类为”FOLDER_ORDERBY” 
  • c) FOLDER_OPEN的按钮字段,属性类为”FOLDER_OPEN”. 
  • d) FOLDER_TITLE的文本项字段,属性类为”DYNAMIC_TITLE”. 
  • e) FOLDER_DUMMY的文本项字段,属性类为”FOLDER_DUMMY”. 

7. 触发器编写 

  • a) FORM. LEVEL 
    • i.  FOLDER_ACTION 
      • app_folder.event(:global.folder_action); 
    • ii. WHEN-NEW-FORM-INSTANCE 
      • app_folder.define_folder_block('testfolder', --form名称                                          
                                                     'xxab_folder_form', --data block名称
                                                     'prompt', --prompt block 名称
                                                     'main_stk', --stack canvas名称
                                                     'main', --window 名称
                                                     ''); --NULL
      • app_folder.event('instantiate');         
  • b) BLOCK LEVEL 
    •  i. 在数据库数据块上创建如下Triggers 
      • Pre-Query 
      • Post-Query 
      • Key-Prev-Item 
      • Key-Next-Item 
      • Key-ExeQry 
      • Key-EntQry 
      • When-New-Record-Instance 
      • Post-Block 
      • Pre-Block 
      • When-New-Block-Instance 
      • Key-Prvrec 
      • Key-Nxtrec 
      • Key-Clrblk 
      • Key-Clrrec 
      • 其中代码均为: app_folder.event('Trigger name') 

8. 在数据项数据块中创建FOLDER_SWITCHER的文本项,属性类为SWITCHER. 

9. 新建两个Stack canvas, 用来分别放置记录指示器及滚动条. 

10. 新建一个Stack canvas, 用来放置FOLDER OPEN及FOLDER TITLE.

 

Thanks and Regards

#include <windows.h> #include <shlobj.h> #include <stdio.h> #include <time.h> #include "aip_common.h" #define BTN_BROWSE_FOLDER (101) #define BTN_SAVE_SYMBOLS (102) #define BTN_GENERATE_DATA (103) #define BTN_PROCESS_DATA (104) #define EDIT_FOLDER_PATH (105) #define EDIT_USER_SYMBOLS (106) #define ZERO (0) #define ONE (1) #define TWO (2) #define MAX_FOLDER_LENGTH (260) #define MAX_SYMBOL_INPUT (10000) #define MAX_LINE_CONTENT (10000) #define MAX_SYMBOL_PAIRS (10) #define MAX_LINE_COUNT (100) #define MAX_LINE_LENGTH (50) #define DIGIT_START L'0' #define DIGIT_END L'9' #define UPPERCASE_START L'A' #define UPPERCASE_END L'Z' #define LOWERCASE_START L'a' #define LOWERCASE_END L'z' #define STACK_INIT -ONE #define STACK_EMPTY -ONE #define LINE_CONTENT_ELEMENTS (MAX_LINE_CONTENT) typedef struct { U2 u2_t_SYMBOL_open; U2 u2_t_SYMBOL_close; } ST_SYMBOL_PAIR; ST_SYMBOL_PAIR st_g_SYMBOL_pairs_p[MAX_SYMBOL_PAIRS]; U4 u4_g_SYMBOL_num_pairs = ZERO; // 符号对数量 U2 u2p_g_FILE_folder_path_p[MAX_FOLDER_LENGTH ]; // 文件夹路径 U2 u2p_g_SYMBOL_user_symbols_p[MAX_SYMBOL_INPUT ]; // 用户输入的符号对 // 函数声明 void v_g_SYMBOL_saveFile(const U2 *u2p_g_FILE_folder_path_p, const U2 *u2p_a_SYMBOL_user_input) ; U4 u4_g_SYMBOL_loadFile(const U2 *u2p_g_FILE_folder_path_p) ; U4 u4_g_SYMBOL_isOpening(U2 u2_t_SYMBOL_ch); U4 u4_g_SYMBOL_isClosing(U2 u2_t_SYMBOL_ch); U4 u4_g_SYMBOL_matches(U2 u2_t_SYMBOL_open, U2 u2_t_SYMBOL_close); void v_g_SYMBOL_generateRandomData(const U2 *u2p_g_FILE_folder_path_p); void v_g_SYMBOL_validateDataFile(const U2 *u2p_g_FILE_folder_path_p); void v_g_FILE_browseFolder(HWND hwnd); void v_g_SYMBOL_saveFile(const U2 *u2p_g_FILE_folder_path_p, const U2 *u2p_a_SYMBOL_user_input) { U2 u2_t_FILE_file_path_p[(U4)MAX_FOLDER_LENGTH ]; swprintf(u2_t_FILE_file_path_p, (U4)MAX_FOLDER_LENGTH , L"%ls\\Symbol.txt", u2p_g_FILE_folder_path_p); // 检查输入的字符是否包含数字或字母 for (U4 u4_t_LOOP_index = ZERO; u2p_a_SYMBOL_user_input[u4_t_LOOP_index] != L'\0'; u4_t_LOOP_index++) { if ((u2p_a_SYMBOL_user_input[u4_t_LOOP_index] >= DIGIT_START && u2p_a_SYMBOL_user_input[u4_t_LOOP_index] <= DIGIT_END) || // 检测到数字 (u2p_a_SYMBOL_user_input[u4_t_LOOP_index] >= UPPERCASE_START && u2p_a_SYMBOL_user_input[u4_t_LOOP_index] <= UPPERCASE_END) || // 检测到大写字母 (u2p_a_SYMBOL_user_input[u4_t_LOOP_index] >= LOWERCASE_START && u2p_a_SYMBOL_user_input[u4_t_LOOP_index] <= LOWERCASE_END)) { // 检测到小写字母 U2 u2_t_ERROR_message_p[(U4)MAX_FOLDER_LENGTH ]; swprintf(u2_t_ERROR_message_p, (U4)MAX_FOLDER_LENGTH , L"错误:输入包含无效字符:'%lc'。请重新输入合法的符号。", u2p_a_SYMBOL_user_input[u4_t_LOOP_index]); MessageBoxW(NULL, u2_t_ERROR_message_p, L"错误", MB_OK | MB_ICONERROR); return; // 立即停止处理 } } FILE *vdp_t_FILE_file = _wfopen(u2_t_FILE_file_path_p, L"w, ccs=UTF-8"); // 使用 UTF-8 编码写入文件 if (!vdp_t_FILE_file) { MessageBoxW(NULL, L"无法创建 Symbol.txt 文件。", L"错误", MB_OK | MB_ICONERROR); return; } U4 u4_t_SYMBOL_pair_count = (U4)ZERO; for (U4 u4_t_LOOP_index = (U4)ZERO; u2p_a_SYMBOL_user_input[u4_t_LOOP_index] != L'\0'; u4_t_LOOP_index++) { // 跳过无效字符 if ((u2p_a_SYMBOL_user_input[u4_t_LOOP_index] == L' ') || (u2p_a_SYMBOL_user_input[u4_t_LOOP_index] == L'\t') || (u2p_a_SYMBOL_user_input[u4_t_LOOP_index] == L'\n')) { continue; // 跳过空格、制表符、换行符 } // 确保符号对有效 if ((u2p_a_SYMBOL_user_input[u4_t_LOOP_index + (U4)ONE] != L'\0')&& (u2p_a_SYMBOL_user_input[u4_t_LOOP_index + (U4)ONE] != L'\n')&& (u2p_a_SYMBOL_user_input[u4_t_LOOP_index + (U4)ONE] != L' ') && (u2p_a_SYMBOL_user_input[u4_t_LOOP_index + (U4)ONE] != L'\t')) { fwprintf(vdp_t_FILE_file, L"%lc%lc\n", u2p_a_SYMBOL_user_input[u4_t_LOOP_index], u2p_a_SYMBOL_user_input[u4_t_LOOP_index + ONE]); // 写入符号对到文件 u4_t_LOOP_index++; // 跳过第二个符号 u4_t_SYMBOL_pair_count++; } } fclose(vdp_t_FILE_file); if (u4_t_SYMBOL_pair_count > ZERO) { MessageBoxW(NULL, L"符号已成功保存到 Symbol.txt 文件!", L"成功", MB_OK | MB_ICONINFORMATION); } else { MessageBoxW(NULL, L"输入中未发现有效符号对。", L"错误", MB_OK | MB_ICONERROR); } } U4 u4_g_SYMBOL_loadFile(const U2 *u2p_g_FILE_folder_path_p) { U2 u2_t_FILE_file_path_p[(U4)MAX_FOLDER_LENGTH ]; swprintf(u2_t_FILE_file_path_p, (U4)MAX_FOLDER_LENGTH , L"%ls\\Symbol.txt", u2p_g_FILE_folder_path_p); FILE *vdp_t_FILE_input_file = _wfopen(u2_t_FILE_file_path_p, L"r, ccs=UTF-8"); // 读取 UTF-8 编码内容 if (!vdp_t_FILE_input_file ) { MessageBoxW(NULL, L"错误:无法打开 Symbol.txt 文件。", L"错误", MB_OK | MB_ICONERROR); return 0; } u4_g_SYMBOL_num_pairs = (U4)ZERO; U2 u2_t_FILE_line_p[(U4)MAX_LINE_CONTENT]; while (fgetws(u2_t_FILE_line_p, (U4)(U4)LINE_CONTENT_ELEMENTS, vdp_t_FILE_input_file ) && u4_g_SYMBOL_num_pairs < MAX_SYMBOL_PAIRS) { U4 u4_t_SYMBOL_line_length = wcslen(u2_t_FILE_line_p); // 去掉行末的换行符 if (u4_t_SYMBOL_line_length > (U4)ZERO && u2_t_FILE_line_p[u4_t_SYMBOL_line_length - (U4)ONE] == L'\n') { u2_t_FILE_line_p[u4_t_SYMBOL_line_length - (U4)ONE] = L'\0'; u4_t_SYMBOL_line_length--; } // 跳过空行 if (u4_t_SYMBOL_line_length == (U4)ZERO) { continue; } // 检查符号对格式 U2 u2_t_SYMBOL_open, u2_t_SYMBOL_close; if (swscanf(u2_t_FILE_line_p, L"%lc%lc", &u2_t_SYMBOL_open, &u2_t_SYMBOL_close) == (U4)TWO) { // 检测数字或字母,直接跳过 if ((u2_t_SYMBOL_open >= DIGIT_START && u2_t_SYMBOL_open <= DIGIT_END) || (u2_t_SYMBOL_open >= UPPERCASE_START && u2_t_SYMBOL_open <= UPPERCASE_END) || (u2_t_SYMBOL_open >= LOWERCASE_START && u2_t_SYMBOL_open <= LOWERCASE_END) || (u2_t_SYMBOL_close >= DIGIT_START && u2_t_SYMBOL_close <= DIGIT_END) || (u2_t_SYMBOL_close >= UPPERCASE_START && u2_t_SYMBOL_close <= UPPERCASE_END) || (u2_t_SYMBOL_close >= LOWERCASE_START && u2_t_SYMBOL_close <= LOWERCASE_END)) { continue; // 跳过该行 } // 如果符号合法,加入符号对数组 st_g_SYMBOL_pairs_p[u4_g_SYMBOL_num_pairs].u2_t_SYMBOL_open = u2_t_SYMBOL_open; st_g_SYMBOL_pairs_p[u4_g_SYMBOL_num_pairs].u2_t_SYMBOL_close = u2_t_SYMBOL_close; u4_g_SYMBOL_num_pairs++; } } fclose(vdp_t_FILE_input_file ); U2 u2_t_ERROR_message_p[256]; swprintf(u2_t_ERROR_message_p, sizeof(u2_t_ERROR_message_p) / sizeof(U2), L"从 Symbol.txt 文件中加载了 %d 个有效符号对。", u4_g_SYMBOL_num_pairs); MessageBoxW(NULL, u2_t_ERROR_message_p, L"成功", MB_OK | MB_ICONINFORMATION); return u4_g_SYMBOL_num_pairs > ZERO; } // 随机生成 Data.txt 文件 void v_g_SYMBOL_generateRandomData(const U2 *u2p_g_FILE_folder_path_p) { if (u4_g_SYMBOL_num_pairs == (U4)ZERO) { MessageBoxW(NULL, L"错误:未加载任何符号对。请先加载 Symbol.txt 文件!", L"错误", MB_OK | MB_ICONERROR); return; } U2 u2_t_FILE_data_path_p[MAX_FOLDER_LENGTH ]; swprintf(u2_t_FILE_data_path_p, MAX_FOLDER_LENGTH , L"%ls\\Data.txt", u2p_g_FILE_folder_path_p); FILE *vdp_t_FILE_input_file = _wfopen(u2_t_FILE_data_path_p, L"w, ccs=UTF-8"); if (!vdp_t_FILE_input_file ) { MessageBoxW(NULL, L"错误:无法创建 Data.txt 文件。", L"错误", MB_OK | MB_ICONERROR); return; } srand((U4)time(NULL)); U4 u4_t_DATA_num_lines = rand() % MAX_LINE_COUNT + ONE; // 随机生成 1 到 100 行 for (U4 u4_t_DATA_line_index = (U4)ZERO; u4_t_DATA_line_index < u4_t_DATA_num_lines; u4_t_DATA_line_index++) { U4 u4_t_FILE_length = rand() % MAX_LINE_LENGTH + (U4)ONE; // 每行随机长度 1 到 50 for (U4 u4_t_SYMBOL_char_index = (U4)ZERO; u4_t_SYMBOL_char_index < u4_t_FILE_length; u4_t_SYMBOL_char_index++) { U4 u4_t_SYMBOL_pair_index = rand() % u4_g_SYMBOL_num_pairs; // 随机选择一个符号对 if (rand() % TWO == (U4)ZERO) { fputwc(st_g_SYMBOL_pairs_p[u4_t_SYMBOL_pair_index].u2_t_SYMBOL_open, vdp_t_FILE_input_file ); // 写入开符号 } else { fputwc(st_g_SYMBOL_pairs_p[u4_t_SYMBOL_pair_index].u2_t_SYMBOL_close, vdp_t_FILE_input_file ); // 写入闭符号 } } fputwc(L'\n', vdp_t_FILE_input_file ); // 换行符 } fclose(vdp_t_FILE_input_file ); MessageBoxW(NULL, L"Data.txt 文件已成功生成!", L"成功", MB_OK | MB_ICONINFORMATION); } // 检查符号是否匹配 U4 u4_g_SYMBOL_matches(U2 u2_t_SYMBOL_open, U2 u2_t_SYMBOL_close) { U4 u4_t_SYMBOL_match_flag = (U4)FALSE; // 匹配结果 for (U4 u4_t_SYMBOL_pair_index = (U4)ZERO; u4_t_SYMBOL_pair_index < u4_g_SYMBOL_num_pairs; u4_t_SYMBOL_pair_index++) { if (st_g_SYMBOL_pairs_p[u4_t_SYMBOL_pair_index].u2_t_SYMBOL_open == u2_t_SYMBOL_open && st_g_SYMBOL_pairs_p[u4_t_SYMBOL_pair_index].u2_t_SYMBOL_close == u2_t_SYMBOL_close) { u4_t_SYMBOL_match_flag = (U4)TRUE; // 匹配成功 break; // 找到结果后退出 } } return u4_t_SYMBOL_match_flag; } // 检查是否是开符号 U4 u4_g_SYMBOL_isOpening(U2 u2_t_SYMBOL_ch) { U4 u4_t_SYMBOL_is_open_flag = (U4)FALSE; // 是否是开符号 for (U4 u4_t_SYMBOL_pair_index = (U4)ZERO; u4_t_SYMBOL_pair_index < u4_g_SYMBOL_num_pairs; u4_t_SYMBOL_pair_index++) { if (st_g_SYMBOL_pairs_p[u4_t_SYMBOL_pair_index].u2_t_SYMBOL_open == u2_t_SYMBOL_ch) { u4_t_SYMBOL_is_open_flag = (U4)TRUE; // 是开符号 break; // 提前退出 } } return u4_t_SYMBOL_is_open_flag; } // 检查是否是闭符号 U4 u4_g_SYMBOL_isClosing(U2 u2_t_SYMBOL_ch) { U4 u4_t_SYMBOL_is_close_flag = (U4)FALSE; // 是否是闭符号 for (U4 u4_t_SYMBOL_pair_index = (U4)ZERO; u4_t_SYMBOL_pair_index < u4_g_SYMBOL_num_pairs; u4_t_SYMBOL_pair_index++) { if (st_g_SYMBOL_pairs_p[u4_t_SYMBOL_pair_index].u2_t_SYMBOL_close == u2_t_SYMBOL_ch) { u4_t_SYMBOL_is_close_flag = (U4)TRUE; // 是闭符号 break; // 提前退出 } } return u4_t_SYMBOL_is_close_flag; } // 验证 Data.txt 文件符号对并保存结果到 Result.txt 文件 void v_g_SYMBOL_validateDataFile(const U2 *u2p_g_FILE_folder_path_p) { // 定义文件路径变量 U2 u2_t_FILE_data_path_p[(U4)MAX_FOLDER_LENGTH]; // Data.txt 文件路径 U2 u2_t_FILE_result_path_p[(U4)MAX_FOLDER_LENGTH]; // Result.txt 文件路径 swprintf(u2_t_FILE_data_path_p, MAX_FOLDER_LENGTH, L"%ls\\Data.txt", u2p_g_FILE_folder_path_p); swprintf(u2_t_FILE_result_path_p, MAX_FOLDER_LENGTH, L"%ls\\Result.txt", u2p_g_FILE_folder_path_p); // 打开 Data.txt 文件 VDP vdp_t_FILE_data_file = _wfopen(u2_t_FILE_data_path_p, L"r, ccs=UTF-8"); if (!vdp_t_FILE_data_file) { MessageBoxW(NULL, L"错误:无法打开 Data.txt 文件。", L"错误", MB_OK | MB_ICONERROR); return; } // 打开 Result.txt 文件 VDP vdp_t_FILE_result_file = _wfopen(u2_t_FILE_result_path_p, L"w, ccs=UTF-8"); if (!vdp_t_FILE_result_file) { MessageBoxW(NULL, L"错误:无法创建 Result.txt 文件。", L"错误", MB_OK | MB_ICONERROR); fclose(vdp_t_FILE_data_file); return; } // 读取 Data.txt 的每一行并处理 U2 u2_t_FILE_line_p[(U4)MAX_LINE_CONTENT]; // 保存单行输入的缓冲区 while (fgetws(u2_t_FILE_line_p, (U4)MAX_LINE_CONTENT, vdp_t_FILE_data_file)) { U4 u4_t_SYMBOL_line_length = wcslen(u2_t_FILE_line_p); // 去掉换行符 if (u4_t_SYMBOL_line_length > ZERO && u2_t_FILE_line_p[u4_t_SYMBOL_line_length - ONE] == L'\n') { u2_t_FILE_line_p[u4_t_SYMBOL_line_length - ONE] = L'\0'; u4_t_SYMBOL_line_length -= ONE; } // 空行直接跳过 if (u4_t_SYMBOL_line_length == ZERO) { continue; } // 定义符号校验栈 U2 u2_t_SYMBOL_validation_stack_p[(U4)MAX_LINE_CONTENT]; // 用于符号校验的栈 U4 u4_t_SYMBOL_stack_top_index = (U4)STACK_INIT; // 栈顶初始索引 U4 u4_t_SYMBOL_matched_flag = (U4)TRUE; // 记录当前行是否匹配 // 遍历字符并进行校验 for (U4 u4_t_SYMBOL_char_index = (U4)ZERO; u4_t_SYMBOL_char_index < u4_t_SYMBOL_line_length; u4_t_SYMBOL_char_index++) { U2 u2_t_SYMBOL_current_char = u2_t_FILE_line_p[u4_t_SYMBOL_char_index]; // 处理开符号 if (u4_g_SYMBOL_isOpening(u2_t_SYMBOL_current_char)) { u2_t_SYMBOL_validation_stack_p[++u4_t_SYMBOL_stack_top_index] = u2_t_SYMBOL_current_char; } // 处理闭符号 else if (u4_g_SYMBOL_isClosing(u2_t_SYMBOL_current_char)) { if (u4_t_SYMBOL_stack_top_index == (U4)STACK_EMPTY || !u4_g_SYMBOL_matches(u2_t_SYMBOL_validation_stack_p[u4_t_SYMBOL_stack_top_index], u2_t_SYMBOL_current_char)) { u4_t_SYMBOL_matched_flag = (U4)FALSE; // 栈空或不匹配 break; } u4_t_SYMBOL_stack_top_index--; // 弹出栈 } } // 栈非空说明有未匹配的符号 if (u4_t_SYMBOL_stack_top_index != (U4)STACK_EMPTY) { u4_t_SYMBOL_matched_flag = (U4)FALSE; } // 写入匹配结果 fwprintf(vdp_t_FILE_result_file, L"%s\n", u4_t_SYMBOL_matched_flag ? L"YES" : L"NO"); } // 关闭文件 fclose(vdp_t_FILE_data_file); fclose(vdp_t_FILE_result_file); MessageBoxW(NULL, L"Result.txt 文件已成功生成!", L"成功", MB_OK | MB_ICONINFORMATION); } // 文件夹选择对话框 void v_g_FILE_browseFolder(HWND hwnd) { BROWSEINFOW st_t_UI_folder_dialog_p = {(U4)ZERO}; // 初始化选择文件夹对话框结构体 st_t_UI_folder_dialog_p.lpszTitle = L"Select Folder"; // 设置标题 st_t_UI_folder_dialog_p.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; // 设置对话框样式 LPITEMIDLIST stp_t_UI_folder_item_p = SHBrowseForFolderW(&st_t_UI_folder_dialog_p); // 显示对话框 if (stp_t_UI_folder_item_p != NULL) { SHGetPathFromIDListW(stp_t_UI_folder_item_p, u2p_g_FILE_folder_path_p); // 获取选择的文件夹路径 SetDlgItemTextW(hwnd, EDIT_FOLDER_PATH, u2p_g_FILE_folder_path_p); // 设置路径到窗口控件 } } // 窗口消息处理过程 LRESULT CALLBACK g_UI_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { RECT st_t_UI_window_rect; // 定义窗口矩形结构体 GetClientRect(hwnd, &st_t_UI_window_rect); // 获取客户区矩形 U4 u4_t_UI_spacing = 20; // 定义控件间隔距离 CreateWindowW(L"BUTTON", L"浏览文件夹", WS_VISIBLE | WS_CHILD, 20, 50, 120, 30, hwnd, (HMENU)BTN_BROWSE_FOLDER, NULL, NULL); CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER, 150, 50, 430, 30, hwnd, (HMENU)EDIT_FOLDER_PATH, NULL, NULL); CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER, 20, 90, 400, 30, hwnd, (HMENU)EDIT_USER_SYMBOLS, NULL, NULL); CreateWindowW(L"BUTTON", L"保存符号到Symbol.txt", WS_VISIBLE | WS_CHILD, 430, 90, 150, 30, hwnd, (HMENU)BTN_SAVE_SYMBOLS, NULL, NULL); CreateWindowW(L"BUTTON", L"随机生成Data.txt", WS_VISIBLE | WS_CHILD, 20, 130, 130, 30, hwnd, (HMENU)BTN_GENERATE_DATA, NULL, NULL); CreateWindowW(L"BUTTON", L"开始处理", WS_VISIBLE | WS_CHILD, 230, 170, 120, 40, hwnd, (HMENU)BTN_PROCESS_DATA, NULL, NULL); break; } case WM_COMMAND: switch (LOWORD(wParam)) { case BTN_BROWSE_FOLDER: v_g_FILE_browseFolder(hwnd); // 文件夹选择对话框 break; case BTN_SAVE_SYMBOLS: GetDlgItemTextW(hwnd, EDIT_FOLDER_PATH, u2p_g_FILE_folder_path_p, MAX_FOLDER_LENGTH); GetDlgItemTextW(hwnd, EDIT_USER_SYMBOLS, u2p_g_SYMBOL_user_symbols_p, MAX_SYMBOL_INPUT); v_g_SYMBOL_saveFile(u2p_g_FILE_folder_path_p, u2p_g_SYMBOL_user_symbols_p); // 保存符号 break; case BTN_GENERATE_DATA: GetDlgItemTextW(hwnd, EDIT_FOLDER_PATH, u2p_g_FILE_folder_path_p, MAX_FOLDER_LENGTH); if (u4_g_SYMBOL_loadFile(u2p_g_FILE_folder_path_p)) { v_g_SYMBOL_generateRandomData(u2p_g_FILE_folder_path_p); // 生成随机数据 } break; case BTN_PROCESS_DATA: GetDlgItemTextW(hwnd, EDIT_FOLDER_PATH, u2p_g_FILE_folder_path_p, MAX_FOLDER_LENGTH); v_g_SYMBOL_validateDataFile(u2p_g_FILE_folder_path_p); // 验证数据文件 break; } break; case WM_DESTROY: PostQuitMessage(ZERO); // 退出消息 break; default: return DefWindowProcW(hwnd, msg, wParam, lParam); // 默认处理 } return ZERO; // 默认返回值 } int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { const U2 u2_g_UI_class_name_p[] = L"符号匹配"; // 定义窗口类名 WNDCLASSW st_t_UI_window_class = {(U4)ZERO}; // 定义窗口类结构体 st_t_UI_window_class.lpfnWndProc = g_UI_WindowProc; // 指定消息处理过程 st_t_UI_window_class.hInstance = hInstance; // 指定实例句柄 st_t_UI_window_class.lpszClassName = u2_g_UI_class_name_p; // 指定窗口类名 RegisterClassW(&st_t_UI_window_class); // 注册窗口类 HWND vdp_t_UI_main_window = CreateWindowW(u2_g_UI_class_name_p, L"符号匹配", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 610, 280, NULL, NULL, hInstance, NULL); // 创建窗口 MSG st_t_UI_message; // 定义消息结构体 while (GetMessageW(&st_t_UI_message, NULL, ZERO, ZERO)) { TranslateMessage(&st_t_UI_message); // 翻译消息 DispatchMessageW(&st_t_UI_message); // 分派消息 } return ZERO; // 返回退出状态码 } 注释改成全英文的,每个函数前面加一段介绍,形如: /*===================================================================================================================================*/ /* Function Name: u4_s_main_processing_task */ /* --------------------------------------------------------------------------------------------------------------------------------- */ /* Description: Processes input file: searches for prefix, extracts/modifies addresses, writes results */ /* Arguments: U1* u1p_a_search_string : Prefix string to search */ /* Return: U4 : SUCCESS if found and processed, WRONG otherwise */ /*===================================================================================================================================*/ 每个if后面都要接else,没有操作就: else { /*do nothing*/ }
最新发布
08-22
<think>好的,用户现在问的是如何在macOS上开发Windows Forms软件。之前他已经问过如何在macOS搭建.NET Framework 4.0的开发环境,现在问题更具体了,直接针对Windows Forms。我需要回顾之前的回答,看看有没有需要调整的地方。 首先,Windows Forms是.NET Framework的一部分,只能在Windows上运行。用户想在macOS上开发,这确实有挑战。之前的回答里提到了三个方案:Mono、虚拟机、迁移到.NET跨平台。但针对Windows Forms,Mono的支持可能有限,特别是设计器方面。虚拟机可能是更可行的方案,但用户可能需要图形界面设计,这时候可能需要完整的Visual Studio。 我需要考虑用户的实际需求。他可能是一个需要在Mac环境下工作,但需要维护或开发现有的Windows Forms应用。或者他可能刚开始一个项目,但误以为可以在Mac上直接开发Windows Forms。需要明确告知Windows Forms的局限性,同时提供替代方案。 另外,用户可能不了解跨平台GUI框架,比如Avalonia或MAUI,这时候需要推荐这些工具,并说明迁移的步骤。同时,虚拟机方案需要详细步骤,比如安装Parallels或VMware,配置共享文件夹,使用Visual Studio等。 还要注意用户可能不愿意购买虚拟机软件,所以需要提到免费的选项如VirtualBox,但性能可能较差。同时,调试部分需要指导如何在虚拟机中设置环境,或者使用远程调试的方法。 另外,是否有其他工具或服务可以在macOS上直接运行Windows应用?比如Wine,但Wine对Windows Forms的支持如何?可能需要调研一下,但通常不推荐,因为兼容性问题太多。 最后,总结各方案的优缺点,帮助用户根据自身情况选择。可能用户最需要的是快速解决方案,所以虚拟机可能是最直接的,尽管资源消耗大。而长期项目则建议迁移到跨平台框架。</think>在 macOS 上开发 **Windows Forms** 应用程序面临根本性限制(依赖 Windows 系统组件),但可通过以下方案实现部分开发或迁移: --- ### **一、核心限制** - **Windows Forms** 是 .NET Framework 的 GUI 框架,底层依赖 Windows API(如 `User32.dll`, `GDI+`)。 - **macOS 原生无法运行或设计 Windows Forms 界面**,需借助跨平台工具或虚拟机。 --- ### **二、可行方案与步骤** #### **方案 1:虚拟机运行完整 Windows 环境(推荐)** ##### **步骤 1:安装虚拟机软件** - **Parallels Desktop**(付费,性能最佳,支持 macOS 无缝模式) - **VMware Fusion**(免费个人版) - **VirtualBox**(免费,配置复杂) ##### **步骤 2:配置 Windows 开发环境** 1. 在虚拟机中安装 **Windows 10/11**。 2. 安装 **.NET Framework 4.8**(支持最新 Windows Forms)。 3. 安装 **Visual Studio Community 2022**(Windows 版),选择“Windows 桌面开发”工作负载。 ##### **步骤 3:开发与调试** - 在虚拟机内使用 Visual Studio 设计器和调试器直接开发。 - 通过共享文件夹功能在 macOS 和 Windows 间同步代码。 #### **方案 2:使用跨平台替代框架(需代码改造)** ##### **步骤 1:迁移到 Avalonia(推荐)** - Avalonia 是跨平台 XAML 框架,语法类似 WPF,支持 macOS/Linux/Windows。 - 安装 Avalonia 模板: ```shell dotnet new install Avalonia.Templates dotnet new avalonia.app -o MyAvaloniaApp ``` - 使用 **VS Code** 或 **Rider** 开发,复用原有业务逻辑,替换 UI 层。 ##### **步骤 2:使用 .NET MAUI(仅部分兼容)** - .NET MAUI 是跨平台框架,但不直接支持 Windows Forms。 - 需重写 UI 层,适合新项目: ```shell dotnet new maui -o MyMauiApp ``` #### **方案 3:Mono + GTK#(老旧方案,不推荐)** - **Mono** 曾提供 `WinForms` 的跨平台实现,但兼容性差且无官方维护。 - 安装 Mono 并尝试运行简单项目: ```shell brew install mono mono MyWinFormsApp.exe ``` - **已知问题**: - 复杂控件(如 `DataGridView`)渲染异常。 - 设计器不可用,需手动编写界面代码。 --- ### **三、方案对比** | 方案 | 优点 | 缺点 | |-----------------------|-------------------------------|---------------------------------------| | **虚拟机 + Visual Studio** | 完整支持设计和调试 | 需 Windows 授权,占用大量系统资源 | | **Avalonia** | 跨平台,现代框架,长期维护 | 需重写 UI 层,学习曲线较高 | | **Mono WinForms** | 无需虚拟机 | 兼容性差,无官方支持,仅适合简单项目 | --- ### **四、详细操作示例(以虚拟机方案为例)** #### **1. 在 Parallels Desktop 中配置共享开发** 1. 安装 Parallels Desktop 并创建 Windows 11 虚拟机。 2. 启用共享文件夹: **Parallels** > **配置** > **共享** > 添加 macOS 项目目录。 3. 在 Windows 中安装 Visual Studio,通过共享目录直接编辑代码。 ![Parallels共享文件夹](https://example.com/parallels-shared-folder.png) #### **2. 调试优化** - **性能提升**: 为虚拟机分配至少 **4 核 CPU + 8GB 内存**,关闭不必要的后台进程。 - **无缝模式**: 启用 Parallels 的“融合模式”,将 Visual Studio 窗口直接映射到 macOS 桌面。 --- ### **五、常见问题** #### **Q1:能否在 macOS 上直接设计 Windows Forms 界面?** - **否**。Windows Forms 设计器依赖 Visual Studio(Windows 版),需通过虚拟机运行。 #### **Q2:Avalonia 能完全替代 Windows Forms 吗?** - **部分替代**: 基础控件(按钮、文本框等)可直接迁移,但复杂功能(如第三方控件库)需使用 Avalonia 等效实现。 #### **Q3:虚拟机运行卡顿如何解决?** - 关闭 macOS 的 Transparency 和动画效果。 - 为虚拟机分配更多内存,并使用 SSD 存储。 --- ### **六、总结建议** - **短期/维护旧项目** → 使用 **虚拟机 + Visual Studio**。 - **长期/新项目** → 迁移到 **Avalonia** 或 **.NET MAUI**。 - **避免尝试**:Mono WinForms(已过时,问题多)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值