Advertisement
alien_fx_fiend

Binary Tree Visualizer (Win32 GUI) (Needs Fixing)

Nov 3rd, 2024
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.75 KB | Source Code | 0 0
  1. #include <windows.h>
  2. #include <windowsx.h>  // Add this line
  3. #include <commctrl.h>
  4. #include <string>
  5. #include <vector>
  6. #include <algorithm>  // Add this at the top with other includes
  7. #include <functional>
  8. #include <ctime>    // for time()
  9. #include <cstdlib>  // for rand() and srand()
  10. #include <random>
  11. #include <sstream>
  12. #include <iostream>
  13. #include <richedit.h> // Include for Rich Edit control
  14. #include <shellapi.h>
  15.  
  16. #pragma comment(lib, "Psapi.lib")
  17. #pragma comment(lib, "comctl32.lib") // Link with the common controls library
  18. //#pragma comment(lib, "riched32.lib")  // Link with the rich edit library
  19. #pragma comment(lib, "Shell32.lib")
  20.  
  21. // Structure for a binary tree node
  22. struct Node {
  23.     int data;
  24.     Node* left;
  25.     Node* right;
  26.  
  27.     Node(int val) : data(val), left(nullptr), right(nullptr) {}
  28. };
  29.  
  30. // Function to insert a new node into the binary tree
  31. Node* insert(Node* root, int val) {
  32.     if (!root) {
  33.         return new Node(val);
  34.     }
  35.  
  36.     if (val < root->data) {
  37.         root->left = insert(root->left, val);
  38.     }
  39.     else {
  40.         root->right = insert(root->right, val);
  41.     }
  42.     return root;
  43. }
  44.  
  45.  
  46. // Helper function to get the height of the tree
  47. // Helper function to get the height of the tree
  48. int getHeight(Node* root) {
  49.     if (!root) return 0;
  50.     return 1 + max(getHeight(root->left), getHeight(root->right));
  51. }
  52.  
  53. // Helper function to add padding
  54. std::string getPadding(int level) {
  55.     return std::string(level * 6, ' ');
  56. }
  57.  
  58. std::string getListString(Node* root, std::string prefix = "") {
  59.     if (!root) return "";
  60.  
  61.     std::string result = prefix + "|_ " + std::to_string(root->data) + "\r\n";
  62.  
  63.     if (root->left) {
  64.         bool hasRight = (root->right != nullptr);
  65.         std::string newPrefix = prefix + (hasRight ? "|  " : "   ");
  66.         result += getListString(root->left, newPrefix);
  67.     }
  68.  
  69.     if (root->right) {
  70.         std::string newPrefix = prefix + "   ";
  71.         result += getListString(root->right, newPrefix);
  72.     }
  73.  
  74.     return result;
  75. }
  76.  
  77. // Modified getTreeString function with correct lambda capture
  78. std::string getTreeString(Node* root) {
  79.     if (!root) return "";
  80.  
  81.     std::vector<std::string> levels;
  82.  
  83.     std::function<void(Node*, int, std::string)> traverse =
  84.         [&levels, &traverse](Node* node, int depth, std::string prefix) {
  85.         if (!node) return;
  86.  
  87.         // Ensure we have enough levels
  88.         while (levels.size() <= depth) {
  89.             levels.push_back("");
  90.         }
  91.  
  92.         // Add current node to its level
  93.         levels[depth] += prefix + std::to_string(node->data) + "\r\n";
  94.  
  95.         // Process children on the same line
  96.         if (node->left || node->right) {
  97.             std::string childPrefix = std::string(prefix.length() +
  98.                 std::to_string(node->data).length() - 1, ' ');
  99.  
  100.             std::string slashLine;
  101.             if (node->left && node->right) {
  102.                 slashLine = childPrefix + "/" + std::string(3, ' ') + "\\\r\n";
  103.             }
  104.             else if (node->left) {
  105.                 slashLine = childPrefix + "/\r\n";
  106.             }
  107.             else if (node->right) {
  108.                 slashLine = childPrefix + "    \\\r\n";
  109.             }
  110.             levels.push_back(slashLine);
  111.         }
  112.  
  113.         // Calculate child prefixes
  114.         std::string leftPrefix = std::string(prefix.length() - 2, ' ') + "  ";
  115.         std::string rightPrefix = std::string(prefix.length() + 2, ' ') + "  ";
  116.  
  117.         // Process both children at the same depth
  118.         if (node->left && node->right) {
  119.             traverse(node->left, depth + 2, leftPrefix);
  120.             traverse(node->right, depth + 2, rightPrefix);
  121.         }
  122.         else {
  123.             // Process single child
  124.             if (node->left) traverse(node->left, depth + 2, leftPrefix);
  125.             if (node->right) traverse(node->right, depth + 2, rightPrefix);
  126.         }
  127.     };
  128.  
  129.     // Reduced initial padding from 40 to 20 spaces
  130.     traverse(root, 0, std::string(20, ' ')); // Reduced center padding
  131.  
  132.     std::string result;
  133.     for (const auto& level : levels) {
  134.         result += level;
  135.     }
  136.  
  137.     return result;
  138. }
  139.  
  140.  
  141. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  142.  
  143. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
  144.  
  145.     const wchar_t CLASS_NAME[] = L"BinaryTreeVisualizer";
  146.  
  147.     WNDCLASS wc = { };
  148.  
  149.     wc.lpfnWndProc = WindowProc;
  150.     wc.hInstance = hInstance;
  151.     wc.lpszClassName = CLASS_NAME;
  152.  
  153.     RegisterClass(&wc);
  154.  
  155.     HWND hwnd = CreateWindowEx(
  156.         0,                              // Optional window styles.
  157.         CLASS_NAME,                     // Window class
  158.         L"Binary Tree Visualizer",    // Window text
  159.         WS_OVERLAPPEDWINDOW,            // Window style
  160.  
  161.         CW_USEDEFAULT, CW_USEDEFAULT, 550, 400,
  162.  
  163.         NULL,       // Parent window    
  164.         NULL,       // Menu
  165.         hInstance,  // Instance handle
  166.         NULL        // Additional application data
  167.     );
  168.  
  169.     if (hwnd == NULL) {
  170.         return 0;
  171.     }
  172.  
  173.     ShowWindow(hwnd, nCmdShow);
  174.  
  175.     // Run the message loop.
  176.     MSG msg = { };
  177.     while (GetMessage(&msg, NULL, 0, 0)) {
  178.         TranslateMessage(&msg);
  179.         DispatchMessage(&msg);
  180.     }
  181.  
  182.     return 0;
  183. }
  184.  
  185. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  186.     static HWND hEdit, hDisplay, hTreeViewRadio, hListViewRadio, hGenerateButton;
  187.     static Node* root = nullptr;
  188.  
  189.     switch (uMsg) {
  190.     case WM_CREATE: {
  191.         // Create Input Field
  192.         hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
  193.             WS_CHILD | WS_VISIBLE | WS_BORDER,
  194.             10, 10, 100, 20, hwnd, NULL, NULL, NULL);
  195.  
  196.         // Create multiline Edit control for display
  197.             // Create display Edit control with proper styles for newlines
  198.         hDisplay = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
  199.             WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
  200.             ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | ES_LEFT,
  201.             10, 40, 510, 300, hwnd, NULL, NULL, NULL);
  202.  
  203.         // Radio Buttons
  204.         hTreeViewRadio = CreateWindowEx(0, L"BUTTON", L"Tree View",
  205.             WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,
  206.             120, 10, 100, 20, hwnd, (HMENU)1, NULL, NULL);
  207.  
  208.         hListViewRadio = CreateWindowEx(0, L"BUTTON", L"List View",
  209.             WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
  210.             230, 10, 100, 20, hwnd, (HMENU)2, NULL, NULL);
  211.  
  212.         // Generate Button
  213.         hGenerateButton = CreateWindowEx(0, L"BUTTON", L"Generate Tree",
  214.             WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
  215.             340, 10, 100, 20, hwnd, (HMENU)3, NULL, NULL);
  216.  
  217.         Button_SetCheck(hTreeViewRadio, BST_CHECKED);
  218.  
  219.         // Set monospace font
  220.             // Set monospace font for better tree display
  221.         HFONT hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
  222.             DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  223.             DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Consolas");
  224.  
  225.         SendMessage(hDisplay, WM_SETFONT, (WPARAM)hFont, TRUE);
  226.  
  227.         // Set tab stops for the display Edit control (optional)
  228.         DWORD tabStops = 16; // in dialog units
  229.         SendMessage(hDisplay, EM_SETTABSTOPS, 1, (LPARAM)&tabStops);
  230.  
  231.         // Set text alignment to center
  232.         //SendMessage(hDisplay, EM_SETALIGNMENT, ES_CENTER, 0);
  233.  
  234.         break;
  235.     }
  236.  
  237.     case WM_COMMAND:
  238.         if (LOWORD(wParam) == 3) { // Generate button clicked
  239.             wchar_t buffer[256];
  240.             GetWindowText(hEdit, buffer, 256);
  241.  
  242.             try {
  243.                 int numNodes = std::stoi(std::wstring(buffer));
  244.  
  245.                 if (numNodes > 0 && numNodes <= 100) {
  246.                     // Clear existing tree
  247.                     delete root;
  248.                     root = nullptr;
  249.  
  250.                     // Generate new tree with better distribution of numbers
  251.                     srand(static_cast<unsigned>(time(nullptr)));
  252.                     std::vector<int> numbers;
  253.                     for (int i = 0; i < numNodes; i++) {
  254.                         numbers.push_back(i * (100 / numNodes) + rand() % (100 / numNodes + 1));
  255.                     }
  256.                     // Shuffle the numbers for more randomness
  257.                     std::random_shuffle(numbers.begin(), numbers.end());
  258.  
  259.                     // Insert numbers into tree
  260.                     for (int num : numbers) {
  261.                         root = insert(root, num);
  262.                     }
  263.  
  264.                     // Get tree representation
  265.                     std::string treeString;
  266.                     if (Button_GetCheck(hTreeViewRadio) == BST_CHECKED) {
  267.                         treeString = getTreeString(root);
  268.                         // Ensure proper line endings
  269.                         // With this:
  270.                         size_t pos = 0;
  271.                         while ((pos = treeString.find('\n', pos)) != std::string::npos) {
  272.                             if (pos == 0 || treeString[pos - 1] != '\r') {
  273.                                 treeString.replace(pos, 1, "\r\n");
  274.                             }
  275.                             pos += 2;
  276.                         }
  277.                     }
  278.                     else {
  279.                         treeString = getListString(root);
  280.                     }
  281.  
  282.                     // Convert string to wide string for Windows
  283.                     int size_needed = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(),
  284.                         (int)treeString.size(), NULL, 0);
  285.                     std::wstring wideStr(size_needed, 0);
  286.                     MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), (int)treeString.size(),
  287.                         &wideStr[0], size_needed);
  288.  
  289.                     // Set the text in the display control
  290.                     SetWindowText(hDisplay, wideStr.c_str());
  291.  
  292.                     // Force proper display of newlines
  293.                     LONG_PTR style = GetWindowLongPtr(hDisplay, GWL_STYLE);
  294.                     style |= ES_MULTILINE | ES_AUTOVSCROLL;
  295.                     SetWindowLongPtr(hDisplay, GWL_STYLE, style);
  296.  
  297.                     // Scroll to top and refresh
  298.                     SendMessage(hDisplay, WM_VSCROLL, SB_TOP, 0);
  299.                     SendMessage(hDisplay, EM_SETSEL, 0, 0);
  300.                     SendMessage(hDisplay, EM_SCROLLCARET, 0, 0);
  301.                 }
  302.                 else {
  303.                     MessageBox(hwnd, L"Please enter a number between 1 and 100.",
  304.                         L"Invalid Input", MB_OK | MB_ICONWARNING);
  305.                 }
  306.             }
  307.             catch (const std::exception&) {
  308.                 MessageBox(hwnd, L"Please enter a valid number.",
  309.                     L"Invalid Input", MB_OK | MB_ICONWARNING);
  310.             }
  311.         }
  312.         else if (LOWORD(wParam) == 1 || LOWORD(wParam) == 2) {
  313.             // Refresh display when view type changes
  314.             if (root != nullptr) {
  315.                 std::string treeString;
  316.                 if (Button_GetCheck(hTreeViewRadio) == BST_CHECKED) {
  317.                     treeString = getTreeString(root);
  318.                     // Ensure proper line endings
  319.                     // With this:
  320.                     size_t pos = 0;
  321.                     while ((pos = treeString.find('\n', pos)) != std::string::npos) {
  322.                         if (pos == 0 || treeString[pos - 1] != '\r') {
  323.                             treeString.replace(pos, 1, "\r\n");
  324.                         }
  325.                         pos += 2;
  326.                     }
  327.                 }
  328.                 else {
  329.                     treeString = getListString(root);
  330.                 }
  331.  
  332.                 // Convert string to wide string
  333.                 int size_needed = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(),
  334.                     (int)treeString.size(), NULL, 0);
  335.                 std::wstring wideStr(size_needed, 0);
  336.                 MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), (int)treeString.size(),
  337.                     &wideStr[0], size_needed);
  338.  
  339.                 SetWindowText(hDisplay, wideStr.c_str());
  340.  
  341.                 // Force proper display of newlines
  342.                 LONG_PTR style = GetWindowLongPtr(hDisplay, GWL_STYLE);
  343.                 style |= ES_MULTILINE | ES_AUTOVSCROLL;
  344.                 SetWindowLongPtr(hDisplay, GWL_STYLE, style);
  345.  
  346.                 // Scroll to top and refresh
  347.                 SendMessage(hDisplay, WM_VSCROLL, SB_TOP, 0);
  348.                 SendMessage(hDisplay, EM_SETSEL, 0, 0);
  349.                 SendMessage(hDisplay, EM_SCROLLCARET, 0, 0);
  350.             }
  351.         }
  352.         break;
  353.  
  354.     case WM_DESTROY:
  355.         delete root; // Clean up
  356.         PostQuitMessage(0);
  357.         return 0;
  358.     }
  359.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  360. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement