From 7666ec39fe8474391890bd4be49561820298e4cf Mon Sep 17 00:00:00 2001 From: LuChiChick <1084116302@qq.com> Date: Fri, 5 Dec 2025 17:49:09 +0800 Subject: [PATCH] Added control buttons to enable selective file export functionality && Fixed the issue where files were not closed after DLT Log export && Resolved the problem of files failing to open due to Chinese path characters && Modified alert pop-up icons && Adjusted the initial display position --- Inc/UI_Layout.hpp | 3 + Src/Command_Solve.cpp | 21 ----- Src/DLT_Utilities.cpp | 2 + Src/Main.cpp | 30 ++++--- Src/UI_Layout.cpp | 184 ++++++++++++++++++++++++++++++++++++++---- 5 files changed, 189 insertions(+), 51 deletions(-) diff --git a/Inc/UI_Layout.hpp b/Inc/UI_Layout.hpp index 3438b50..dfb5129 100644 --- a/Inc/UI_Layout.hpp +++ b/Inc/UI_Layout.hpp @@ -17,6 +17,9 @@ namespace Widgets // 工作流区域 void Workflow_Area(const ImVec2 &size = ImVec2(0, 0)); + + // 控制面板区域 + void Control_Panel(const ImVec2 &size = ImVec2(0, 0)); } #endif \ No newline at end of file diff --git a/Src/Command_Solve.cpp b/Src/Command_Solve.cpp index d189656..62c8ed9 100644 --- a/Src/Command_Solve.cpp +++ b/Src/Command_Solve.cpp @@ -12,27 +12,6 @@ DLT_Log File; // 命令行处理 void Pre_Command_Solve(void) { - CSV_Table CSV; - CSV.insert_column_before((unsigned)0, "First insert"); - CSV.append_column("Test column"); - CSV.append_column("Test column 2"); - CSV.append_column("Test column 3"); - CSV.insert_column_after("Test column 2", "Test insert column"); - CSV.insert_column_after("Test column 3", "Test insert column after End"); - - CSV.insert_column_before("Test column", "Test insert column before Head"); - CSV.insert_column_before("Test column", "Test insert column before Origin"); - - CSV.insert_cell_before("Test column 2", 0, "0"); - CSV.append_cell("Test column 2", "1"); - CSV.insert_cell_before("Test column 2", 0, "Insert"); - CSV.insert_cell_after("Test column 3", (unsigned)0, "Insert Cell"); - CSV.append_cell("Test column 3", "1"); - CSV.append_cell("Test column 3", "MyWawwww,dwadawdawd"); - CSV.append_cell("Test column 3", "3"); - - CSV.export_to_file("new.csv"); - // 获取命令行 int argc; LPWSTR *argv; diff --git a/Src/DLT_Utilities.cpp b/Src/DLT_Utilities.cpp index 5e04b9a..84953f5 100644 --- a/Src/DLT_Utilities.cpp +++ b/Src/DLT_Utilities.cpp @@ -405,5 +405,7 @@ DLT_Type::DLT_Err DLT_Log::export_to_csv(const char *file_name_str) p_msg = p_msg->p_next; } + fclose(p_file); + return DLT_Type::DLT_ERROR_NONE; } \ No newline at end of file diff --git a/Src/Main.cpp b/Src/Main.cpp index 90379d9..b86b15e 100644 --- a/Src/Main.cpp +++ b/Src/Main.cpp @@ -12,6 +12,7 @@ extern "C" #include "d3d11.h" #include "tchar.h" #include "wchar.h" +#include "locale.h" } // 自定义头文件 @@ -35,6 +36,9 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg // 入口主函数 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { + // 设置本地化以支持特殊字符 + setlocale(LC_ALL, ".UTF-8"); + // 命令行前置处理 Pre_Command_Solve(); @@ -61,17 +65,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine RegisterClassExW(&wc); // 创建窗体 - Main_Window_hWnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名 - MAIN_FRAME_TITTLE, // 窗体标题 - WS_OVERLAPPEDWINDOW, // 窗体风格为标准可重叠的顶层窗口 - 100, // 起始坐标x - 100, // 起始坐标y - (int)(MAIN_FRAME_SIZE_WIDTH_MIN * main_scale), // 窗体长 - (int)(MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale), // 窗体宽 - nullptr, // 父窗体句柄 - nullptr, // 菜单句柄 - wc.hInstance, // 创建实例句柄 - nullptr); // 额外的事件参数指针 + Main_Window_hWnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名 + MAIN_FRAME_TITTLE, // 窗体标题 + WS_OVERLAPPEDWINDOW, // 窗体风格为标准可重叠的顶层窗口 + (GetSystemMetrics(SM_CXSCREEN) - (MAIN_FRAME_SIZE_WIDTH_MIN * main_scale)) / 2, // 起始坐标x,设置为屏幕正中 + (GetSystemMetrics(SM_CYSCREEN) - (MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale)) / 2, // 起始坐标y,设置为屏幕正中 + (int)(MAIN_FRAME_SIZE_WIDTH_MIN * main_scale), // 窗体长 + (int)(MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale), // 窗体宽 + nullptr, // 父窗体句柄 + nullptr, // 菜单句柄 + wc.hInstance, // 创建实例句柄 + nullptr); // 额外的事件参数指针 // 在窗体内创建 Direct 3D 设备 if (!CreateDeviceD3D(Main_Window_hWnd)) @@ -407,10 +411,10 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) DragFinish(hDrop); if (with_duplicated_input) - MessageBoxW(hWnd, L"存在重复输入", L"", MB_OK); + MessageBoxW(hWnd, L"存在重复输入", L"", MB_OK | MB_ICONWARNING); if (with_illegal_input) - MessageBoxW(hWnd, L"存在非法输入,仅支持 .dlt 文件", L"", MB_OK); + MessageBoxW(hWnd, L"存在非法输入,仅支持 .dlt 文件", L"", MB_OK | MB_ICONWARNING); return 0; } diff --git a/Src/UI_Layout.cpp b/Src/UI_Layout.cpp index 3d50370..583071a 100644 --- a/Src/UI_Layout.cpp +++ b/Src/UI_Layout.cpp @@ -2,6 +2,7 @@ #include "imgui_impl_win32.h" #include "Global_Variables.hpp" #include "Config.hpp" +#include "DLT_Utilities.hpp" extern "C" { @@ -9,6 +10,8 @@ extern "C" #include "stdio.h" } +#include "thread" + // UI布局 void UI_Layout() { @@ -36,16 +39,21 @@ void UI_Layout() ImGui::Begin("Main Panel", NULL, window_flags); // 创建主面板 ImGui::PopStyleVar(2); // 退出绘制风格栈中的设置项 { + const ImGuiStyle &style = ImGui::GetStyle(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY)); // 拖拽输入区域 - Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2)); + Widgets::Drag_Input_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().x / 2 > MAIN_FRAME_SIZE_WIDTH_MIN / 2 ? MAIN_FRAME_SIZE_WIDTH_MIN / 2 : ImGui::GetContentRegionAvail().x / 2)); // 文件列表组件 - Widgets::File_List_Area(); + Widgets::File_List_Area(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - (ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale + style.ItemSpacing.y))); + + // 导出文件 + Widgets::Control_Panel(ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() + 20 * main_scale)); } ImGui::End(); - ImGui::ShowDemoWindow(nullptr); + // ImGui::ShowDemoWindow(nullptr); } void Widgets::Drag_Input_Area(const ImVec2 &size) @@ -64,23 +72,20 @@ void Widgets::Drag_Input_Area(const ImVec2 &size) // Initialize OPENFILENAME ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = Main_Window_hWnd; - ofn.lpstrFile = szFile; - // Set lpstrFile[0] to '\0' so that GetOpenFileName does not - // use the contents of szFile to initialize itself. - ofn.nMaxFile = sizeof(szFile); - ofn.lpstrFilter = L"(.dlt)\0*.dlt\0"; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = NULL; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; + ofn.lStructSize = sizeof(ofn); // 结构体大小 + ofn.hwndOwner = Main_Window_hWnd; // 对话框唤起窗体 + ofn.lpstrFile = szFile; // 输出缓冲区 + ofn.nMaxFile = sizeof(szFile); // 缓冲区大小 + ofn.lpstrFilter = L"(.dlt)\0*.dlt\0"; // 文件格式筛选器 + ofn.nFilterIndex = 1; // 默认选择的筛选器 + + // 文件路径必须存在 | 文件本身必须存在 | 允许多文件选择 | 使用资源管理器 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER; // Display the Open dialog box. // 处理文件输入 - if (GetOpenFileNameW(&ofn) == TRUE) + if (GetOpenFileNameW(&ofn)) { // 重复输入检测 bool with_duplicated_input = false; @@ -101,7 +106,7 @@ void Widgets::Drag_Input_Area(const ImVec2 &size) } if (with_duplicated_input) { - MessageBoxW(Main_Window_hWnd, L"存在重复输入", L"", MB_OK); + MessageBoxW(Main_Window_hWnd, L"存在重复输入", L"", MB_OK | MB_ICONWARNING); } else { @@ -194,7 +199,7 @@ void Widgets::Drag_Input_Area(const ImVec2 &size) void Widgets::File_List_Area(const ImVec2 &size) { ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f); - ImGui::BeginChild("File_List_Area_Wrapper", ImVec2(size.x, size.y), ImGuiChildFlags_Border); + ImGui::BeginChild("File_List_Area_Wrapper", size, ImGuiChildFlags_Border); ImGui::PopStyleVar(); { @@ -266,4 +271,149 @@ void Widgets::Workflow_Area(const ImVec2 &size) ImNodes::EndNode(); } ImNodes::EndNodeEditor(); +} + +void Widgets::Control_Panel(const ImVec2 &size) +{ + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImGui::BeginChild("Control_Panel", size, ImGuiChildFlags_Border); + ImGui::PopStyleVar(2); + { + static bool export_confirmed = false; + static bool export_task_created = false; + static char export_file_path_str[MAX_PATH] = {'\0'}; + + if (!export_confirmed) + { + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 10.0f); + if (ImGui::Button(u8"导出", ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y))) + { + if (input_dlt_file_list_head == nullptr) + MessageBoxW(Main_Window_hWnd, L"需要至少输入一个文件", L"", MB_OK | MB_ICONERROR); + else + { + OPENFILENAMEW ofn; // common dialog box structure + static wchar_t szFile[MAX_PATH] = {L'\0'}; // buffer for file name + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); // 结构体大小 + ofn.hwndOwner = Main_Window_hWnd; // 对话框唤起窗体 + ofn.lpstrFile = szFile; // 输出缓冲区 + ofn.nMaxFile = sizeof(szFile); // 缓冲区大小 + ofn.lpstrFilter = L"(.csv)\0*.csv\0"; // 文件格式筛选器 + ofn.nFilterIndex = 1; // 默认选择的筛选器 + + // 文件路径必须存在 | 文件本身必须存在 | 使用资源管理器 + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER; + + if (GetSaveFileNameW(&ofn)) + { + // 提取文件路径 + memset(export_file_path_str, '\0', sizeof(export_file_path_str)); + int size_needed = WideCharToMultiByte(CP_UTF8, 0, szFile, -1, NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, szFile, -1, export_file_path_str, size_needed, NULL, NULL); + + wchar_t File_Name[MAX_PATH] = {L'\0'}; + wchar_t *p_str_end = szFile + wcslen(szFile); + + // 处理后缀 + char *p_extension_name = export_file_path_str + (strlen(export_file_path_str) - 4); + + if (p_extension_name[0] != '.' || toupper(p_extension_name[1]) != 'C' || toupper(p_extension_name[2]) != 'S' || toupper(p_extension_name[3]) != 'V') + { + p_extension_name += 4; + p_extension_name[0] = '.'; + p_extension_name[1] = 'c'; + p_extension_name[2] = 's'; + p_extension_name[3] = 'v'; + + p_str_end[0] = L'.'; + p_str_end[1] = L'c'; + p_str_end[2] = L's'; + p_str_end[3] = L'v'; + } + + while (p_str_end != szFile && *(p_str_end - 1) != L'\\') + p_str_end--; + + size_t len = wcslen(p_str_end); + for (size_t count = 0; count < len; count++, p_str_end++) + File_Name[count] = *p_str_end; + + memcpy(szFile, File_Name, sizeof(File_Name)); + + // 判定是否覆盖文件 + FILE *p_file = fopen(export_file_path_str, "rb"); + if (p_file != nullptr) + { + fclose(p_file); + if (MessageBoxW(Main_Window_hWnd, L"文件已存在,是否覆盖?", L"", MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) == IDYES) + export_confirmed = true; + } + else + export_confirmed = true; + } + } + } + ImGui::PopStyleVar(); + } + else + { + // 创建导出任务 + if (!export_task_created) + { + export_task_created = true; + + // 执行导出任务的线程 + std::thread export_thread( + [&]() + { + DLT_Log Log; + Input_File_Node *p_file_list = input_dlt_file_list_head; + DLT_Type::DLT_Err err; + + while (p_file_list != nullptr) + { + err = Log.load_from_file(p_file_list->file_name_str); + if (err != DLT_Type::DLT_ERROR_NONE) + break; + p_file_list = p_file_list->p_next; + } + + if (err != DLT_Type::DLT_ERROR_NONE) + { + switch (err) + { + case DLT_Type::DLT_ERROR_FILE_OPEN_FAILED: // 文件打开失败 + MessageBoxW(Main_Window_hWnd, L"文件打开失败,检查路径是否存在特殊字符", L"", MB_OK | MB_ICONERROR); + break; + default: + MessageBoxW(Main_Window_hWnd, L"文件加载失败", L"", MB_OK | MB_ICONERROR); + } + } + else + { + err = Log.export_to_csv(export_file_path_str); + + if (err == DLT_Type::DLT_ERROR_NONE) + MessageBoxW(Main_Window_hWnd, L"导出完成", L"", MB_OK); + else + MessageBoxW(Main_Window_hWnd, L"导出失败,检查文件占用", L"", MB_OK | MB_ICONERROR); + } + export_confirmed = false; + export_task_created = false; + }); + + // 分离线程 + export_thread.detach(); + } + + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.5f); + ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y), u8"正在导出..."); + ImGui::PopStyleVar(); + } + } + ImGui::EndChild(); } \ No newline at end of file