IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

Ouvrir une fenêtre (graphique) depuis une appli console


Sujet :

Windows

  1. #1
    Membre confirmé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Points : 455
    Points
    455
    Billets dans le blog
    1
    Par défaut Ouvrir une fenêtre (graphique) depuis une appli console
    Bonjour,

    je travaille sur un programme en mode console du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main ( int argc, char * argv [] )
        {
        InfoStruct info ;
        fonction_superbalaise( argc,argv,&info ) ;
        printf("%s\n",info.debug_string ) ;
        return 0 ;
        }
    et je voudrais (si c'est possible) créer une fenêtre (avec CreateWindow) et dessiner dedans.

    Idéalement, mon code ressemblerait à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void draw ( InfoStruct * info ) ;
    
    int main ( int argc, char * argv [] )
        {
        InfoStruct info ;
        fonction_superbalaise( argc,argv,&info ) ;
        if // (on veut en plus un affichage graphique)
           draw( &info ) ;
        printf("%s\n",info.debug_string ) ;
        return 0 ;
        }
    et dans un autre fichier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <Windows.h>
    
    void draw ( InfoStruct * info )
        {
        HWND  window = CreateWindowEx( NULL,"test","test",WS_POPUP,...
        HDC   dc     = GetWindowDC( window ) ;
        PAINTSTRUCT paintst ;
        BeginPaint( window,&paintst ) ;
        // LineTo...
        // TextOutW...
        EndPaint( window,&paintst ) ;
        }
    Mais est-il possible de créer une fenêtre lorsque le projet que l'on a créé est en mode console ?
    J'ai fait déjà plein d'essais, mais le CreateWindow ou CreateWindowEx me renvoient toujours NULL... même avec un RegisterClassEx avant...
    Je suis très loin d'être un expert en windozrie mais j'ai cru comprendre que c'était possible...

    Toute suggestion, conseil ou exemple de code seraient les bienvenus...
    Captain'Flam
    anciennement Sopsag, aka Hadrien
    Win seven x64 & Win 10 / Visual 2017 / Python 2.7 / Eclipse

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    C'est simple, il te suffit de faire pareil que dans une application fenêtrée: RegisterClassEx, CreateWindowEx, boucle de messages...

    Le problème, c'est pour les entrées: Tu ne pourras pas à la fois lire des caractères sur la console et attendre des messages Windows, donc si tu as des trucs à entrer je te conseille de passer par un contrôle EDIT dans ta fenêtre.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre confirmé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Points : 455
    Points
    455
    Billets dans le blog
    1
    Par défaut
    J'ai réussi à faire marcher l'exemple fourni dans la doc Visual (Using Window Classes).
    J'ai essayé en afféctant hInstance à NULL (le paramètre de WinMain que je n'ai plus avec un simple main), et ça marche.

    Ce que je ne comprends pas, c'est que c'est exactement la même chose que dans mes essais précédents. Enfin il doit bien y avoir une différence, mais je ne la vois pas...

    En tous cas merci... je finissais par croire que c'était impossible.

    Pour ceux que ça intéresse, voici mon code :
    Display.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #ifndef __display_h__
    #define __display_h__
    
    #include "Vector2D.h"
    
    class Display
        {
        public:
            Display () ;
           ~Display () ;
    
            bool init ( Vector2D pos , Vector2D size ) ;
            void line ( Vector2D p0 , Vector2D p1 , int color ) ;
    
        protected:
            struct PrivateDisplay ;
            PrivateDisplay * m ;
        } ;
    
    #endif /* __display_h__ */
    Display.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    #include <windows.h>
    #include <string.h>
    #include "Display.h"
    
    LRESULT CALLBACK MainWndProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
        {
        return( DefWindowProc( hWnd,message,wParam,lParam )) ;
        }
    
    struct Display::PrivateDisplay
        {
        PrivateDisplay ()  { is_init = false ;}
        bool     is_init ;
        HWND     hwnd  ;
        HDC      dc    ;
        HFONT    font  ;
        Vector2D size  ;
        } ;
    
    Display::Display () 
        {
        m = new PrivateDisplay ;
        }
    
    Display::~Display () 
        {
        if (m->is_init)
            {
            DeleteObject( m->font ) ;
            DeleteDC( m->dc ) ;
            }
        delete m ;
        }
    
    bool Display::init ( Vector2D pos , Vector2D size ) 
        {
        WNDCLASSEX wcx ;
        memset( &wcx,0,sizeof( wcx )) ;
        wcx.cbSize        = sizeof( wcx ) ;
        wcx.lpfnWndProc   = MainWndProc ;
        wcx.lpszClassName = "spam" ;
        RegisterClassEx( &wcx ) ;
    
        m->size  = size ;
        m->hwnd  = CreateWindow( wcx.lpszClassName,0,0,pos.x,pos.y,m->size.x,m->size.y,NULL,NULL,NULL,NULL ) ;
        m->dc    = GetWindowDC( m->hwnd ) ;
        m->font  = CreateFont( 16,0,0,0,0,FALSE,FALSE,FALSE,0,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH | FF_DONTCARE,"Arial" ) ;
    
        ShowWindow  ( m->hwnd,TRUE ) ;
        UpdateWindow( m->hwnd ) ;
    
        PAINTSTRUCT paintst ;
        BeginPaint  ( m->hwnd,&paintst ) ;
        HBRUSH brush = CreateSolidBrush( RGB( 0,0,0 )) ;
        SelectObject( m->dc,brush ) ;
        Rectangle   ( m->dc,0,0,m->size.x,m->size.y ) ;
        DeleteObject( brush ) ;
        EndPaint( m->hwnd,&paintst ) ;
        m->is_init = true ;
        return true ;
        }
    
    void Display::line ( Vector2D p0 , Vector2D p1 , int color )
        {
        PAINTSTRUCT paintst ;
        BeginPaint  ( m->hwnd,&paintst ) ;
        HPEN pen = CreatePen( PS_SOLID,1,RGB( 0,100,200 )) ;
        SelectObject( m->dc,pen ) ;
        MoveToEx( m->dc,p0.x,p0.y,NULL ) ;
        LineTo( m->dc,p1.x,p1.y ) ;
        DeleteObject( pen ) ;
        EndPaint( m->hwnd,&paintst ) ;
        }
    (Vector2D est juste une struct avec int x,y).

    Comme ça, le reste de mon code reste "standard" (i.e. n'est pas pollué par une inclusion de Windows.h).
    Captain'Flam
    anciennement Sopsag, aka Hadrien
    Win seven x64 & Win 10 / Visual 2017 / Python 2.7 / Eclipse

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Tu peux obtenir le HINSTANCE de ton exécutable avec GetModuleHandle(NULL).

    Attention, le HINSTANCE/HMODULE retourné est toujours celui de l'EXE, donc si tu écris un jour une DLL il te faudra utiliser une autre méthode.

    PS: Tu ne dessines pas comme tu devrais. BeginPaint/EndPaint ne sont supposés être utilisés que dans le traitement d'un message WM_PAINT, tu sais...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre confirmé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Points : 455
    Points
    455
    Billets dans le blog
    1
    Par défaut
    PS: Tu ne dessines pas comme tu devrais. BeginPaint/EndPaint ne sont supposés être utilisés que dans le traitement d'un message WM_PAINT, tu sais...
    Argl !
    En vérité, je n'ai aucune notion de bonnes pratiques en matière de dessin avec l'API Win32.
    Les rares fois où je m'en sers, je bricole un truc copié/collé depuis des tutoriels ou autres bouts de code trouvés sur le net.
    Et à propos de BeginPaint/EndPaint, tout ce que je sais, c'est que si je ne les mets pas, ça ne dessine rien, et que tel que je les utilise, j'arrive à avoir ce que je veux...
    Mais si tu connais une bonne source d'exemples de code graphique qui s'appuient sur Win32, je suis preneur !
    Merci
    Captain'Flam
    anciennement Sopsag, aka Hadrien
    Win seven x64 & Win 10 / Visual 2017 / Python 2.7 / Eclipse

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    En fait, normalement tout le dessin est fait dans le traitement de WM_PAINT. Le traitement des autres messages (pression de boutons etc.) ne fait que deux choses, côté dessin:
    1. Mémoriser ce qui doit être dessiné (par exemple, les données d'un graphique)
    2. Dire à Windows de redessiner la fenêtre quand il aura le temps (Appeler InvalidateRect() sur la fenêtre avec NULL au pointeur de rectangle fait ça très bien).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre confirmé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Points : 455
    Points
    455
    Billets dans le blog
    1
    Par défaut
    Merci,
    mais si je ne me trompe, ce dont tu me parles, c'est de la philosophie de programmation par évènements, non ?
    Or, dans mon cas, pas très orthodoxe, je ne gère aucun évènement...
    Je n'ai pas la fameuse boucle GetMessage/TranslateMessage/DispatchMessage, mais je dessine quand j'en ai besoin.

    En fait, comme je travaille sur un programme qui fait des calculs sur des graphes, ma petite classe Display ne me sert qu'à afficher des traces graphiques.
    C'est à dire qu'aux différentes étapes de mon algo, je dessine l'état courant de mon graphe, sans me soucier de la souris ou du clavier...

    D'où ma question : y a-t-il une bonne pratique dans un cas comme le mien ?
    Captain'Flam
    anciennement Sopsag, aka Hadrien
    Win seven x64 & Win 10 / Visual 2017 / Python 2.7 / Eclipse

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Est-ce un truc supposé être animé, ou est-ce simplement "on dessine au fur et à mesure des calculs, puis on laisse l'utilisateur regarder" ?

    Car dans le second cas, le plus simple est de tout dessiner dans un Bitmap hors-écran pendant tes calculs, et puis afficher ledit bitmap dans le traitement de WM_PAINT.

    Dans le premier cas, c'est plus compliqué, mais rien qu'un InvalidateRect() + UpdateWindow() ne puisse gérer.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre confirmé
    Avatar de Captain'Flam
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2011
    Messages
    273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Février 2011
    Messages : 273
    Points : 455
    Points
    455
    Billets dans le blog
    1
    Par défaut
    J'aimerais une classe Display ayant une API du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class Display
        {
        public:
            Display () ;
           ~Display () ;
            bool init ( Vector2D pos , Vector2D size ) ;
            void line ( Vector2D p0 , Vector2D p1 , int color ) ;
        protected:
            ...
        } ;
    qui créé une fenêtre quand j'appelle init et dessine une ligne au moment où j'appelle line.
    C'est à dire que si je débugue mon code pas à pas, quand je passe sur un appel à line, je veux voir la ligne se tracer tout de suite.

    Mais tout le reste de mon code reste de type console, avec un simple int main ( argc , argv ) et aucune inclusion de windows.h où autre header propriétaire microsoft.
    Il n'y a que dans Display.cpp que je m'autorise du code non standard.

    Du coup, je n'ai aucune boucle de traitement des messages, et en particulier, je ne peux pas traiter WM_PAINT.

    Ce que j'ai fait jusqu'à présent :
    dans init :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    RegisterClassEx
    CreateWindow
    GetWindowDC
    SetWindowPos
    ShowWindow
    dans line :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    BeginPaint
    MoveToEx
    LineTo
    EndPaint
    Ça marche plutôt bien, mais je me demande quand même si c'est la bonne marche à suivre...
    Captain'Flam
    anciennement Sopsag, aka Hadrien
    Win seven x64 & Win 10 / Visual 2017 / Python 2.7 / Eclipse

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je pense que la meilleure marche à suivre dans ce cas serait non seulement de tout dessiner sur une image, mais en plus d'avoir l'affichage dans un autre thread.

    Ou carrément dans un autre process si tu veux pouvoir utiliser le debugger, mais comme on ne peut pas partager une image tu te retrouverais à devoir faire de l'IPC pour tes ordres de dessin. D'un autre côté, ça n'est pas tellement sorcier avec le message WM_COPYDATA qui se charge du marshalling.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Créer une fenêtre Windows depuis une application console
    Par khayyam90 dans le forum Contribuez
    Réponses: 0
    Dernier message: 28/12/2010, 23h56
  2. Réponses: 0
    Dernier message: 28/12/2010, 19h36
  3. Réponses: 6
    Dernier message: 12/08/2007, 11h10
  4. [SWT] Lancer une fenêtre SWT depuis une autre
    Par sunvialley dans le forum SWT/JFace
    Réponses: 12
    Dernier message: 21/04/2006, 17h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo