Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Form2->ShowModal() - форма теряет фокус

490
17 марта 2008 года
frid-karatel
357 / / 15.09.2007
Почему-то неправильно отображается модальная форма.

Что делаю:
1. Запускаю другую программу через CreateProcess(...)
2. Скрываю все формы запускаемого приложения через ShowWindow(hWnd, SW_HIDE)
3. Показываю модально Form2->ShowModal();
4. После показа формы в обработчике OnShow(...) я выполняю определенные действия вплоть то инициализации потока и ожидания работы с ним. Фактически, Form2 отображает ProgressBar операции, которую пользователь может отменить. Чтобы запретить доступ к Form1, пока не закончится обработка функции, я создал Form2->ShowModal(...)

Если просто выполнять какой-нибудь цикл после создания формы, то Form2 отображается правильно. А вот если запускать приложение, то, как я понял, она теряет фокус и что-то неправильно обрабатывает - Form2 cкрывается за Form1. Приходится кликать на Form1, чтобы показалась Form2...

Пробовал... SetFocus(), и даже SendToBack(...), а потом BringToFront(...) ... И Form2->Visible = true делал

Все без толку... вот пока на главную форму не кликнешь - не покажется модальная Form2...

Код:
void __fastcallTForm1::ShowModalForm()
{
  if (HideForm)
  {
    Form2->Position = poDesigned;
    Form2->Left = -111;
    Form2->Top = -111;
  } else
  {
    Form2->Position = poMainFormCenter;  
  }
  Form2->ShowModal();
}
//----------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TButton* btn = (TButton*)Sender;
  if (btn->Name == "btnShowModal") ShowModalForm();
  <...>
}


PS: и Form1, и Form2 у меня не имеют бордюра (заголовка, сист. кнопок и т.п. вещей)
11
17 марта 2008 года
oxotnik333
2.9K / / 03.08.2007
в ShowWindow(hWnd, SW_HIDE) hWnd случайно не равер HWND модальной формы или TApplication::Handle ?
1
17 марта 2008 года
kot_
7.3K / / 20.01.2000
 
