Удаление динамически созданного элемента управления borland 6 c++ builder

У меня проблема с удалением динамически созданной кнопки в Borland C++Builder 6.

__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner) {
  TButton *but = new TButton(this);
  but->Left = 100;
  but->Top = 100;
  but->OnClick = click;
  Form1->InsertControl(but);
}

void __fastcall TForm1::click(TObject *Sender) {
    delete Sender;
}

Когда я нажимаю на созданную кнопку, появляется ошибка «Нарушение прав доступа по адресу 40005905 в модуле rtl60.bpl, чтение адреса 00000018».

Я знаю, что неправильно назначать метод для кнопки, которая удаляет ее, но мне действительно нужно удалить кнопку, нажав на нее.


person Ilya Marchenko    schedule 23.12.2015    source источник


Ответы (1)


В вашем коде две ошибки.

  1. глобальная переменная Form1 еще не была назначена при вызове конструктора TForm1, поэтому ваш оператор Form1->InsertControl(but) недействителен и может привести к сбою. Используйте this-> вместо Form1->. Однако вы не должны вызывать InsertControl() напрямую, вместо этого установите свойство кнопки Parent:

    but->Parent = this;
    
  2. Небезопасно delete Sender события во время работы обработчика событий. RTL по-прежнему требуется доступ к объекту после выхода обработчика (о чем свидетельствует ваша ошибка AccessViolation). Вам придется отложить delete, например, с помощью короткого таймера:

    void __fastcall TForm1::DeleteButtonTimerElapsed(TObject *Sender)
    {
        TObject *obj = reinterpret_cast<TObject*>(DeleteButtonTimer->Tag);
        DeleteButtonTimer->Tag = 0;
        DeleteButtonTimer->Enabled = false;
        delete obj;
    }
    
    void __fastcall TForm1::click(TObject *Sender)
    {
        DeleteButtonTimer->Tag = reinterpret_cast<int>(Sender);
        DeleteButtonTimer->Enabled = true;
    }
    

    Или отправьте личное сообщение самому себе, используя PostMessage() (я предпочитаю такой подход):

    #define WM_DELETE_OBJECT (WM_USER + 1)
    
    void __fastcall TForm1::WndProc(TMessage &Message)
    {
        if (Message.Msg == WM_DELETE_OBJECT)
            delete reinterpret_cast<TObject*>(Message.LParam);
        else
            TForm::WndProc(Message);
    }
    
    void __fastcall TForm1::click(TObject *Sender)
    {
        TButton *btn = static_cast<TButton*>(Sender);
        btn->OnClick = NULL;
        PostMessage(Handle, WM_DELETE_OBJECT, 0, reinterpret_cast<LPARAM>(Sender));
    }
    
person Remy Lebeau    schedule 23.12.2015