C++ Builder 6 + delete

0

Witam, jestem nowy w Builderze. Chciałem stworzyć po raz pierwszy program, który będzie wykorzystywał dynamiczne alokowanie pamięci.

 
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "okno.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent *Owner)
    : TForm(Owner)
{
    enableMenu();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::enableMenu()
{
    startButton = new TButton(this);
    startButton->Parent = this;
    startButton->OnClick = disableMenu;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::disableMenu(TObject *sender)
{
    delete startButton;
}
//--------------------------------------------

Kompilować się kompiluje, ale gdy naciskam guzik startButton, to wyskakuje mi MsgBox z napisem:
Project xxx raised exception class EAccessViolation with message 'Access violation at address xxx in module 'rtl60.bpl'. Read of address xxx'. Process stopped. Use Step or Run to continue.

Gdy kliknę OK na tym MsgBoxie, wejdę w zakładkę Run>Run, to wyskakuje jeszcze jeden MsgBox:
Access violation at address xxx in module 'rtl60.bpl'. Read of address xxx.

Po czym program dalej kontynuuje swoje wykonywanie. Irytujące są te błędy. Jak się ich pozbyć?

0

Nie możesz usunąć przycisku w odpowiedź na jego kliknięcie.
Schowaj go poprzez Visible=false; zaś usuń później, np w timerze.

0

Dzięki za pomoc. Faktycznie działa, lecz napotkałem pewien problem, który wyrzuca podobne błędy.
Mianowicie, gdy próbuję dynamiczne stworzyć obiekt klasy TForm1, czyli po prostu drugie okno programu, to faktycznie działa, lecz gdy próbuje je dynamiczne usunąć, to już nie jest tak kolorowo i raz zamykanie formularza przechodzi sprawnie i normalnie, a raz wyskakują takie oto błędy (oczywiście MsgBox):

Project xxx raised exception EAccessViolation with message 'Access violation at address xxx in module 'rtl60.bpl'. Read of address xxx'. Process stopped. Use Step or Run to contiune.

Jak i oczywiście drugi MsgBox (po Run>Run):

Access violation at address xxx in module 'rtl60.bpl'. Read of address xxx.

Plik .cpp:

 
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    tworzOkno = new TButton(Form1);
    tworzOkno->Parent = Form1;
    tworzOkno->OnClick = tworzOknoMetoda;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::tworzOknoMetoda(TObject *Sender)
{
    okno2 = new TForm1(Form1);
    zamknijOkno2 = new TButton(okno2);
    zamknijOkno2->Parent = okno2;
    zamknijOkno2->Caption = "Zamykaj!";
    zamknijOkno2->OnClick = zamknijOknoMetoda;
    okno2->Show();
}

void __fastcall TForm1::zamknijOknoMetoda(TObject *Sender)
{
    okno2->OnClose = destruktorOkna;
    okno2->Close();
    delete okno2;
}

void __fastcall TForm1::destruktorOkna(TObject *Sender, TCloseAction &Akcja)
{
    delete zamknijOkno2;
}

Plik .h:

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
private:	// User declarations
    void __fastcall tworzOknoMetoda(TObject *Sender);
    void __fastcall zamknijOknoMetoda(TObject *Sender);
    void __fastcall destruktorOkna(TObject *Sender, TCloseAction &Akcja);
    TForm1 *okno2;
    TButton *tworzOkno;
    TButton *zamknijOkno2;
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
0
void __fastcall TForm1::tworzOknoMetoda(TObject *Sender)
{
    TForm1 *okno2 = new TForm1(Application);
    TButton *zamknijOkno2 = new TButton(okno2);
    zamknijOkno2->Parent = okno2;
    zamknijOkno2->Caption = "Zamykaj!";
    zamknijOkno2->OnClick = zamknijOknoMetoda;
    okno2->Show();
}
 
void __fastcall TForm1::zamknijOknoMetoda(TObject *Sender)
{
    TButton *btn=(TButton*)Sender;
    ((TForm*)(btn->Parent))->Close(); // delete samo się zrobi
}
0

Czy ja mogę prosić o łopatologiczne wytłumaczenie tej linijki, bo nie rozumiem:

((TForm*)Parent)->Close(); // delete samo się zrobi

W sensie, że nie rozumiem tego zapisu jak i tego, czemu i czym jest to cale ((TForm*)Parent).

Przepraszam, że o tyle proszę, staram się dociec do źródła błędu, żeby lepiej to zrozumieć i na przyszłość nie mieć problemów. Chciałbym wiedzieć dlaczego tak, a nie tak i już.

0

Może przeanalizuj to:

unit1.dfm

object Form1: TForm1
  Left = 621
  Top = 259
  Width = 178
  Height = 141
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  Position = poDefaultPosOnly
  OnClose = FormClose
  PixelsPerInch = 96
  TextHeight = 13
  object BtnCreate: TButton
    Left = 8
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Create'
    Default = True
    TabOrder = 0
    OnClick = BtnCreateClick
  end
  object BtnClose: TButton
    Left = 88
    Top = 8
    Width = 75
    Height = 25
    Cancel = True
    Caption = 'Close'
    TabOrder = 1
    OnClick = BtnCloseClick
  end
end

unit1.pas

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BtnCloseClick(TObject *Sender)
{
   Close();   
}
//---------------------------------------------------------------------------

void __fastcall TForm1::BtnCreateClick(TObject *Sender)
{
   (new TForm1(Application))->Show();
}
//---------------------------------------------------------------------------


void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
   Action=caFree;
}
//---------------------------------------------------------------------------
0

Dziękuję za kompleksowe wytłumaczenie, ale mam (chyba) ostatnie pytanie, czy dobrze rozumuję?

TButton btn=(TButton)Sender;
Tworzysz wskaźnik na obiekt klasy TButton, po czym przypisujesz komórce w pamięci, na która wskazuje ten wskaźnik, zrzutowaną na klase TButton wartość Sender (jeśli mógłbyś wytłumaczyć czym to Sender jest, nie mogę tego nigdzie znaleźć, a jeśli już znajduję, to w j. angielskim).

((TForm*)(btn->Parent))->Close();
Dla rodzica obiektu btn (wpierw rzutujesz ten obiekt na klasę TForm) wywołujesz metodę Close.

Pytanie drugie, ten wskaźnik był ci potrzebny tylko do tego, żeby wiedzieć które okno masz zamknąć? (jak się domyślam, w momencie przypisania mu (wskaźnikowi) wartości Sender zawiera on to, na rzecz czego został stworzony?)

Wybacz, że się tak dopytuję, ale chyba mój aktualny stan wiedzy nie jest adekwatny do tego, co piszesz.

0

Do Sender jest podstawiony obiekt który spowodował to zdarzenie.
Podpiąłeś zamknijOkno2->OnClick = zamknijOknoMetoda; więc po naciśnięciu zamknijOkno2 odpali się zamknijOknoMetoda z Sender=zamknijOkno2

1 użytkowników online, w tym zalogowanych: 0, gości: 1