Всем привет. В общем капитально запутался, и не могу правильно организовать структуру программы (или как это правильно называется?). Собственно задача: создать интерфейс как на картинке. С динамическим созданием совладал, интерфейс создается, но я не знаю как создать событие он клик, точнее знаю но есть одно но, есть небольшой такой парадокс непонятный для меня. max_el=accs_list->Count; можно узнать только после нажатия кнопки "загрузить акки", и поэтому получается что нужно создавать массивы указателей по кол-ву акков после того как StringList accs_list заполнится, но, парадокс для меня вот в чем, что бы создать кол-во элементов равное кол-ву акков, приходится объявлять массивы указателей в обработчике кнопки, и там же создаются сами элементы, но функция он клик далее в коде void __fastcall TForm1::stop_click(TObject * Sender) находится не в функции кнопки TForm1::Button1Click и если я в обработчике он клик кнопки stop вызову label_stop_command[((TButton*)Sender)->Tag]->Caption="true"; то это ошибка т.к. элемент label_stop_command[] еще не создан и соответственно нельзя к нему обратиться, компилятор ругается. можно сделать например TGroupBox **accs_thread=new TGroupBox*[100]; но если допустим будет 101 акк в текстовом файле то вывалится ошибка, да и вообще этот вариант не нравится, нужно создание элементов четко по кол-ву акков, не больше и не меньше. Сам кодер-любитель самоучка если что и в профессиональных терминах не особо разбираюсь, поэтому если можно объясните пожалуйста понятным языком и желательно на пальцах. В общем цель: динамичное создание элементов по кол-ву акков, с полноценными кнопками и обработчиками, с зараннее неизвестным кол-вом акков. Спасибо, с уважением. Code: TStringList*accs_list=new TStringList;//тут акки void __fastcall TForm1::Button1Click(TObject *Sender) { OpenTextFileAccs->Execute(); accs_list->LoadFromFile(OpenTextFileAccs->FileName); Label2->Caption="["+IntToStr(accs_list->Count)+"]"; max_el=accs_list->Count; // создаю массивы указателей по кол-ву акков, в .h файле они все прописаны extern TGroupBox **accs_thread; итд TGroupBox **accs_thread=new TGroupBox*[max_el]; TLabel **label_acc=new TLabel*[max_el]; TLabel **label_status=new TLabel*[max_el]; TLabel **work_status=new TLabel*[max_el]; TLabel **label_stop_command=new TLabel*[max_el]; TButton **stop_thread=new TButton*[max_el]; int i_el =0; //создаю визуальные элементы while (i_el<accs_list->Count) { accs_thread[i_el]=new TGroupBox(this); accs_thread[i_el]->Parent=ScrollBox1; accs_thread[i_el]->Align = alTop; accs_thread[i_el]->AlignWithMargins=true; accs_thread[i_el]->Margins->Top=3; accs_thread[i_el]->Left=20; accs_thread[i_el]->Height=65; accs_thread[i_el]->Width=660; accs_thread[i_el]->ParentColor=false; accs_thread[i_el]->ParentBackground=false; accs_thread[i_el]->Color=clSkyBlue; accs_thread[i_el]->Caption="Поток#"+IntToStr(i_el)+" "+accs_list->Strings[i_el]; /// label_acc[i_el] = new TLabel(this); label_acc[i_el]->Parent=accs_thread[i_el]; label_acc[i_el]->Caption="acc"+IntToStr(i_el); label_acc[i_el]->Left=15; label_acc[i_el]->Top=15;//top_grboxacc; label_stop_command[i_el] = new TLabel(this); label_stop_command[i_el]->Parent=accs_thread[i_el]; label_stop_command[i_el]->Caption="false"; label_stop_command[i_el]->Left=100; label_stop_command[i_el]->Top=15;//top_grboxacc; //label_stop_command[i]->Visible=false; work_status[i_el] = new TLabel(this); work_status[i_el]->Parent=accs_thread[i_el]; work_status[i_el]->Caption="ожидание"; work_status[i_el]->Left=200; work_status[i_el]->Top=15; label_status[i_el] = new TLabel(this); label_status[i_el]->Parent=accs_thread[i_el]; label_status[i_el]->Caption="Status: "; label_status[i_el]->Left=150; label_status[i_el]->Top=15; stop_thread[i_el] = new TButton(this); stop_thread[i_el]->Parent=accs_thread[i_el]; stop_thread[i_el]->Caption="stop"; stop_thread[i_el]->Left=310; stop_thread[i_el]->Height=23; stop_thread[i_el]->Width=54; stop_thread[i_el]->Top=15; stop_thread[i_el]->Tag=i_el; stop_thread[i_el]->OnClick = stop_click; //функция он клик кнопки stop i_el ++; } //правильно ли я удаляю созданные массивы указателей? delete[] accs_thread; delete[] label_acc; delete[] label_status; delete[] work_status; delete[] label_stop_command; delete[] stop_thread; } Code: void __fastcall TForm1::stop_click(TObject * Sender) { Form1->MemoLog->Lines->Add("qweqwe^_^"); Form1->MemoLog->Lines->Add( ((TButton*)Sender)->Tag); //Form1->MemoLog->Lines->Add( BoolToStr(mass_stop_thr[((TButton*)Sender)->Tag]) ); //label_stop_command[((TButton*)Sender)->Tag]->Caption="true"; }
Ох. Я конечно слегка перебрал и потому нихрена не понял. Но делается все так: 1. Ты загружаешь акки в StringList 2. Каждому акку создаешь в соответствие компонент и где-то в служебном поле прописываешь например ID этого акка (порядковый номер в string_list). UPD: но надо учесть что при удалении номера эти id сместятся поэтому желательно-бы как-то хранить их иначе чем в обычном списке. Ну или найти красивое решение можно, но это придется поморщить мозг. В тупую если - то лучше всего просто по id-шникам. 3. Размещаешь кнопочки как тебе пожелается и связываешь все их on_click с одним единственным обработчиком которому либо передаешь в качестве параметра присвоенный id - либо из этого обработчика определяешь Sender'а а у него читаешь этот id/ 4. Внутри обработчика, согласно указанному id делаешь то что требуется. UPD: уничтожение компонентов можно привязать к соответствующему свойству StringGrid'а (ты же в нем создаешь их ? ) или поднять собственное свойство... тут уже зависит от реализации. И все вроде...
Спасибо что откликнулись. Вот примерно так и делаю. Вместо id и служебного поля юзаю Tag, вот этой строчкой создаю его для каждой кнопки stop_thread[i_el]->Tag=i_el; А вот она и та самая одна функция он-клик, и вы наверное видите закомментированную строчку где я и смотрел Sender, вот только есть одна проблема которую я и назвал парадоксом, при такой архитектуре нельзя изменить в он-клике лейбл label_stop_command[((TButton*)Sender)->Tag]->Caption="true"; (тут как раз использую Tag для определения какой именно элемент нужно поменять по счёту) так как он ещё не создан, а раньше создавать массивы указателей я не могу, потому что тогда будет неизвестно кол-во акков по которому и создается нужное кол-во элементов. Code: void __fastcall TForm1::stop_click(TObject * Sender) { Form1->MemoLog->Lines->Add("qweqwe^_^"); Form1->MemoLog->Lines->Add( ((TButton*)Sender)->Tag); //просто так в Лог выводится ID нажатой кнопки //а вот эта строчка закомментирована т.к. ошибка ведь label_stop_command еще не создан. //label_stop_command[((TButton*)Sender)->Tag]->Caption="true"; } Зачем я меняю этот лейбл, что бы в потоке, можно было определить для какого потока нажата кнопка "stop", ну типа такого: Code: while (true) //допустим это какой то рабочий цикл { if (label_stop_command[thread_id]->Caption=="true") { work_status[thread_id]->Caption="остановлен"; break; } ::Sleep(1000); } Изначально для этой цели пробовал сделать глобальный массив bool, но какие то траблы с ним были именно при глобальном использовании, не зашло в общем и пришлось выдумывать вот с лейблом. Грубо говоря я и сделал как вы сказали и всё работает, интерфейс создается динамически (на скрине видно), у каждой кнопки свой Tag - номер компонента согласно номеру акка, и функция он-клик тоже создается, одна, в ней смотрю тег того кто вызвал он-клик ((TButton*)Sender)->Tag , с этим проблем нет. Проблема в том что из он-клика нельзя поменять Caption лейбла т.к. этот лейбл еще не создан, а зараннее создать их нельзя т.к. еще будет неизвестно кол-во акков. кстати прочитал в гугле что в моем случае delete[] accs_thread; будет некорректным удалением. Ну это ладно, в цикле удалю оператором delete. нет, для списка акков использую StringList, а сами визуальные компоненты это просто GroupBox'ы же просто в ScrollBox'е. как то так...
Чот я туплю. Нехрена не понять как это не создан если ты создаешь лейбл вместе с кнопкой stop. Если создана кнопка - значит есть и лейбл с таким же id. Можно проверять указатель на null еще на всякий случай для хорошего тона. Вообще с тредами так не очень правильно работать. Обычно для этого юзаются мьютексы/семафоры, но в принципе обычный булев массив как ты делал - это норм, но тоже с мьютексом чтобы разные треды одновременно не могли писать и читать оттуда ибо будет жопа. Тут есть вроде ман.
Дело в том что все элементы создаются в функции это кнопка "LoadAccs" void __fastcall TForm1::Button1Click(TObject *Sender) { } И получается что пока эта функция не была вызвана, элементов нету, и нету того лейбла. А заранее создать массив указателей я не могу, т.к. еще неизвестно кол-во акков. Палка о двух концах короче. Не знаю с какой стороны подойти. Изначально я делал отдельную функцию CreateElements на юните формы, и при старте потоков вызывал ее из потока, но так не подходит, потому что по замыслу нужно сначала загрузить акки и создать для каждого акка еще интерфейсы управления, для каждого акка будут задаваться разные настройки, еще до их запуска. Для синхронизации, в потоках юзаю CriticalSection, это я для примера привел максимально простой код, что бы понятно было зачем в данном случае мне менять Label, но суть моей проблемы не в этом. Спасибо. __________________________________________________________________________ UPD: гуглением на тему динамических массивов наткнулся на векторы. Но пока не пойму как их можно использовать.