IsDialogMessage() verhindert Zeilenumbruch in multiline edit...



  • Hey!

    Damit WS_TABSTOP funktioniert, sieht meine Schleife so aus:

    MSG message = { };
    	while(GetMessage(&message, 0, 0, 0))
        {
    		if(!IsDialogMessage(GetForegroundWindow(), &message))	
    		{
    			TranslateMessage(&message);
    			DispatchMessage(&message);
    		}
        }
    

    Jedoch wird leider kein Zeilenumbruch mehr gemacht, wenn ich in einem multiline edit Enter drücke... Wer weiß, was IsDialogMessage() noch für Nachteile hat, so wie ich es jetzt benutze.

    Wie schaffe ich es, dass WS_TABSTOP funktioniert, aber sonst nichts eingeschränkt wird?

    Danke!
    MfG



  • Wie wäre es, wenn du bei IsDialogMessage das Handle deines Hauptfensters angibst und nicht irgendein Fensterhandle von irgendwelchen anderen Fenster aus, wo möglich, noch fremden Prozessen?


  • Mod

    Wie erzeugst Du das Edit-Control?
    ES_WANTRETURN gesetzt?



  • Hey!

    Danke! ES_WANTRETURN hat gefehlt.
    Ok, ich werde das richtige Fensterhandle übergeben.

    Danke!
    MfG



  • Leider hat...

    if(!IsDialogMessage(MyClass::getInstance().getWindowHandle(), &message))
    {
    	TranslateMessage(&message);
    	DispatchMessage(&message);
    }
    

    ...noch einen Haken:
    Ich kann die Enter-Taste nicht mehr abfragen. Es kommt einfach keine Nachricht. Habs auch mit subclassing probiert...

    Wie kann ich das beheben?

    Danke!
    MfG



  • IsDialogMessage() verarbeitet die Enter-Nachricht.
    D.h. wenn Du an diese Information rankommen möchtest, mußt Du sie noch VOR Aufruf von IsDialogMessage() aus &message abfragen!

    Martin



  • bei Enter bekommst du ne WM_COMMAND mit IDOK



  • @Mmacher
    Und wie soll dann meine Schleife aussehen, wenn auch WS_TABSTOP funktionieren soll?

    @glaubich
    Dem scheint nicht so.

    MfG



  • Kenn mich sehr wenig mit dem WINAPI aus...
    So funktioniert es, ist das so richtig oder hat es wieder einen oder mehrere Haken?

    MSG message = { };
    	while(GetMessage(&message, 0, 0, 0))
        {
    		if(IsDialogMessage(MyClass::getInstance().getWindowHandle(), &message))	
    		{
    			if(message.message == WM_KEYDOWN)
    				DispatchMessage(&message);
    		}
    		else
    		{
    			TranslateMessage(&message);
    			DispatchMessage(&message);
    		}
        }
    

    MfG


  • Mod

    Das ist falsch. Wenn IsDialogMessage einen Wert <>0 zurück gibt, dann wurde die Nachricht bereits ausgeliefert. Du sendest Sie dann gleich zweimal!



  • Mhm, und wie mache ich es nun richtig?

    MfG



  • Sorry, daß ich nicht schneller antworten konnte.
    Da Du die Funktion IsDialogMessage() verwendest, gehe ich von einem Beispiel mit einem nichtmodalen Dialog aus.

    Szenario:
    Applikation hat ein Hauptfenster (mit hwnd_frame) und ein nichtmodaler Dialog (mit hwnd_dialog).
    Sowohl das Hauptfenster als auch der nichtmodale Dialog haben jeweils eine eigene Callback-Prozedur. D.h. für dieses Beispiel spielt es (eigentlich) keine Rolle wie diese Prozeduren programmiert wurden.
    Wenn der nichtmodale Dialog erscheint (und somit die Variable b_dialog_aktiv gesetzt), so soll die Tastenkombination "ALT+F4" die gesamte Applikation (und nicht als Windows-Standard nur den nichtmodalen Dialog) beenden.
    Im Gegenzug muß ich selbst dafür sorgen, daß die Tastenkombination "Strg+F4" den nichtmodalen Dialog beendet.
    Zusätzlich soll ein Tastendruck "Tab" den Eingabefokus vom nichtmodalen Dialog auf das Haupfenster gesetzt werden.

    Zunächst hier die eigentliche Nachrichtenschleife in WinMain():

    BOOL b_IsDialogMessage_erlaubt, b_TranslateMessage_erlaubt, b_retvalue;
    HACCEL haccel_accelerator;
    HWND hwnd_frame, hwnd_dialog;
    MSG struct_msg = { 0 };
    
    do
    {
      b_retvalue = GetMessage( &struct_msg, NULL, 0, 0 );
          //Alle Nachrichten werden einzeln nacheinander von der Queue abgeholt und
          //auch von dort entfernt (ohne Message-Filterung). Mögliche Rückgabewerte sind:
          //==0: WM_QUIT Nachricht -> Programm beenden.
          // >0: Normale Nachricht -> verarbeiten.
          //==-1: Fehler ist aufgetreten-> Programm beenden.
      if ( b_retvalue > 0 )
      {
        //Eine normale Nachricht ist eingetroffen.
        b_IsDialogMessage_erlaubt = Dialog_ProcessMessageFilter( &struct_msg );
        if ( TranslateAccelerator( hwnd_frame, haccel_accelerator, &struct_msg ) == 0 )
            //Prüft ob die in struct_msg enthaltene Nachricht ein Tastaturereignis beschreibt:
            //Wenn ja, folgt ein Vergleich mit der über haccel_accelerator angegebenen Tabelle.
            //Sollte die Routine dort fündig werden, übergibt sie der Window-Prozedur eine Nachricht
            //des Typs WM_COMMAND bzw. WM_SYSCOMMAND und liefert einen Wert ungleich 0 zurück.
        {
          b_TranslateMessage_erlaubt = 1;   //Aufrufe von TranslateMessage() und DispatchMessage() zunächst erlauben.
          if ( b_IsDialogMessage_erlaubt != 0 )
          {
            if ( IsDialogMessage( hwnd_dialog, &struct_msg ) != 0 )
                //IsDialogMessage() determines whether a message is intended for the specified dialog box and, if it is, processes the
                //message. If the message has not been processed, the return value is zero. Because the IsDialogMessage() performs all
                //necessary translating and dispatching of messages, a message processed by IsDialogMessage() MUST NOT be passed
                //to TranslateMessage() or DispatchMessage()!
            {
              b_TranslateMessage_erlaubt = 0;   //Aufrufe von TranslateMessage() und DispatchMessage() blockieren.
            }
          }
          if ( b_TranslateMessage_erlaubt != 0 )
          {
            TranslateMessage( &struct_msg );  //Übersetzt angekommene Virtual-Key Codes bei Bedarf in entsprechende Zeichen-Nachrichten (WM_CHAR).
            DispatchMessage( &struct_msg );   //Sorgt für "Verteilung" der Nachrichten an die zuständigen Fenster- und Dialog-Prozeduren.
          }
        }
      }
      else
      {
        if ( b_retvalue < 0 )
        {
          //********************************
          //** Ein Fehler ist aufgetreten **
          //********************************
          ProgrammEnde_FreeMemory_MessageboxFunktionFehlgeschlagen( -1, TEXT( "Error in GetMessage() aufgetreten!" ) );
              //Ein Fehler ist aufgetreten, Abbruch des Programms.
        }
      }
    } while ( b_retvalue != 0 );    //Solange abarbeiten, bis Nachricht WM_QUIT eintrifft.
    

    Nun muß ich in der Nachrichtenschleife erstmal herausfinden, ob die Nachricht überhaupt von meiner nichtmodalen Dialog stammt. Wenn ja, dann werte diese aus. Das macht die Funktion Dialog_ProcessMessageFilter():

    BOOL Dialog_ProcessMessageFilter( const LPMSG pstruct_msg )
    {
    BOOL b_IsDialogMessage_erlaubt;
    
    if ( ( b_dialog_aktiv == 0 )  //Dialog ist nicht aktiv (Wert abhängig, ob nichtmodaler Dialog aktiv ist oder nicht).
         || ( hwnd_dialog == NULL ) )   //Fenster für Dialog ist nicht erzeugt.
    {
      return( 0 );  //0=Aufruf von IsDialogMessage() in der Message-Schleife blockieren.
    }
    
    b_IsDialogMessage_erlaubt = 1;  //Aufruf von IsDialogMessage() zunächst grundsätzlich erlauben.
    if ( ( IsChild( hwnd_dialog, pstruct_msg->hwnd ) == TRUE )
         || ( pstruct_msg->hwnd == hwnd_dialog ) )
    {
      //Die Nachricht stammt von nichtmodaler Dialogbox.
      switch ( pstruct_msg->message )
      {
        case WM_KEYDOWN:
        switch ( pstruct_msg->wParam )
        {
          case VK_F4:
          if ( GetKeyState( VK_CONTROL ) < 0 )  //Tasten "Ctrl"+"F4".
          {
            SendMessage( hwnd_dialog, WM_CLOSE, (WPARAM)0, (LPARAM)0 );
                //Dialogbox beenden.
            b_IsDialogMessage_erlaubt = 0;    //Aufruf von IsDialogMessage() blockieren.
          }
          break;
    
          case VK_TAB:  //Taste "Tab".
          SendMessage( hwnd_frame, WM_SETFOCUS, (WPARAM)hwnd_dialog, (LPARAM)0 );
              //Eingabefokus auf Hauptfenster übertragen.
          b_IsDialogMessage_erlaubt = 0;  //Aufruf von IsDialogMessage() blockieren.
          break;
        }
        break;
    
        case WM_SYSKEYDOWN:
        switch ( pstruct_msg->wParam )
        {
          case VK_F4: //Tasten "Alt"+"F4".
          SendMessage( hwnd_frame, WM_CLOSE, (WPARAM)0, (LPARAM)0 );
              //Die gesamte Applikation beenden.
          b_IsDialogMessage_erlaubt = 0;  //Aufruf von IsDialogMessage() blockieren.
          break;
        }
        break;
      }
    }
    return( b_IsDialogMessage_erlaubt );  //0=Aufruf von IsDialogMessage() in der Message-Schleife blockieren.
                                          //1=Aufruf von IsDialogMessage() in der Message-Schleife ist erlaubt.
    } //Ende von Dialog_ProcessMessageFilter().
    

    Diese Funktion Dialog_ProcessMessageFilter() liefert als Rückgabewert einen BOOL-Wert, welcher entscheidet, ob die Nachricht auch an IsDialogMessage() weitergeleitet werden darf oder nicht.

    Ich denke, kürzer kann ich es kaum beschreiben. Trotzdem hoffe ichs, das Prinzip Tastaturauswertung von Dialogen oder Controls in den Dialogen einigermaßen verständlich dargestellt zu haben?

    Martin



  • Ohjeohje 😞

    Ich verwende keine Dialogbox. Habe lediglich ein Hauptfenster und paar Childs darin...

    Sorry, und von dem da oben versteh ich beinahe garnix zumal das wohl für meinen Fall garnicht benötigt wird?

    Nochmal:
    Habe ein Fenster mit paar childs, und möchte dass WS_TABSTOP funktioniert aber auch dass die Enter-Taste WM_KEYDOWN sendet.

    Es funktioniert so:

    MSG message = { };
    	while(GetMessage(&message, 0, 0, 0))
        {
    		if(IsDialogMessage(SlowBob::getInstance().getWindowHandle(), &message))	
    		{
    			if(message.message == WM_KEYDOWN)
    				DispatchMessage(&message);
    		}
    		else
    		{
    			TranslateMessage(&message);
    			DispatchMessage(&message);
    		}
        }
    

    Aber Martin Richter meinte, das sei falsch. Jedoch werden Nachrichten anscheinend NICHT doppelt gesendet, nachdem ich nach der "if(message.message == WM_KEYDOWN)" Abfrage TranslateMessage() weggelassen habe...

    Doch möchte ich wissen, ob das Konstrukt nicht doch noch etwas Ungewolltes bewirken könnte.

    Danke trotzdem, MMacher!
    MfG



  • Wenn Du in der MSDN-Doku zu IsDialogMessage() lesen würdest:

    IsDialogMessage() determines whether a message is intended for the specified dialog box and, if it is, processes the 
    message. If the message has not been processed, the return value is zero. Because the IsDialogMessage() performs all 
    necessary translating and dispatching of messages, a message processed by IsDialogMessage() [b]MUST NOT[/b] be passed 
    to TranslateMessage() or DispatchMessage()!
    

    Somit darfst Du auf keinen Fall DispatchMessage() im Zweig

    {
      if(message.message == WM_KEYDOWN)
      DispatchMessage(&message);
    }
    

    aufrufen!

    Das meinte Martin Richter mit "zweimal senden", da Du diese Nachricht einmal schon in IsDialogMessage() gesendet hast und dann noch ein zweites Mal über DispatchMessage()!

    Übrigens, es werden massig viele Nachrichten gesendet, nicht nur Tastendrücke.

    Gib Dir einen Ruck und schau Dir mal die Kommentare im meinem Quelltext an, insbesondere in der Nachrichtenschleife (also dem ersten Block). Dann verstehst Du vielleicht eine der wichtigsten Grundprinzipien der WinAPI-Programmierung ein wenig besser?

    Martin



  • Ich werd daraus nicht schlau und ehrlichgesagt will ich es auch garnicht. Ich möchte doch nuuur wissen, wie ich mein Problem löse...

    Nicht bös gemeint, aber um es selbst herauszufinden brauch ich hier doch kein Thema eröffnen...

    Nnnaja, so vielleicht?

    MSG message = { };
    	while(GetMessage(&message, 0, 0, 0))
        {
    		if(message.wParam == VK_RETURN)
    		{
    			TranslateMessage(&message);
    			DispatchMessage(&message);
    		}
    		else if(!IsDialogMessage(SlowBob::getInstance().getWindowHandle(), &message))	
    		{
    			TranslateMessage(&message);
    			DispatchMessage(&message);
    		}
        }
    

    Funktioniert jedenfalls.

    MfG



  • Das sieht schon viel besser aus.
    So werden keine Nachrichten mehr doppelt verschickt.

    ABER: Durch dieses Konstrukt bekommt der Dialog-Manager (der in IsDialogMessage() integriert ist) alle Nachrichten mit wParam = VK_RETURN nicht mehr.
    D.h. ich gehe davon aus, wenn Du z.B. irgendwo im Fenster einen Button hast, bewirkt ein Return-Tastendruck kein Auslösen des Buttons mehr (mit Mausklick ist das Button-Auslösen natürlich weiterhin möglich)! (Habs aus Zeitmangel nicht getestet ob das so stimmt, es müßte aber so sein.)

    Für eine ordentlich saubere Programmierung würde ich zusätzlich noch eine Abfrage einbauen, ob die Nachricht auch das für Dich richtige Handle message.hwnd enthält.

    Martin



  • Jo danke!
    Aber die zusätzliche Abfrage ist wohl nicht nötig, da ich die Funktionalität, mit Enter einen Button betätigen zu können, garnicht einbauen möchte.

    Ich denke das Thema hat sich erledigt.
    MfG


Anmelden zum Antworten