Код:
SetWindowPos(Form2->Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
490
17 марта 2008 года
frid-karatel
357 / / 15.09.2007
Цитата: kot_
 
Код:
SetWindowPos(Form2->Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);



Не получается...

Как я понял, суть проблемы в том, что я запускаю из своей проги (скажем, MyProg) другую прогу (назовем, OtherProg) через CreateProcess(...), затем я через перечисление EnumWIndow(...) скрываю все окна OtherProg, используя ShowWindow(... SW_HIDE).

В итоге получается, что сначала фокус стоит на MyProg, затем при запуске он переходит в OtherProg, а так как я скрываю все окна OtherProg, то фокус не стоит ни на одном окне (приложении)... И моя Form2, показанная ShowModal() не видна, т.е. скрыта за основным окном, т.е. за формой Form1. Только после клика на главном окне (Form1) появляется Form2...

490
17 марта 2008 года
frid-karatel
357 / / 15.09.2007
Цитата: oxotnik333
в ShowWindow(hWnd, SW_HIDE) hWnd случайно не равер HWND модальной формы или TApplication::Handle ?



Нет,

Код:
<...>
  if (CreateProcess(NULL, RUNAPPNAME, 0, 0, FALSE, 0, 0, 0, &si, &pi))
  {
    DWORD res = WaitForInputIdle(pi.hProcess, 3000);
    if (res == WAIT_TIMEOUT)
    {
      TerminateProcess(pi.hProcess, 0);
    } else
    {
      EnumWindows((WNDENUMPROC)WndEnumProc, pi.dwProcessId);
      <...>
9.3K
17 марта 2008 года
iridum
175 / / 26.08.2007
При показе VCL-формы в модальном режиме выборка сообщений из очереди осуществляется особым образом. Модальные окна в VCL - это не то же самое, что модальные диалоги с точки зрения API. Диалог может быть создан только на основе шаблона, и его модальность обеспечивается самой операционной системой, а VCL допускает модальность для любой формы, позволяя разработчику не быть ограниченным возможностями предусмотренного системой шаблона. Достигается это следующим образом: при вызове метода ShowModal все окна запрещаются средствами VCL, затем окно показывается обычным образом, как немодальное, но из-за того, что все остальные окна запрещены, создаётся эффект модальности.

Внутри ShowModal создаётся своя петля сообщений. В этой петле в цикле вызывается метод Application.HandleMessage до тех пор, пока не будет установлено свойство ModalResult или не придёт сообщение WM_Quit. После завершения этой петли вновь разрешаются все окна, которые были разрешены до вызова ShowModal, а "модальная" форма закрывается. В отличие от системных модальных диалогов модальная форма VCL во время своей активности не посылает родительскому окну сообщение WM_EnterIdle, но благодаря тому, что "модальная" петля сообщений использует HandleMessage, будет вызываться Idle, а значит, будет возникать событие Application.OnIdle, которое позволит выполнять фоновые действия.
Написано на http://delphikingdom.ru/asp/viewitem.asp?catalogid=169

Я тож из длл-плагина не могу отобразть просто так модальную форму в основном приложении, для этого я делаю что типа:

Код:
class TXti
{
 private:
   bool ShowDialog(xti *xte)
   {
           Synchronize(SShowDialog);
           return Answer;
   }

   void __fastcall SShowDialog();
}
....
void __fastcall TXti::SShowDialog()
{
       SwDialog= new TShowDialog(Application);
       Answer = SwDialog->ShowModal() == mrOk;
       delete SwDialog;
       SwDialog = NULL;
}
...
Xti->ShowDialog(xte);


А вот насчёт
 
Код:
SetWindowPos(Form2->Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);

Окно уж явно не будет ни модальным ни TOPMOST и будет постоянно пропадать под другие окна.

Кстати зделать это можно
 
Код:
SetWindowLong(Form2->Handle, GWL_EXSTYLE, WS_EX_TOPMOST);

без ноликов :)
11
18 марта 2008 года
oxotnik333
2.9K / / 03.08.2007
Цитата: kot_
 
Код:
SetWindowPos(Form2->Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);



такое вряд ли поможет, т.к. форма показывается модально, и выполнение кода после TForm::ShowModal тормозится до ее закрытия

[quote=frid-karatel]

Код:
<...>
  if (CreateProcess(NULL, RUNAPPNAME, 0, 0, FALSE, 0, 0, 0, &si, &pi))
  {
    DWORD res = WaitForInputIdle(pi.hProcess, 3000);
    if (res == WAIT_TIMEOUT)
    {
      TerminateProcess(pi.hProcess, 0);
    } else
    {
      EnumWindows((WNDENUMPROC)WndEnumProc, pi.dwProcessId);
      <...>

[/quote]
и какие выводы по поводу HWND дает этот код, если в нем ниразу хендл ничей не указан?
490
18 марта 2008 года
frid-karatel
357 / / 15.09.2007
Цитата: oxotnik333
и какие выводы по поводу HWND дает этот код, если в нем ниразу хендл ничей не указан?



Вот практически полный код моих действий:

Код:
BOOL CALLBACK WndEnumProc(HWND hWnd, LPARAM lParam)
{
  DWORD pid;
  GetWindowThreadProcessId(hWnd, &pid);
  if (pid == (DWORD)lParam)
  {
    ShowWindow(hWnd, SW_HIDE);
  }
  return true;
}
//---------------------------------------------------------------------------
void StartOtherProg()
{
  <...>
  if (CreateProcess(NULL, OTHERPROGFILE, 0, 0, FALSE, 0, 0, 0, &si, &pi))
  {
    DWORD res = WaitForInputIdle(pi.hProcess, 3000);
    if (res == WAIT_TIMEOUT)
    {
      TerminateProcess(pi.hProcess, 0);
    } else
    {
      EnumWindows((WNDENUMPROC)WndEnumProc, pi.dwProcessId);
      <...>
    }
    Form1->ShowWaitForm();
    <...>
}
//---------------------------------------------------------------------------
DWORD CALLBACK OperationThread()
{
  <...>
  Form2->Close();
  return 0;  
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ShowWaitForm()
{
  <...>
  Form2->ShowModal();
  <...>
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormShow(TObject *Sender)
{
  CloseHandle(CreateThread(0, 0, OperationThread, 0, NULL, NULL));
}


Я запускаю функцию StartOtherProg(), и до тех пор, пока запущеное мной другое приложение (окна которого скрыты) не выполнит все действия, я ожидаю...

Я еще подключаю к запускаемой программе DLL в CreateProcess:
 
Код:
LPVOID p = VirtualAllocEx(pi.hProcess, 0, strlen(PROG_DLL) + 1, MEM_COMMIT, PAGE_READWRITE);
      if (p)
      {
        if (WriteProcessMemory(pi.hProcess, p, PROG_DLL, strlen(PROG_DLL) + 1, NULL))

В этом не может быть проблемы?
11
18 марта 2008 года
oxotnik333
2.9K / / 03.08.2007
а что вот это делает:

 
Код:
CloseHandle(CreateThread(0, 0, OperationThread, 0, NULL, NULL));

да и вообще... сначала Form2 показывается модально, затем на ее OnShow стоит Form2->Close()
1
18 марта 2008 года
kot_
7.3K / / 20.01.2000
Цитата: iridum
При показе VCL-формы в модальном режиме выборка сообщений из очереди осуществляется особым образом. Модальные окна в VCL - это не то же самое, что модальные диалоги с точки зрения API. Диалог может быть создан только на основе шаблона, и его модальность обеспечивается самой операционной системой, а VCL допускает модальность для любой формы, позволяя разработчику не быть ограниченным возможностями предусмотренного системой шаблона. Достигается это следующим образом: при вызове метода ShowModal все окна запрещаются средствами VCL, затем окно показывается обычным образом, как немодальное, но из-за того, что все остальные окна запрещены, создаётся эффект модальности.

Внутри ShowModal создаётся своя петля сообщений. В этой петле в цикле вызывается метод Application.HandleMessage до тех пор, пока не будет установлено свойство ModalResult или не придёт сообщение WM_Quit. После завершения этой петли вновь разрешаются все окна, которые были разрешены до вызова ShowModal, а "модальная" форма закрывается. В отличие от системных модальных диалогов модальная форма VCL во время своей активности не посылает родительскому окну сообщение WM_EnterIdle, но благодаря тому, что "модальная" петля сообщений использует HandleMessage, будет вызываться Idle, а значит, будет возникать событие Application.OnIdle, которое позволит выполнять фоновые действия.
Написано на http://delphikingdom.ru/asp/viewitem.asp?catalogid=169

Я тож из длл-плагина не могу отобразть просто так модальную форму в основном приложении, для этого я делаю что типа:

Код:
class TXti
{
 private:
   bool ShowDialog(xti *xte)
   {
           Synchronize(SShowDialog);
           return Answer;
   }

   void __fastcall SShowDialog();
}
....
void __fastcall TXti::SShowDialog()
{
       SwDialog= new TShowDialog(Application);
       Answer = SwDialog->ShowModal() == mrOk;
       delete SwDialog;
       SwDialog = NULL;
}
...
Xti->ShowDialog(xte);


А вот насчёт
 
Код:
SetWindowPos(Form2->Handle,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);

Окно уж явно не будет ни модальным ни TOPMOST и будет постоянно пропадать под другие окна.

Кстати зделать это можно
 
Код:
SetWindowLong(Form2->Handle, GWL_EXSTYLE, WS_EX_TOPMOST);

без ноликов :)


Многа букафф не осилил.
Прежде чем писать - может стоит проверить то , что вы цитируете? Попытка профессиональной риторики - еще не говорит о том, что утверждения верны.
Кроме того - вынужден разочаровать - данный код работает - причем форма к которой данное свойство применяется вызывается из длл.
Не смотря, на то что по вашему мнению это невозможно. :)
З.Ы. Возможно это так же связанно с тем что модальную форму вы создаете

 
Код:
SwDialog= new TShowDialog(Application);

я всегда модальную форму создаю
 
Код:
SwDialog= new TShowDialog(NULL);

надеюсь не нужно объяснять почему?
490
18 марта 2008 года
frid-karatel
357 / / 15.09.2007
Цитата: oxotnik333
а что вот это делает:
 
Код:
CloseHandle(CreateThread(0, 0, OperationThread, 0, NULL, NULL));

CloseHandle(...) закрывает создаваемый поток...[//QUOTE]

[QUOTE=oxotnik333;238189]да и вообще... сначала Form2 показывается модально, затем на ее OnShow стоит Form2->Close()


Form2->Close() не стоит в OnShow окна - он стоит в созданном потоке...

PS: я привел примерный код моей программы

9.3K
18 марта 2008 года
iridum
175 / / 26.08.2007
Цитата: kot_
Многа букафф не осилил.
Прежде чем писать - может стоит проверить то , что вы цитируете? Попытка профессиональной риторики - еще не говорит о том, что утверждения верны.
Кроме того - вынужден разочаровать - данный код работает - причем форма к которой данное свойство применяется вызывается из длл.
Не смотря, на то что по вашему мнению это невозможно. :)
З.Ы. Возможно это так же связанно с тем что модальную форму вы создаете
 
Код:
SwDialog= new TShowDialog(Application);

я всегда модальную форму создаю
 
Код:
SwDialog= new TShowDialog(NULL);

надеюсь не нужно объяснять почему?



Уважаемый _kot во всём что я здесь написал я уверен, и без разницы как вы создаёте это окно, отображатся модально оно не будет, а вот то что я написал про VCL это правда, и несмотря на ваш большой опыт я вам бы советывал это прочитать, потому что это одна из тонкостей билдера, у него модальные окна организуются не так как в WINAPI.

ps.Я только что специально перепроверил, и так как вы сказали тоже, а вот вы даже строки не осилили, а вот и зря, так много знать - не уделять внимания мелочам.
Тем не менее, действительно если

 
Код:
SwDialog= new TShowDialog(NULL);

Раньше так делал, но модальное окно не пробывал.
А вот через SetWindowPos становится поверх других окон не хочет.
11
18 марта 2008 года
oxotnik333
2.9K / / 03.08.2007
[QUOTE=frid-karatel]CloseHandle(...) закрывает создаваемый поток...[/QUOTE]
А нахрена создавать и тут же убивать его???

[QUOTE=frid-karatel]
Form2->Close() не стоит в OnShow окна - он стоит в созданном потоке...

PS: я привел примерный код моей программы[/QUOTE]

А поток запускается на OnShow...

ЗЫ: архитектура явно страдает
9.3K
18 марта 2008 года
iridum
175 / / 26.08.2007
Может кто подскажет как зделать окно всегда сверху из длл плагина в основном приложении. SetWindowPos, SetWindowLong не прокатывают. Окно нужно не модальное, а такое, чтобы всегда было поверх всех остальных окон этого приложения.
1
18 марта 2008 года
kot_
7.3K / / 20.01.2000
Цитата: iridum
Уважаемый _kot во всём что я здесь написал я уверен, и без разницы как вы создаёте это окно, отображатся модально оно не будет, а вот то что я написал про VCL это правда, и несмотря на ваш большой опыт я вам бы советывал это прочитать, потому что это одна из тонкостей билдера, у него модальные окна организуются не так как в WINAPI.

ps.Я только что специально перепроверил, и так как вы сказали тоже, а вот вы даже строки не осилили, а вот и зря, так много знать - не уделять внимания мелочам.
Тем не менее, действительно если
 
Код:
SwDialog= new TShowDialog(NULL);

Раньше так делал, но модальное окно не пробывал.
А вот через SetWindowPos становится поверх других окон не хочет.


Вот горе-то, горе. :):):)
У меня становиться - у вас не становиться.
Писать и читать никто не мешает - и о том что билдер имеет свои ньюансы в работе с окнами я знаю - по крайней мере новостью для меня это не является. Но. Окно в данном случае все равно окном остается. И установка его первым в Z-последовательности сработает в любом случае.

9.3K
18 марта 2008 года
iridum
175 / / 26.08.2007
Цитата: kot_
Вот горе-то, горе. :):):)
У меня становиться - у вас не становиться.
Писать и читать никто не мешает - и о том что билдер имеет свои ньюансы в работе с окнами я знаю - по крайней мере новостью для меня это не является. Но. Окно в данном случае все равно окном остается. И установка его первым в Z-последовательности сработает в любом случае.



_Kot в последнем вашем посте я узнал много полезного, очень очень полезный пост. Если не сложно,учитывая ваш опыт, ответе пожалуйста на мой вопрос вашим постом выше, очень надеюсь что вы ответите без гнева присущего вам в этой теме )

ps. Ни от кого ничег оне пребую )) просто действительно именно щас вдруг потребовалось зделать окно поверх, не получается пока если кто знает как ответте пожалуйста.

490
18 марта 2008 года
frid-karatel
357 / / 15.09.2007
Цитата: oxotnik333
А нахрена создавать и тут же убивать его???
А поток запускается на OnShow...
ЗЫ: архитектура явно страдает



Вообще, я в своей программе поток создаю при создании первой формы (основной, т.е. Form1), ставлю его в "спящий" режим, а потом активирую. Т.е. вместо CloseHandle(CreateThread(...)) я активирую поток, соответственно, функция Form2::FormShow(...) выполняется полностью.

В потоке же я жду, пока программа выполнит все действия... Когда все ОК, я закрываю модальную форму Form2...

Итак, в чем же может быть проблема, и почему форма не показывается?

PS: может тупо сэмулировать клик на главной форме? и все... :)

1
18 марта 2008 года
kot_
7.3K / / 20.01.2000
Цитата: iridum
_Kot в последнем вашем посте я узнал много полезного, очень очень полезный пост. Если не сложно,учитывая ваш опыт, ответе пожалуйста на мой вопрос вашим постом выше, очень надеюсь что вы ответите без гнева присущего вам в этой теме )

