Uaktywnianie okna - problem

0

Witam,

Mam ukryte okno, chcę je przywołać na pierwszy plan i uaktywnić. Próbowałem mnóstwa wygooglowanych funkcji, nic nie działa:

  • SetForegroundWindow co prawda podświetla mi je na pasku i ustawia nad innymi, ale okno nadal jest nieaktywne
  • SetFocus, SetActiveWindow, ShowWindow(handle, SW_SHOW) nie działają (również wariant SW_SHOWNORMAL)
  • SendMessage(Handle, WM_ACTIVATE, 1, 0) nie działa.
    Próbowałem i na uchwytach okna, i aplikacji - nic. Coś dziwnego działo się przy poprzedzeniu SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW) jakimiś innymi funkcjami - okno aktywowało się na chwilę i gasło, ale nie jestem w stanie teraz odtworzyć tego zachowania.

Dodatkowo z nieznanych mi przyczyn nie działa też zdarzenie OnDeactivate, w którym próbowałem to okno ukryć. Program nie robi jeszcze praktycznie nic, używa jednego DLLa i komunikatu WM_USER + 101. W kodzie projektu ustawiam Application.ShowMainForm := false, przed wyświetleniem okna zmieniam na true.

Czy ktoś może zna jakieś inne wyjaśnienie takiego zachowania niż "Windows"? Jeśli tak, to bardzo chętnie je poznam ;) Dodam, że chodzi o Delphi 2009 na Windowsie 2000.

0

Po co masz ShowMainWindow = false?

Moim zdaniem to może powodować problem, lub jakaś inna aplikacja ma okno ustawione zawsze na wierzchu, ale raczej obstawiałbym to pierwsze.

0

Po starcie program ma być niewidoczny, jest wywoływany hotkeyem. Ale przed wszystkimi funkcjami ustawiałem na true. Jeszcze Application.MainFormOnTaskbar = false. Oba ustawiłem na true w kodzie projektu, nie pomogło. Da się wywołać na pierwszy plan przez SetWindowPos, ale nie da rady uaktywnić chociaż teoretycznie SetWindowPos powinno to zrobić samo, bez innych dodatków. SetForegroundWindow i BringToFront tylko mrugają przyciskiem na taskbarze.

Przy wywołaniu przez SetWindowPos aktywne pozostaje ostatnio używane okno. W tle mam przynajmniej dwa programy z oknami zawsze na wierzchu, ale oba ukryte i nigdy nie sprawiały problemów.

Przychodzi do głowy takie coś, żeby ustawić kursor na pasku tytułowym, zasymulować kliknięcie i przesunąć z powrotem na miejsce, ale nie dość że to karkołomne, to jeszcze niezbyt pr0 i tró. Można jeszcze zrobić osobny EXE i go wywoływać, ale po pierwsze to powolne, a po drugie będzie zalegać w pamięci.

0

powiem tak... zrobilem przed sekunda prosty eksperyment:

procedure TForm1.FormCreate(Sender: TObject);
begin
 Application.ShowMainForm:=false;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 if GetKeyState(VK_CONTROL)<0
    then Form1.Show;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Form1.Hide;
end;

i dziala. po uruchomieniu nie widac zadnego okna ani belki na pasku zadan. po przytrzymaniu ctrl wyswietla form1 i ustawia jej focus.
moze ustawianie showmainform na false, pozniej na true wszystko psuje. to samo z tym MainFormOnTaskbar. jesli nie bedzie widac okna to na pewno nie bedzie tez belki na pasku zadan...
powyrzucaj z kodu wszystko co odpowiada za pokazywanie/ukrywanie formy i wykorzystaj tylko to z kodu pozyzej.
sprawdz tez, czy glowne okno nie ma jakis dziwnych ustawien, flag itd...</delphi>

0

Myślę, że to rozwiąże twój problem

{
Funkcja wyszukuje kawałek tekstu i dopasowuje go do istniejącej nazwy okna, której szukamy

Np.: chcemy zmaksymalizować/zminimalizować/przywrócić/zamknąć
okno notatnika. Wiemy że w nazwie okna jest zdanie "XXYYZZ - Notepad".
XXYYZZ zmienia się w zależności od otwartego dokumentu.

Wystarczy że podamy samo "- Notepad", a funkcja zwróci nam uchwyt do
szukanego okna o zmiennej początkowej nazwie.
}
function FindWindowExt(Text: string): hWnd;
var
 Han: hWnd;
 cTitle: array [0..254] of Char;
 sTitle: string;
begin
 Han  := FindWindow(nil, nil);
 Text := AnsiLowerCase(Text);

 while Han <> 0 do
   begin
    GetWindowText(Han, cTitle, 255);
    sTitle := cTitle;
    if cTitle = '' then
      begin
       Han := GetWindow(Han, GW_HWNDNEXT);
       Continue;
      end;

    sTitle := AnsiLowerCase(sTitle);
    Application.ProcessMessages;
    if Pos(Text, sTitle) <> 0 then Break;
    Han := GetWindow(Han, GW_HWNDNEXT);
  end;

 Result := Han;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 Han1: hWnd; {Handle, Cardinal, DWORD, hWnd}
 Han2: THandle;
