afficher les numéros de ligne

ChachaChacha Membre
23:48 modifié dans API AppKit #1
Salut,

Je me pose un problème, et je n'ai absolument aucune idée de la façon de le résoudre. Je voudrais une zone où l'on puisse taper du texte, et qui affiche à  gauche les numéros de ligne (comme dans XCode, quoi).
Voici donc une multi-question : comment dois-je emboà®ter quelles vues ?
Je ne sais vraiment pas par quelle bout y prendre (comme on dit chez moi).

+
Chacha

Réponses

  • cbrandtcbrandt Membre
    23:48 modifié #2
    une nsscrollview qui afficherait une nsrulerview surchargée ?
  • ChachaChacha Membre
    23:48 modifié #3
    dans 1111328637:

    une nsscrollview qui afficherait une nsrulerview surchargée ?


    NSRulerView, tiens je ne connais pas ça, je vais regarder.
    Merci du tuyau !

    +
    Chacha
  • ChachaChacha Membre
    23:48 modifié #4
    Bon, ça y est, je me suis un peu rencardé sur tout ce qui peut intervenir dans mon problème : afficher les numéros de ligne en marge d'une NSTextView.
    Apparemment, ce n'est pas simple; plutôt que de partir dans n'importe quelle direction, je vous demanderais bien encore quelques conseils.
    Isolons les problèmes:
      -Ma NSTextView n'a pas de scroller horizontal, le texte revient tout seul à  la ligne, donc une ligne "réelle" se terminant par "\n" peut tenir sur plusieurs lignes "visuelles" de la NSTextview, ce qui induit une forte irrégularité dans ce que je devrais afficher dans la NSRulerView.
      -je vais donc avoir besoin, a priori (détrompez-moi sinon), de calculer un peut le <bounding rect> d'une ligne réelle. Pour ça, je crois que c'est le NSLayoutManager qui contient la bonne information, et me permettra, avec un NSRange de caractères, de calculer la taille à  l'écran (tenant compte de la fonte, etc.)
      -ensuite, je n'ai qu'à  surcharger l'affichage des marqueurs dans la rulerview, pour afficher un numéro en regard de chaque <bounding rect> calculé précédemment; c'est la partie la moins claire dans ma tête, je suis un peu perdu.

    Vos avis ?

    +
    Chacha
  • ClicCoolClicCool Membre
    23:48 modifié #5
    dans 1111344156:

      -je vais donc avoir besoin, a priori (détrompez-moi sinon), de calculer un peut le <bounding rect> d'une ligne réelle. Pour ça, je crois que c'est le NSLayoutManager qui contient la bonne information, et me permettra, avec un NSRange de caractères, de calculer la taille à  l'écran (tenant compte de la fonte, etc.)


    euh, je dis peut-être une bétise pour ton cas mais la méthode size des NSAttributedString tout simplement ça t'irait pas ?

    size

    - (NSSize)size
    Returns the bounding box of the marks that the receiver draws.
  • ChachaChacha Membre
    23:48 modifié #6
    dans 1111344438:

    euh, je dis peut-être une bétise pour ton cas mais la méthode size des NSAttributedString tout simplement ça t'irait pas ?

    À première vue non, car la taille de la string est, je pense, indépendant de son contexte; je veux dire, c'est la taille qu'elle aurait si on l'affichait sur une seule ligne, mais en réalité elle est peut-être à  cheval sur plusieurs lignes à  cause de la largeur réduite du NSTextView.
  • ChachaChacha Membre
    mars 2005 modifié #7
    Yesss ! J'ai réussi !
    Je posterai un code propre dès que ce sera bien rôdé. En fait ça a été plus simple que ce que je croyais.

    +
    Chacha

    [Fichier joint supprimé par l'administrateur]
  • ChachaChacha Membre
    23:48 modifié #8
    Voilà  le code en question. Il est perfectible pour plusieurs raisons : efficacité, et répartition plus logique du travail entre les différentes classes. Mais ce code que je vous propose est vraiment petit, et facile à  comprendre, vous pourrez donc l'adapter facilement.

    1)Créez une classe LineCountRulerView dérivant de NSRulerView
    2)associez ce ruler personnalisé à  votre textView ainsi:
    <br />  NSScrollView* scrollView = (NSScrollView*) [[myTextView superview] superview];<br />  [myTextView setRulerVisible:YES];<br />  [scrollView setHasHorizontalRuler:NO];<br />  [scrollView setHasVerticalRuler:YES];<br />  LineCountRulerView* lineCountRulerView =<br />    [[LineCountRulerView alloc] initWithScrollView:scrollView orientation:NSVerticalRuler];<br />  [scrollView setVerticalRulerView:lineCountRulerView];<br />  [lineCountRulerView setClientView:myTextView];<br />  [lineCountRulerView release];<br />
    


    Puis, réimplémentez la méthode suivante dans LineCountRulerView:
    <br />-(void)drawHashMarksAndLabelsInRect:(NSRect)aRect<br />{<br />  NSRect visibleRect  = [(NSClipView*)[[self clientView] superview] documentVisibleRect];<br />  NSLayoutManager* lm = [(NSTextView*)[self clientView] layoutManager];<br />  NSTextContainer* tc = [(NSTextView*)[self clientView] textContainer];<br />  NSString* text      = [(NSTextView*)[self clientView] string];<br /><br />  /* ma bidouille avec end, lineStart et cur permet de trouver les NSRange caractérisant les lignes se terminant par &#092;n. On peut sûrement l&#39;améliorer */<br />  const unsigned long end = [text length];<br />  unsigned long lineStart = 0;<br />  unsigned long cur   = 0;<br />  int lineNumber = 1;<br />  while(lineStart &lt; end) //tant qu&#39;on n&#39;a pas parcouru toutes les lignes<br />  {<br />    //je cherche le &#39;&#092;n&#39; suivant<br />    while ((cur &lt; end) &amp;&amp; ([text characterAtIndex:cur] != &#39;&#092;n&#39;))<br />      ++cur;<br /><br />    //voici le NSRange caratérisant la ligne<br />    NSRange lineRange = NSMakeRange(lineStart, cur-lineStart+1);<br /><br />    //je calcule son bounding rect<br />    NSRect rect = [lm boundingRectForGlyphRange:lineRange inTextContainer:tc];<br /><br />    //si la ligne est visible, afficher le numéro de ligne<br />    if (NSIntersectsRect(rect, visibleRect))<br />    {<br />      NSPoint origin = NSMakePoint(0, rect.origin.y-visibleRect.origin.y);<br />      NSString* numberString = [[[NSString alloc] initWithFormat:@&quot;%d&quot;, lineNumber] autorelease];<br />      [numberString drawAtPoint:origin withAttributes:nil];<br />    }<br />    lineStart = ++cur;<br />    ++lineNumber;<br />  }<br />}//quoi, c&#39;est déjà  fini ?<br />
    


    Une dernière chose, il faut rafraà®chir le ruler quand le texte est modifié. On peut le faire brutalement en lui faisant scruter la notification correspondante:
    Toujours dans LineCountRulerView:
    <br />-(id) initWithScrollView:(NSScrollView*)scrollView orientation:(NSRulerOrientation)orientation<br />{<br />  self = [super initWithScrollView:scrollView orientation:orientation];<br />  if (self)<br />  {<br />    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:)<br />     name:NSTextDidChangeNotification object:nil];<br />  }<br />  return self;<br />}<br /><br />-(void) dealloc<br />{<br />  [[NSNotificationCenter defaultCenter] removeObserver:self];<br />  [super dealloc];<br />}<br /><br />-(void) textDidChange:(NSNotification*)aNote<br />{<br />  [self setNeedsDisplay:YES];<br />}<br /><br />
    


    pas mal, non ? Je vous file une petite capture d'écran:

    [Fichier joint supprimé par l'administrateur]
  • ClicCoolClicCool Membre
    23:48 modifié #9
    Pas mal du tout en vérité.

    Ca vaudrait d'être mis dans les trucs et astuces ou dans les ressources ça !

    Je vais p'tet encore dire une bétise mais pour identifier tes lignes séparées par des @\n, pourquoi ne pas tout tronçoner dans un array de lignes avec
    arrayDesLignes = [leTexte componentSeparatedByString:@&quot;&#092;n&quot;];
    


    ?
  • ChachaChacha Membre
    23:48 modifié #10
    dans 1111360301:

    Je vais p'tet encore dire une bétise mais pour identifier tes lignes séparées par des @\n, pourquoi ne pas tout tronçoner dans un array de lignes avec
    arrayDesLignes = [leTexte componentSeparatedByString:@&quot;&#092;n&quot;];
    


    ?

    J'allais te répondre une bêtise ! Je m'appretais, furibond, à  transcrire au clavier qu'une telle technique perd l'information des ranges, et puis en fait j'ai réalisé qu'on retrouve très facilement cette information avec la taille des chaà®nes. Donc oui, c'est une excellente idée !

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