Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C++ Builder > Динамическое создание и разрушение формы


Автор: Kirgston 7.1.2010, 20:59
Всем доброго времени суток. Вот собственно что то до конца не понимаю... создаю форму так:
Application->CreateForm(__classid(TForm2), &Form2);
Когда моя форма отработала (ту какую я динамически создал) я делаю Form2->Free(); в итоге получаю ошибку Аксесс Виолейшен и форма не очищается из памяти а дальше там висит (ну если я правильно понял). Как правильно "удалять" форму?

Под словами динамическое создание имел ввиду то что форму создаю не при старте программы а в нужный мне момент. Спасибо!

Автор: pdbq 7.1.2010, 21:08
возможно я не прав но попробуйте так:
Код

Form = new TForm(this);
Form->ShowModal();
Form->~TForm();

Автор: 586 7.1.2010, 21:32
Цитата(pdbq @  7.1.2010,  21:08 Найти цитируемый пост)
Form->~TForm();

нужно уничтожить объект, а не просто вызвать деструктор
Код
Form = new TForm(this);
Form->ShowModal();
delete Form;

Автор: vikaz 7.1.2010, 21:36
Цитата(Kirgston @  7.1.2010,  22:59 Найти цитируемый пост)
Application->CreateForm(__classid(TForm2), &Form2);

а в чем фишка создания формы таким образом? Почему не:
Код

TForm2 * Form2 = new TForm2 (this);

Автор: Kirgston 8.1.2010, 08:58
Цитата(vikaz @  7.1.2010,  21:36 Найти цитируемый пост)
а в чем фишка создания формы таким образом? Почему не:

Ну так делает Билдер. Я так же пробовал. Кстати....
Попробовал так:
Код

TForm2 * Form2 = new TForm2 (this);

В результате на строчке:
Код

Label2->Left=Form2->Width/2 - Label2->Width/2;

Вылетает Access Violation.

Автор: vikaz 8.1.2010, 09:59
Цитата(Kirgston @  8.1.2010,  10:58 Найти цитируемый пост)
Вылетает Access Violation.

Так и будет! Так как данная строчка не создает глобальный указатель Form2. Я выходил из этого, передавая нужные мне указатели.

Добавлено через 47 секунд
или просто переписать вот так:
Код

Label2->Left=Width/2 - Label2->Width/2;

Автор: Kirgston 8.1.2010, 13:12
Хмм... кстати вот вопросик про ту же динамическую форму... вот когда я делаю ShowModal() и открываю модально нужную мне форму. В делфях чтобы выйти из модальной формы я писал Close; Форма сразу закрывалась и управление переходило на строчку ниже после вызова модальной формы. Здесь же не так... да ладно поставил return; но чувствую что это как то нелепо...

Автор: SVN74 8.1.2010, 13:39
Проверьте правильность включений #include - видят ли все друг друга.
Создавать форму можно - Application->CreateForm(__classid(TForm2), &Form2);
В обработчике Form2 (OnClose)  напишите Action = caFree; - (Но после этого уже Form2 не будет доступна, поэтому необходимо будет заново создавать форму).
Закрывать форму можно Form2->Close();
-------------------------------------------------------
Подумайте, нужно ли вам все время очищать память, если Form2 будет вам нужна несколько раз?
Указатель на Form2 - обязательно должен быть виден всей главной форме.

Автор: 586 8.1.2010, 14:31
Цитата(Kirgston @  8.1.2010,  13:12 Найти цитируемый пост)
вот когда я делаю ShowModal() и открываю модально нужную мне форму. В делфях чтобы выйти из модальной формы я писал Close; Форма сразу закрывалась и управление переходило на строчку ниже после вызова модальной формы

Чтобы закрыть модальный диалог, измени свойство ModalResult:
Код
void __fastcall TForm2::Button1Click(TObject *Sender)
{
    ModalResult = mrOk;
}

ShowModal() возвратит значение mrOk.

Автор: Kirgston 9.1.2010, 10:34
Цитата(586 @  8.1.2010,  14:31 Найти цитируемый пост)
ShowModal() возвратит значение mrOk.

Странно чуток... 
static const ShortInt mrOk = 0x1;
я делал модал резалт не mrOk , а просто 1 (забыл просто про mrOk). В итоге управление не передавалось в место откуда была вызвана модальная форма (конечно вызвана была из другой формы). А кода дальше исполнялся. Может я просто забыл мат часть и всё так и должно быть... а может и очередной баг Билдера 2010  smile 


Цитата(SVN74 @  8.1.2010,  13:39 Найти цитируемый пост)
Создавать форму можно - Application->CreateForm(__classid(TForm2), &Form2);В обработчике Form2 (OnClose)  напишите Action = caFree; - (Но после этого уже Form2 не будет доступна, поэтому необходимо будет заново создавать форму).Закрывать форму можно Form2->Close();

Охххх благодарю!!! Совсем забыл о caFree  smile 


Цитата(SVN74 @  8.1.2010,  13:39 Найти цитируемый пост)
Подумайте, нужно ли вам все время очищать память, если Form2 будет вам нужна несколько раз?

Хм... не знаю сколько раз нужна... но думаю нормальный пользователь запустит её ну 1, ну 2 раза и всё =). К тому же на формочке не мало компонентов. Это что то типа авто обновления. Тот же Indy TCP Client, полосочки всякие, списки и т.д. И в принципе оно не мало жрет оперативки... если скажем там 4 списочка ( ListBox ) и в каждом по 9к записей))))) (меня не бить, сделал я нормально. Бить разрабов игры для какой я делаю авто обновление  smile ). То есть это где то под 1-2 мб оперативки. На скорость я не думаю что будет сильно влиять (спешить то некуда). 

Автор: Kirgston 10.1.2010, 15:45
Опять не пойму... сделал вот так:
Код

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

#include <vcl.h>
#include <iostream.h>
#include "md5.h"
#include "md5wrapper.h"
#pragma hdrstop
#pragma comment(lib,"Wininet.lib");

#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "IdBaseComponent"
#pragma link "IdComponent"
#pragma link "IdTCPClient"
#pragma link "IdTCPConnection"
#pragma link "IdAntiFreeze"
#pragma link "IdAntiFreezeBase"
#pragma resource "*.dfm"
TForm2 *Form2;
md5wrapper MD5;
/*TStringList *files=new TStringList;
TStringList *hash=new TStringList;
TStringList *urls=new TStringList;

TStringList *cfiles=new TStringList;
TStringList *chash=new TStringList;  */
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void TForm2::GetUpdateList()
{
    try {
        TC->Connect();
        if (TC->Connected()) {

            int count=0;
            count=TC->IOHandler->ReadInt64();
            TC->IOHandler->ReadStrings(files,count);
            ListBox1->Items=files;

            count=TC->IOHandler->ReadInt64();
            TC->IOHandler->ReadStrings(hash,count);
            ListBox2->Items=hash;

            count=TC->IOHandler->ReadInt64();
            TC->IOHandler->ReadStrings(urls,count);
            ListBox3->Items=urls;

            count=TC->IOHandler->ReadInt64();
            TC->IOHandler->ReadStrings(size,count);
            ListBox4->Items=size;

        }
    } catch (...) {
        Application->MessageBoxA(L"Невозможно соеденится с сервером обновлений!",L"Auto Updater",MB_OK);
        Form2->Close();
        terminate=true;
        Application->ProcessMessages();

    }

}
//---------------------------------------------------------------------------

void TForm2::Search(UnicodeString dir)
{
    bool updated=false;
    ProgressBar1->Position=0;
    ProgressBar1->Max=ListBox1->Count;
    for (int i=0; i < ListBox1->Count; i++) {
        Application->ProcessMessages();
        UnicodeString Name=dir;
        Name+=ListBox1->Items->Strings[i];
        Label2->Caption=L"Текущий файл: "+IntToStr(i)+L" \\ Всего файлов: "+IntToStr(ListBox1->Count);
        Label2->Left=Form2->Width/2 - Label2->Width/2;
        Label3->Caption=Name;
        Label3->Left=Form2->Width/2 - Label3->Width/2;
        if (FileExists(Name)) {
            string Md5=MD5.getHashFromFile(Name.t_str());
            UnicodeString str=Md5.c_str();
            if (str!=ListBox2->Items->Strings[i]) {
                DeleteFile(Name);
                if (!Download(ListBox3->Items->Strings[i],Name,i))
                {
                    UnicodeString tmp=L"Невозможно скачать файл " + ListBox3->Items->Strings[i];
                    Application->MessageBoxA(tmp.w_str(),L"Auto Updater",MB_OK);
                    updated=false;
                }
                else
                    updated=true;
            }
        }
        else
        {
            Download(ListBox3->Items->Strings[i],Name,i);
            updated=true;
        }
        ProgressBar1->Position++;
        Application->ProcessMessages();
    }
    ProgressBar1->Visible=false;
    Label2->Visible=false;
    Label3->Visible=false;
    if (updated) {
        Application->MessageBoxA(L"Обновления успешно установлены!",L"Auto Updater",MB_OK);
    }
    else
     Application->MessageBoxA(L"Ваш игровой клиент не нуждается в обновлениях.",L"Auto Updater",MB_OK);

    Form2->Close();

    //Form2->~TForm2();
    //URLDownloadToFile
}
//---------------------------------------------------------------------------
bool TForm2::Download(AnsiString url,AnsiString dest,int i)
{
    ProgressBar2->Position=0;
    ProgressBar2->Max=StrToInt(ListBox4->Items->Strings[i]);
    char buf[256];
    AnsiString str=dest,agent=0;

    int np;
    bool err;
    err=false;

    HINTERNET session,file;          //PRE_CONFIG_INTERNET_ACCESS INTERNET_OPEN_TYPE_PRECONFIG
    session = InternetOpen(agent.c_str(), PRE_CONFIG_INTERNET_ACCESS, 0, 0, 0);

    file    = InternetOpenUrl(session,url.c_str(), 0, 0, 0, 0);

    DWORD    Code = 0,
    Size = sizeof( Code );
    if (file==NULL)
        err=true;
    else
    if (HttpQueryInfo( file, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, ( LPVOID ) &Code, ( LPDWORD  ) &Size, NULL  ) )
        if (Code!=200)
            err=true;
        else
        {
            unsigned long len=0,offs=0;
            AnsiString buff="";

            if (file!=NULL)
            {
                DWORD Written;
                HANDLE hDestFile = CreateFile(str.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

                if (hDestFile == INVALID_HANDLE_VALUE)
                    err=true;
                else

                do
                {
                    Application->ProcessMessages();
                    InternetReadFile(file, buf, sizeof(buf), &len);
                    if (len>=0)
                    {
                        offs += len;
                        buff=buf;
                        WriteFile(hDestFile, buf, len, &Written, NULL);
                        ProgressBar2->Position+=len;
                        Application->ProcessMessages();
                    }

                    else
                    {
                        int error = GetLastError();
                        err=true;
                        InternetCloseHandle(file);
                        InternetCloseHandle(session);
                        Application->ProcessMessages();
                        ::Sleep(1000);
                        Application->ProcessMessages();
                        session = InternetOpen("Our Agent", PRE_CONFIG_INTERNET_ACCESS, 0, 0, 0);
                        file = InternetOpenUrl(session, url.c_str(), 0, 0, 0, 0);
                        InternetSetFilePointer(file, offs, 0, FILE_BEGIN, 0);
                    }

                } while (len);

                CloseHandle(hDestFile);

             }

            InternetCloseHandle(file);
            InternetCloseHandle(session);


            if (!err)
                return true;
            else
                return false;
        }
}
//---------------------------------------------------------------------------

void __fastcall TForm2::FormDestroy(TObject *Sender)
{
    delete files;
    delete hash;
    delete urls;
    delete size;

    delete cfiles;
    delete chash;
}
//---------------------------------------------------------------------------


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

void __fastcall TForm2::FormCreate(TObject *Sender)
{
    files=new TStringList;
    hash=new TStringList;
    urls=new TStringList;
    size=new TStringList;

    cfiles=new TStringList;
    chash=new TStringList;


}
//---------------------------------------------------------------------------

void __fastcall TForm2::Timer1Timer(TObject *Sender)
{
    Timer1->Enabled=false;

    GetUpdateList();

    if (terminate) {
        return;    
    }
    files->Clear();
    hash->Clear();
    urls->Clear();
    size->Clear();

    cfiles->Clear();
    chash->Clear();
    ProgressBar1->Visible=true;
    Label2->Visible=true;
    Label3->Visible=true;
    Label1->Caption=L"Начата проверка игрового клиента. Пожалуйста дождитесь окончания.";
    Application->ProcessMessages();
    Search(ExtractFilePath(Application->ExeName));
}
//---------------------------------------------------------------------------


После того как происходить Форм Клоус, форм дестрой код в таймере дальше продолжает исполнятся... 

Автор: mrbrooks 11.1.2010, 09:12
Kirgston, могу посоветовать:
1. Отказаться от событий OnCreate/OnDestroy. На каком основании - смотри в хелпе или в этой ветке форума. Вопрос обсуждался. Замени соответственно на конструктор формы - где выделяешь память, тот же OnClose - для высвобождения.
2. Работу с сервером вынеси в отдельный класс.

Автор: Kirgston 11.1.2010, 10:22
Цитата(mrbrooks @  11.1.2010,  09:12 Найти цитируемый пост)
1. Отказаться от событий OnCreate/OnDestroy. На каком основании - смотри в хелпе или в этой ветке форума. Вопрос обсуждался. Замени соответственно на конструктор формы - где выделяешь память, тот же OnClose - для высвобождения.

Если не сложно скажите как приблизительно называлась тема? Перерыл 2 страницы нашел только 1 тему про форму и то не ту.

Автор: mrbrooks 11.1.2010, 10:43
Цитата(Kirgston @  11.1.2010,  10:22 Найти цитируемый пост)
Если не сложно скажите как приблизительно называлась тема?

сказать не могу, ибо не помню.  smile  по большому счету там была ссылка из хелпа камрад:

Цитата

Note:    Use of the OnCreate event is discouraged in C++Builder because it can interact badly with the form’s constructor. It is recommended that you override the form constructor instead.

Автор: Kirgston 11.1.2010, 10:45
Кстати опять таки... сделал класс. Сделал свой конструктор + деструктор. Может я просто не так понимаю как оно должно работать... но...  smile 

Идет код, выскочила ошибка. Я вызываю деструктор класса и ожидаю что класс удалится и код в вызваной из этого класса ф-ции не будет дальше исполнятся. Но видать я думаю не так как надо  smile 

Мне тогда что писать какие то переменные типа mayterminate и проверять их мол надо ли сделать сейчас return и выйти из ф-ции класса или продолжать код? А на выходе из класса уже ставить деструкторы? 

Автор: mrbrooks 11.1.2010, 10:58
Kirgston, камрад - почитай про работу деструкторов.

Автор: Kirgston 11.1.2010, 17:19
mrbrooks,  smile уже всё сделал благодарю! =)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)