begin
 Han1 := FindWindowExt('- Notepad');
 if Han1 <> 0 then
   begin
    {Przywracanie okna musi odbyć się bezpośrednio na uchwycie głównej aplikacji, a nie okna}
    Han2 := GetWindow(Han1, GW_OWNER); //Get the handle of application window

    {Zamiast SW_RESTORE, można użyć, WM_CLOSE, SW_MINIMIZE, SW_MAXIMIZE i innych param.}
    ShowWindow(Han2, SW_RESTORE);
    
    {Przywrócenie okna na wierzch. Nie używaj dla WM_CLOSE, SW_MINIMIZE}
    SetForegroundWindow(Han2);
   end;
end;
0
cimak napisał(a)

powiem tak... zrobilem przed sekunda prosty eksperyment:

procedure TForm1.FormCreate(Sender: TObject);
begin
 Application.ShowMainForm:=false;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 if GetKeyState(VK_CONTROL)<0
    then Form1.Show;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Form1.Hide;
end;

i dziala. po uruchomieniu nie widac zadnego okna ani belki na pasku zadan. po przytrzymaniu ctrl wyswietla form1 i ustawia jej focus.
moze ustawianie showmainform na false, pozniej na true wszystko psuje. to samo z tym MainFormOnTaskbar. jesli nie bedzie widac okna to na pewno nie bedzie tez belki na pasku zadan...
powyrzucaj z kodu wszystko co odpowiada za pokazywanie/ukrywanie formy i wykorzystaj tylko to z kodu pozyzej.
sprawdz tez, czy glowne okno nie ma jakis dziwnych ustawien, flag itd...</delphi>

Wypróbowałem na czystym projekcie - okno wyskakuje na wierzch, ale bez focusa.

@Opi - uchwyt do głównego, ukrytego okna aplikacji w moim przypadku najprościej uzyskać przez Application.Handle, ShowWindow działa j.w., a SetForegroundWindow tylko powoduje miganie na taskbarze.

Czyżby to była kwestia Win2k? Raczej powątpiewam, ale skoro ten sam kod u innych działa a u mnie nie...

W takim razie może inaczej: czy ktoś ma jeszcze inny pomysł na wyświetlenie okna z focusem, żeby user nie musiał na nie czekać jak np. w przypadku odpalenia osobnego EXE? Albo jak w miarę prosty sposób przechwytywać tekst do nieaktywnego okna? Hook globalny już mam, ale trzeba by okodować np. backspace'a, strzałki, przemieszczanie po tekście itd. a chodzi mi o coś prostszego.

0

dziwne u mnie wyskakiwalo normalnie z focusem...
hmm... a zernknij na to, moze cos wymyslisz:
http://4programmers.net/Forum/575091?h=restore#id575091
przypomnial mi sie moj problem gdy napisales o tej mrugajacej belce na pasku zadan... ;]

0

prawdopodobnie masz problem z dwiema formami modalnymi czyż nie, jakaś modalna ma być.. modalniejsza.. ;) ?

ja stosuję taką kombinację i działa poprawnie:

iHandle := FindWindow('TfmObjectClipboard', nil); //znajduje uchwyt
oForm := FindControl(iHandle) as TForm; //wyciagam forme
oForm.Show(); //"uwidaczniam" forme jesli jest ukryta
oForm.BringToFront(); //wyciagam ja na wierzch
EnableWindow(oForm.Handle, True); //aktywuję

0

@zajcev - mam tylko jedno okno, niemodalne. Aplikacja siedzi schowana, okno ma być focusowane hotkeyem.

@cimak - na Win2k kod powoduje "odfocusowanie" wszystkich okien. Jeśli wcześniej wywlekę swoje na wierzch przez SetWindowPos, to mam je na górze i nie ma aktywnego okna. Z ciekawości uruchomiłem to samo na Viście - SetWindowPos ustawia okno na górze, ForceForegroundWindow je uaktywnia, krótko mówiąc wszystko działa.

Zrobiłem jeden eksperyment i nie mogę się z tego otrząsnąć. Wstawiłem TEdit na formatkę. Na Win2k okno nie jest aktywne, ale w TEdit kursor normalnie mruga i mogę wpisywać do niego tekst. Tak jakby miało focusa, ale pasek tytułu jest wyszarzony.

Właściwie o to mi chodziło. Głupio to wygląda, ale działa ;) Gdyby ktoś miał z tym jeszcze problem - daję kod odpowiedzialny za wyświetlenie okna.

  fStartS.Show;
  SetWindowPos(fStartS.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW);
  ForceForegroundWindow(fStartS.Handle);

Dzięki dla wszystkich pomocnych ludzi tutaj :)

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