To warm up in c ++, I write a small OOP add-on over WinApi so that you can create windows and carry out the necessary basic manipulations (such as changing text, sizes, setting events on controls, etc.) with a couple of lines of code. It was planned that its use would be something like this:
WqWindow::WqBegin(); WqWindow w; WqButton b(&w); WqTextBox tb(&w); tb.SetPosition(WqPosition(50, 10)) ->SetSize(WqSize(200, 25)) ->SetText(""); b.SetText("Cool button") ->SetSize(WqSize(150, 25)) ->SetPosition(WqPosition(50, 50)) ->SetAcnhor(WqControlAnchor(false, false, true, false)) ->SetOnClick([&b, &tb, &w]() { cout << "Clicked!" << endl; }); w.SetTitle("Cool window") ->SetSize(WqSize(400, 400)) ->ClosesProgram(false) ->SetOnClose([]() { cout << "Closed!" << endl; return true; }) ->Show(); WqWindow::WqEnd(); The principle is approximately the same: when creating a control, a pointer to it is added to the vector of window object elements (WqWindow) and when removed, in the destructor, this element is removed from the vector. Something like this
//Убираем из списка элементов управления окна this->window_->controls_.erase(std::remove(this->window_->controls_.begin(), this->window_->controls_.end(), this), this->window_->controls_.end()); The events of the buttons and other elements are handled in the window procedure. The principle is the following: we get the handle of the window that caused the event (HWND), using the user pointer (which was assigned when creating the WqWindow window), we get the associated WqWindow object and refer to the control vector. We pass through them in a loop, and call the lambda functions of these elements. It looks like this:
case WM_COMMAND: if (wqWindow && !wqWindow->controls_.empty()) { const std::vector<WqControl*> safeControlPointers(wqWindow->controls_); for (WqControl * control : safeControlPointers) { if (control->initialized_) { if (HIWORD(wParam) == EN_CHANGE) { if (control && control->ControlClassName() == "Edit" && control->GetHWND() == (HWND)(lParam)) { WqTextBox * pTextBox = ((WqTextBox*)control); if (pTextBox->onChanged_) { pTextBox->onChanged_(); } } } else { if (control->ControlClassName() == "Button" && control->GetHWND() == (HWND)(lParam)) { WqButton * pButton = ((WqButton*)control); if (pButton->onClick_) { pButton->onClick_(); } } } } } } break; And then I thought - what if the user of this library wants to delete (by calling the destructor) some control in the lamba expression, for example like this:
->SetOnClick([&b, &tb, &w]() { tb.~WqTextBox(); }); In this case, I just added the safeControlPointers variable, so that when we walk through the vector, we work as if with a copy of the vector, and not with that vector, the size of which will change. It was supposed to be all right, but still there was an error during execution (when pressing the button). The fact is that in the copy of the vector there was a pointer to the object which, as it were, was deleted. I DON'T KNOW HOW, but the following helped me - I declared the control-> initialized_ flag in WqControl, which in the constructor became true and the destructor was set to flase. In the loop, you probably noticed a check.
if (control->initialized_) Due to this, the program did not break when you click on the button. I did not fully understand why (after all, an object is destroyed, deleted from memory, and therefore access to any of its members is impossible). I would be glad if you explain how this is possible. Well, I did not stop there, and decided to try to create a TextBox (which I then decided to delete when clicked) not on the stack but on the heap (that is, using the new operator) and then call delete when clicked. Here everything finally broke. And no checks help (for pointer emptiness and others).
Question : How to implement a similar mechanism so that when you click there is the ability to delete other elements? How to properly approach this? Thanks in advance.
DestroyWindowcall when you destroy an object? - LLENNEnumChildWindows. - VTT