ps. Ни от кого ничег оне пребую )) просто действительно именно щас вдруг потребовалось зделать окно поверх, не получается пока если кто знает как ответте пожалуйста.


Да собственно не вопрос.
Код приложения-хоста:

Код:
void __fastcall TfmMain::actAddPositionExecute(TObject *Sender)
{
if(dmMain->cdsSelectPriceItems->FieldByName("price")->Value==0)return;
HANDLE ghMutex = CreateMutex(NULL,FALSE,"CreateFormComplex");
int Res = GetLastError();
HWND hWnd = NULL;
if(Res==ERROR_ALREADY_EXISTS || Res == ERROR_INVALID_HANDLE)
 hWnd = FindWindow("TfmComplete",NULL);
else{
 CloseHandle(ghMutex);
  typedef HWND (__import *pLoadForm)(HWND Handler,const char* connect);
  pLoadForm fLoadForm = NULL;
  HINSTANCE hDll = LoadLibrary("complcomp.dll");
  if(!hDll)return;
  fLoadForm = (pLoadForm)GetProcAddress(hDll,"_LoadForm");
  if(!fLoadForm){
  ShowMessage("Not load func!");return;
  }
  String temp = WideCharToString(dmMain->adoConnect->ConnectionString);
  hWnd = fLoadForm(this->Handle,temp.c_str());
}

SetWindowPos(hWnd,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
SendMessage(hWnd,MM_ADDITEMS,dmMain->cdsSelectPriceItems->FieldByName("priceitem")->Value,0);
}

Этот код вызывается в случае, если окно необходимо поместить на передний план - но при этом модальным оно быть не должно. Думаю что в пояснениях код не нуждается. Это код который выполняется в длл
 
Код:
HWND LoadForm(HWND Handler,const char *connect){
CoInitialize(NULL);
  TfmComplete *fmMn = new TfmComplete(NULL);
  fmMn->SetConnect(Handler,connect);
  fmMn->Show();
  return fmMn->Handle;
}

Когда выполняется этот участок кода - окно отображается, но скрывается когда клик происходит по родительскому окну или любому другому.
Это код вызова формы, которая показывается как модальная:
Код:
void __fastcall TfmMain::actShowComplectExecute(TObject *Sender)
{
  //
  typedef HWND (__import *pLoadForm)(HWND Handler,const char* connect);
  pLoadForm fLoadForm = NULL;
  HINSTANCE hDll = LoadLibrary("complcomp.dll");
  if(!hDll)return;
  fLoadForm = (pLoadForm)GetProcAddress(hDll,"_LoadFormAll");
 if(!fLoadForm){
 ShowMessage("Not load func!");return;
 }
  String temp = WideCharToString(dmMain->adoConnect->ConnectionString);
   fLoadForm(this->Handle,temp.c_str());
  FreeLibrary(hDll);
}

Соответствующая функция в длл:
 
Код:
HWND LoadFormAll(HWND Handler,const char *connect){
CoInitialize(NULL);
  TfmMain *fmMain = new TfmMain(NULL);
  fmMain->SetConnect(Handler,connect);
  fmMain->ShowModal();
  delete fmMain;
CoUninitialize();  
  return 0;
}

Если же в первой функции использовать вместо
 
Код:
SetWindowPos(hWnd,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);

 
Код:
SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);

вы получите окно, которое модальным не является - но при этом находиться всегда сверху.
490
19 марта 2008 года
frid-karatel
357 / / 15.09.2007
блин... я так и не понял ... в чем у меня проблема? почему модальная форма не показывается?
11
19 марта 2008 года
oxotnik333
2.9K / / 03.08.2007
Цитата: frid-karatel
блин... я так и не понял ... в чем у меня проблема? почему модальная форма не показывается?



запускай поток на OnShow модальной формы
т.е.

 
Код:
TModalForm *ModalForm = new TModalForm(NULL);
ModalForm->ShowModal();
//------------------------
void __fastcall TModalForm::FormShow(TObject *Sender)
{
  CreateThread(...);
}
//--------------------
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог