Comment fermer ma fenêtre ?

sisopetronsisopetron Membre
21:17 modifié dans API AppKit #1
Bonjour à  tous,

Je suis débutant en cocoa et je suis confronté à  un problème qui, malgré des heures de lecture, résiste à  toutes mes tentatives de résolution.

J'essaie d'afficher un splashscreen.  Dans IB j'ai créé une fenêtre (NSWindow) supplémentaire dans mon fichier XIB principal. Dans xcode, j'ai créé une classe appelée SplashScreen que j'ai reliée à  cette fenêtre.  Voici l'implémentation de vette classe :

@implementation SplashScreen<br /><br /><br />- (id)initWithContentRect:(NSRect)contentRect <br />				styleMask:(unsigned int)style<br />				&nbsp; backing:(NSBackingStoreType)bufferingType <br />					defer:(BOOL)flag<br />{<br />	// Détermine le centre de l&#39;écran principal.<br />	NSScreen* mainScreen = [NSScreen mainScreen];<br />	NSRect screen = [mainScreen frame];<br />	NSPoint center = NSMakePoint(screen.size.width / 2, screen.size.height / 2);<br />	contentRect.origin.x = center.x - (contentRect.size.width / 2);<br />	contentRect.origin.y = center.y - (contentRect.size.height / 2);<br />	<br />	// Appel à  la fonction init héritée, mais passe NSBorderlessWindowMask à  la place <br />	// du style normal.&nbsp; Cela donne une fenêtre sans barre de titre ni bords.<br />	id window = [super initWithContentRect:contentRect<br />								 styleMask:NSBorderlessWindowMask <br />								&nbsp;  backing:bufferingType <br />									 defer:flag];<br />	if (window)<br />	{<br />		// Fixe l&#39;opacité de la fenêtre<br />		[window setOpaque:NO];<br />		<br />		// Impose une couleur claire au fond de la fenêtre (sans cela,<br />		// on aurait le fond normal d&#39;OS X : des barres horizontales).<br />		[window setBackgroundColor:[NSColor colorWithDeviceWhite:1.0 alpha:0.0]];<br />		<br />		// Pas d&#39;ombre à  la fenêtre.<br />		[window setHasShadow:NO];<br />		<br />		// Place la fenêtre au dessus de toutes les autres.&nbsp; Même d&#39;autres applications. <br />		// Tant qu&#39;elle ne reste pas plus de 2 secondes au dessus des autres, l&#39;utilisateur<br />		// ne s&#39;en plaindra pas, il est cependant possible de choisir un autre niveau<br />		// comme le niveau application de façon à  permettre à  l&#39;utilisateur de <br />		// continuer à  utiliser l&#39;ordinateur pendant que le programme charge.&nbsp; Voir la <br />		// documentation sur NSWindow pour la description d&#39;autres niveaux d&#39;affichage.<br />		[window setLevel:NSFloatingWindowLevel];<br />	}<br />	<br />	return window;<br />}<br />


Toujours dans IB, j'ai associé cette fenêtre à  une classe delegate appelée AppCotroller.

Mon problème est le suivant : bien que la case 'Visible at Launch' de ma fenêtre ne soit pas cochée, elle s'affiche d'emblée au démarrage de l'application.  Est-ce mon code qui provoque cet affichage ?  Et deuxième question : comment puis-je fermer cette fenêtre 'at runtime' ?  Que dois-je écrire comme code pour y parvenir ?

Merci de votre aide.

Réponses

  • apocaalypsoapocaalypso Membre
    21:17 modifié #2
    Pour fermer ta fenêtre, rien de plus simple :
    [window close:nil];
    
  • sisopetronsisopetron Membre
    21:17 modifié #3
    Merci pour ta réponse.

    Ou est-ce que je mets cette instruction ?  Si je fais
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification <br />{ <br />	[window close:nil];<br />}
    

    il me retourne un warning : window undeclared

    Pratiquement comment je dois-je faire ? Et où dois-je mettre ce code ?

    NB: Pardon si mes questions vous paraissent idiotes mais je suis super débutant.
  • apocaalypsoapocaalypso Membre
    21:17 modifié #4
    Cela dépend de quand tu souhaite fermer ta fenêtre, si tu mets ce code dans ton  applicationDidFinishLaunching:, c'est à  dire la méthode appelée lorsque ton application a terminé son lancement, ta fenêtre se fermera directement à  l'ouverture de ton application.

    Dans mon example, window est définie en variable d'instance (dans le .h). Mais ça dépend de comment tu déclares ta window, apparemment elle n'est déclarée que dans une seule méthode.
    Dans ton cas, si SplashScreen est définie en tant de NSWindow, remplace window par self (qui renvoie donc à  ta fenêtre) :
    [self close:nil];
    
  • sisopetronsisopetron Membre
    21:17 modifié #5
    Toujours un problème : j'obtiens un

    warning: &#39;SplashScreen&#39; may not respond to &#39;-close:&#39;
    

    et évidemment ma fenêtre ne se ferme pas.
  • ClicCoolClicCool Membre
    21:17 modifié #6
    S'il te répond ça c'est qu'il ne sait pas que "splashScreen" est une NSWindow.

    Comment l'a tu déclarée ?
  • sisopetronsisopetron Membre
    21:17 modifié #7
    Euh,

    Dans l'interface de mon SplashScreen.h il y a :

    @interface SplashScreen : NSWindow {<br />}
    


    Comment la déclarer autrement ? 
  • apocaalypsoapocaalypso Membre
    21:17 modifié #8
    [super performClose:nil] ?
  • ClicCoolClicCool Membre
    21:17 modifié #9
    Ah ?
    Alors où as-tu écris la suggestion d'apocaalypso ?
    dans 1256055809:

    [self close:nil];
    



    Dans l'implémentation de ton SplashScreen ?

    Vu que tu veux mettre ça dans le didFinishLaunched, j'ai dans l'idée que t'as écris ça dans ton appDélagate ... non ?
    Alors ton appDelegate doit garder un pointeur vers ton SplashScreen.
    genre, dans le fichier de déclaration d'interface (.h) de ton AppDelegate:
    SplashScreen * maSplashScreen;
    

    Puis dans son implémentation (.m) tu mets le code qui ouvre la fenêtre , tu y mets la référence vers cette SplashScreen genre.
    maSplashScreen= [SplashScreen alloc] initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen];
    


    Tu te retrouves là  avec une référence valide qui te permetra plus tard, dans le didFinishLaunching d'écrire:
    [maSplashScreen close:nil];
    
  • sisopetronsisopetron Membre
    21:17 modifié #10
    Bon, je commence à  comprendre...

    J'ai encore une erreur :

    error: conflicting types for &#39;maSplashScreen&#39;
    


    Et je ne la comprends pas celle-là .
  • ClicCoolClicCool Membre
    21:17 modifié #11
    dans 1256061786:

    Bon, je commence à  comprendre...

    J'ai encore une erreur :

    error: conflicting types for &#39;maSplashScreen&#39;
    


    Et je ne la comprends pas celle-là .


    ça t'indique qu'il n'arrive pas à  déterminer le type exacte de maSplashScreen.

    ça arrive, par exemple, quand la déclaration indique un type (SplashScreen* ...) mais que dans l'implémentation on l'initialise avec un autre type (NSWindow*...)
  • ClicCoolClicCool Membre
    21:17 modifié #12
    dans 1256027534:

    .../...
    @implementation SplashScreen<br /><br /><br />- (id)initWithContentRect:(NSRect)contentRect <br />				styleMask:(unsigned int)style<br />				&nbsp; backing:(NSBackingStoreType)bufferingType <br />					defer:(BOOL)flag<br />{<br />	// Détermine le centre de l&#39;écran principal.<br />	NSScreen* mainScreen = [NSScreen mainScreen];<br />	NSRect screen = [mainScreen frame];<br />	NSPoint center = NSMakePoint(screen.size.width / 2, screen.size.height / 2);<br />	contentRect.origin.x = center.x - (contentRect.size.width / 2);<br />	contentRect.origin.y = center.y - (contentRect.size.height / 2);<br />	<br />	// Appel à  la fonction init héritée, mais passe NSBorderlessWindowMask à  la place <br />	// du style normal.&nbsp; Cela donne une fenêtre sans barre de titre ni bords.<br />	id window = [super initWithContentRect:contentRect<br />								 styleMask:NSBorderlessWindowMask <br />								&nbsp;  backing:bufferingType <br />									 defer:flag];<br />	if (window)<br />	{<br />		// Fixe l&#39;opacité de la fenêtre<br />		[window setOpaque:NO];<br />		<br />		// Impose une couleur claire au fond de la fenêtre (sans cela,<br />		// on aurait le fond normal d&#39;OS X : des barres horizontales).<br />		[window setBackgroundColor:[NSColor colorWithDeviceWhite:1.0 alpha:0.0]];<br />		<br />		// Pas d&#39;ombre à  la fenêtre.<br />		[window setHasShadow:NO];<br />		<br />		// Place la fenêtre au dessus de toutes les autres.&nbsp; Même d&#39;autres applications. <br />		// Tant qu&#39;elle ne reste pas plus de 2 secondes au dessus des autres, l&#39;utilisateur<br />		// ne s&#39;en plaindra pas, il est cependant possible de choisir un autre niveau<br />		// comme le niveau application de façon à  permettre à  l&#39;utilisateur de <br />		// continuer à  utiliser l&#39;ordinateur pendant que le programme charge.&nbsp; Voir la <br />		// documentation sur NSWindow pour la description d&#39;autres niveaux d&#39;affichage.<br />		[window setLevel:NSFloatingWindowLevel];<br />	}<br />	<br />	return window;<br />}<br />
    
    .../...


    A priori ça vient de là : id window = [super initWithContentRect:contentRect
    styleMask:NSBorderlessWindowMask


    Dans ton initialisation tu appèles le super pour qu'il te renvoie ce qu'il sait faire (une NSWindow).
    Nulle part tu lui demandes d'initialiser ton SplashScreen, tu renvoie ensuite la NSWindow ainsi crée comme résultat de l'initialisation de ta SplashScreen ... il est perdu.

    Remplace tous les window par self
    self = [super initWithContentRect:contentRect<br />								 styleMask:NSBorderlessWindowMask
    
  • sisopetronsisopetron Membre
    21:17 modifié #13
    Je te remercie de t'intéresser à  mon cas et je dois t'avouer que je ne m'en sors pas :  j'ai remplacé tous les woindow par self et ça ne marche toujours pas.  Peut-être l'erreur se trouve-t-elle dans l'implémentation de ma classe AppController dont je te donne ici le contenu :

    #import &quot;AppController.h&quot;<br />#import &quot;SplashScreen.h&quot;<br /><br />@implementation AppController<br /><br />- (void)axakeFromNib<br />{<br />	maSplashScreen = [[SplashScreen alloc] initWithContentRect:(NSRect)contentRect <br />													 styleMask:(NSUInteger)windowStyle <br />													&nbsp;  backing:(NSBackingStoreType)bufferingType <br />														 defer:(BOOL)deferCreation <br />														screen:(NSScreen *)screen];<br />	<br />}<br /><br /><br /><br />- (void)applicationDidFinishLaunching:(NSNotification *)aNotification <br />{ <br />	NSLog(@&quot;L&#39;application est chargée&quot;); <br />	[maSplashScreen close:nil];<br />}
    


    Tu veux bien y jeter un oeil ?  Merci.
  • ClicCoolClicCool Membre
    21:17 modifié #14
    - (void)axakeFromNib


    Si c'est du copier/collé de ton code, ça m'étonnerait qu'axakeFromNib soit appelé.
    A moins que tu n'ai une méthode awakeFromNib qui appèle à  son tour axakeFromNib ?
  • sisopetronsisopetron Membre
    21:17 modifié #15
    oups, voilà  c'est corrigé, mais ça ne change rien : j'ai toujours les même erreurs à  la compilation :

    error: &#39;contentRect&#39; undeclared (first use in this function)<br />error: &#39;windowStyle&#39; undeclared (first use in this function)<br />error: &#39;bufferingType&#39; undeclared (first use in this function)<br />error: &#39;deferCreation&#39; undeclared (first use in this function)<br />error: &#39;screen&#39; undeclared (first use in this function)<br />warning: &#39;SplashScreen&#39; may not respond to &#39;-close:&#39;
    


    Une idée de comment je peux corriger ça ?
  • apocaalypsoapocaalypso Membre
    21:17 modifié #16
    C'est quand même emmerdant de rester bloqué autant de temps pour fermer une fenêtre !  :)

    Copie-nous tout ton AppDelegate, ça sera plus simple.
  • sisopetronsisopetron Membre
    21:17 modifié #17
    Me voilà  de retour : désolé pour le délai, j'ai été un peu (beaucoup) occupé hier.  :P

    dans 1256243725:

    C'est quand même emmerdant de rester bloqué autant de temps pour fermer une fenêtre !  :)


    Tu l'as dit  :)

    Voilà  l'AppController :

    #import &quot;AppController.h&quot;<br />#import &quot;SplashScreen.h&quot;<br /><br />@implementation AppController<br /><br />- (void)awakeFromNib<br />{<br />&nbsp;  maSplashScreen = [[SplashScreen alloc] initWithContentRect:(NSRect)contentRect<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; styleMask:(NSUInteger)windowStyle<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; backing:(NSBackingStoreType)bufferingType<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  defer:(BOOL)deferCreation<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; screen:(NSScreen *)screen];<br />&nbsp;  <br />}<br /><br /><br /><br />- (void)applicationDidFinishLaunching:(NSNotification *)aNotification<br />{<br />&nbsp;  NSLog(@&quot;L&#39;application est chargée&quot;);<br />&nbsp;  [maSplashScreen close:nil];<br />}
    


    Ne serait-ce pas plutôt dans IB que le problème se pose ?  J'y ai définit la classe AppController comme delegate de ma fenêtre SplashScreen.  Ne devrais-je pas créer un outlet de ma fenêtre SplashScreen ?  Et si oui, qu'en faire ?

    Merci de m'aider.
  • ClicCoolClicCool Membre
    21:17 modifié #18
    dans 1256243725:

    C'est quand même emmerdant de rester bloqué autant de temps pour fermer une fenêtre !  :).../...

    Surtout s'il pleut  ;D



    dans 1256281199:

    Ne serait-ce pas plutôt dans IB que le problème se pose ? 

    Avant tout faudrait que ton code ne soit pas juste du copié-collé de prototypes de méthodes.
    Si tu ne défini pas contentRect, windowStyle, bufferingType, deferCreation ni screen ça risque pas de faire quoique ce soit.


    dans 1256281199:
    Merci de m'aider.

    Je crois surtout que tu devrais faire quelques tuto cocoa pour mieux appréhender l'ObjC avant tout, puis les frameWorks.

    Même s'il y a pleins de commodités et d'automatismes dans les frameworks et qu'IB est un outil puissant pour gérer l'interface, y'a pas de magie non plus et faut tout de même maitriser un peu le code.
  • sisopetronsisopetron Membre
    21:17 modifié #19
    dans 1256282068:
    Je crois surtout que tu devrais faire quelques tuto cocoa pour mieux appréhender l'ObjC avant tout, puis les frameWorks.


    Je fais, je fais.  Mais tu as raison, il y a un truc qui m'échappe là  et j'essaie juste de comprendre.

    Juste une petite question encore : contentRect, windowStyle, bufferingType, deferCreation sont définis dans la classe SplashScreen.  Il faut que je les redéfinisse dans mon AppController ?  Ne puis-je pas me contenter d'un

    maSplashScreen = [[SplashScreen alloc] init];
    


    tout simple ?
  • apocaalypsoapocaalypso Membre
    21:17 modifié #20
    Si, y tu accèderai ainsi en faisant par exemple maSplashScreen.contentRect (biensûr en définissant les @property dans ta classe SpashScreen de contentRect, etc...).
  • wiskywisky Membre
    21:17 modifié #21
    Si je peux me permettre d'apporter une modeste contribution à  ce sujet, je souhaiterai te faire par d'une méthode que je trouve plus efficace pour un splashscreen. Car le temps de chargement d'un fichier NIB n'est pas négligeable. La solution est de faire la fenêtre via du code.
    Pour moi cette fenêtre doit apparaitre le plus tôt possible et disparaitre dès que l'application est chargé.

    Voici un lien : http://wisky2.blogspot.com/2009/10/creer-une-fenetre-dattente-efficace-en.html
  • sisopetronsisopetron Membre
    21:17 modifié #22
    dans 1256292607:

    Si je peux me permettre d'apporter une modeste contribution à  ce sujet, je souhaiterai te faire par d'une méthode que je trouve plus efficace pour un splashscreen. Car le temps de chargement d'un fichier NIB n'est pas négligeable. La solution est de faire la fenêtre via du code.
    Pour moi cette fenêtre doit apparaitre le plus tôt possible et disparaitre dès que l'application est chargé.

    Voici un lien : http://wisky2.blogspot.com/2009/10/creer-une-fenetre-dattente-efficace-en.html


    Ah merci, c'est très intéressant ça.  Je m'y plonge.


    dans 1256292504:

    Si, y tu accèderai ainsi en faisant par exemple maSplashScreen.contentRect (biensûr en définissant les @property dans ta classe SpashScreen de contentRect, etc...).


    Je vais suivre ta suggestion et essayer comme ça.  Merci.
  • wiskywisky Membre
    21:17 modifié #23
    Je viens de voir que tu n'avais pas écrit le fonction init. L'exemple type de cette fonction est :
    <br />- (id)init{<br />if(self = [super init]){<br />//Ici le code pour initialiser l&#39;objet !<br /><br />}<br />return self;<br />}<br />
    

    Cela t'évitera peu être d'autre déboire  8--)
  • sisopetronsisopetron Membre
    octobre 2009 modifié #24
    wisky, ton truc est épatant.

    J'ai cependant un warning qui manifestement n'empèche pas le splashscreen de d'afficher : à  la ligne [splashScreen setDelegate:self]; j'ai : un warning qui me dit "class AppController does not implement the NSWindowDelegate protocol."

    Tu peux m'expliquer la raison de ce warning ?  Merci.
  • sisopetronsisopetron Membre
    21:17 modifié #26
    dans 1256334813:


    Merci pour ce lien.  Si j'ai bien compris, setDelegate permet de définir un delegate pour une classe à  la volée dans le code.

    Dans le cas qui m'occupe ici, c'est à  dire le code donné par wisky, cette  ligne ([splashScreen setDelegate:self]; ) n'est pas indispensable au bon fonctionnement du programme : si on la commente la compilation et l'exécution se déroulent sans problème.

    A quoi cela sert-il ici de définir un delegate alors ici ?

    NB: je suis désolé si mes questions vous paraissent triviales : je suis une débutant au tout début du début de l'apprentissage de cocoa. ;)
  • ClicCoolClicCool Membre
    21:17 modifié #27
    dans 1256401569:
    .../...NB: je suis désolé si mes questions vous paraissent triviales : je suis une débutant au tout début du début de l'apprentissage de cocoa. ;)


    J'ai dans l'idée que ça fait bail que ça te démange de te lancer dans l'aventure ;)
  • apocaalypsoapocaalypso Membre
    21:17 modifié #28
    Définir un delegate te permet par exemple d'exécuter des méthodes de delegate (par exemple dans le cas d'une WebView, ça te permet d'exécuter du code lorsque par exemple la page Web a finit de charger, ou a commencer de charger, ...).
  • wiskywisky Membre
    octobre 2009 modifié #29
    dans 1256323923:

    wisky, ton truc est épatant.

    J'ai cependant un warning qui manifestement n'empèche pas le splashscreen de d'afficher : à  la ligne [splashScreen setDelegate:self]; j'ai : un warning qui me dit "class AppController does not implement the NSWindowDelegate protocol."

    Tu peux m'expliquer la raison de ce warning ?  Merci.

    Dans ton cas ce n'est pas obligatoire. Je vais corriger ça sur mon blog !
    Tout objet acceptant un delegate permet de le changer à  la volé. Il faut cependant implémenter le protocole correspondant.
    Le delegate permet à  un objet d'envoyer des messages à  un objet spécifié pour effectuer des opération lié à  l'évènement cela évite de passer par le centre de notification. En tout cas je le vois comme ça  8--)


    PS : N'hésite pas à  laisser un message sur mon blog !
  • sisopetronsisopetron Membre
    21:17 modifié #30
    dans 1256402131:

    J'ai dans l'idée que ça fait bail que ça te démange de te lancer dans l'aventure ;)


    Comment as-tu deviné ?  ;)  :)

    A apocaalypso et wisky, merci pour vos explications.  Je continue mon exploration de cocoa (si mon travail me laisse un peu de temps) et j'aurai dans peu de temps sûrement encore pleins de questions à  vous poser sur ce forum.

    A+
Connectez-vous ou Inscrivez-vous pour répondre.