Question

Je veux ajustement cordes dans une largeur spécifique. Exemple, "Bonjour tout le monde" -> "... monde", "Bonjour ...", "Il ... DNR".
Savez-vous où je peux trouver le code pour cela? C'est une astuce très utile pour représenter l'information, et je voudrais l'ajouter dans mes applications (bien sûr).

Modifier : Désolé, j'ai oublié de mentionner le Font partie. Non seulement pour les chaînes de largeur fixe, mais selon le type de police.

Était-ce utile?

La solution

Il est un algorithme assez simple pour vous écrire si vous ne pouvez pas le trouver nulle part - le pseudocode serait quelque chose comme:

if theString.Length > desiredWidth:
    theString = theString.Left(desiredWidth-3) + "...";

ou si vous voulez les points de suspension au début de la chaîne, cette deuxième ligne serait:

    theString = "..." + theString.Right(desiredWidth-3);

ou si vous le voulez au milieu:

    theString = theString.Left((desiredWidth-3)/2) + "..." + theString.Right((desiredWidth-3)/2 + ((desiredWidth-3) mod 2))

Edit: Je suppose que vous utilisez MFC. Puisque vous le vouloir avec les polices, vous pouvez utiliser le

CString fullString
CSize size = pDC->GetOutputTextExtent(fullString);
bool isTooWide = size.cx > desiredWidth;

Si c'est trop grand, alors vous pouvez faire une recherche pour essayer de trouver la plus longue chaîne que vous pouvez adapter; et il pourrait être aussi intelligent une recherche que vous voulez - par exemple, vous pouvez juste essayer « Bonjour Worl ... » puis « Bonjour Wor ... » puis « Bonjour Wo ... »; la suppression d'un personnage jusqu'à ce que vous trouvez qu'il convient. Sinon, vous pouvez faire un - essayez « Bonjour Worl ... » - Si cela ne « t travail, puis utilisez seulement la moitié des caractères du texte original: « Bonjour ... » - si cela correspond, essayez à mi-chemin entre et: « Bonjour Wo ... » jusqu'à ce que vous trouviez la plus longue qui ne fonctionne toujours. Ou vous pouvez essayer une heuristique d'estimation (diviser la longueur totale de la longueur désirée, estimer proportionnellement le nombre de caractères, et la recherche à partir de là.

La solution simple est quelque chose comme:

unsigned int numberOfCharsToUse = fullString.GetLength();
bool isTooWide = true;
CString ellipsis = "...";
while (isTooWide)
{
    numberOfCharsToUse--;
    CString string = fullString.Left(numberOfCharsToUse) + ellipsis;
    CSize size = pDC->GetOutputTextExtent(string);
    isTooWide = size.cx > desiredWidth;
}

Autres conseils

Il est vraiment assez trivial; Je ne pense pas que vous trouverez un code spécifique à moins que vous avez quelque chose de plus structuré à l'esprit.

Vous voulez essentiellement:

  1. pour obtenir la longueur de la chaîne que vous avez, et la largeur de la fenêtre.
  2. savoir combien charaters vous pouvez prendre de la chaîne d'origine, qui sera essentiellement largeur 3 fenêtre. Appelez que k .
  3. Selon que vous voulez mettre les points de suspension au milieu ou à la fin de la main droite, soit prendre le premier étage (k / 2) caractères d'un bout, concaténé avec « ... », puis concaténé avec la dernière étage (k / 2) caractères (avec peut-être un caractère plus nécessaire en raison de la division); ou prendre les premiers caractères k, ollowed par "...".

Je pense que la réponse de Smashery est un bon début. Une façon d'obtenir le résultat final serait d'écrire un code de test avec des entrées de test et les résultats souhaités. Une fois que vous avez un bon jeu de configuration des tests, vous pouvez mettre en œuvre votre code de manipulation de chaîne jusqu'à ce que vous obtenez tous vos tests à passer.

  • Calculer la largeur du texte ( basé sur la police)

Si vous utilisez l'API MFC GetOutputTextExtent vous obtiendrez la valeur.

  • si la largeur est supérieure à la donnée largeur spécifique, calculer la largeur de l'ellipse première:

    = ellipseWidth calculer la largeur (...)

  • Supprimer la partie de chaîne avec ellipseWidth largeur de l'extrémité et ajouter ellipse.

    quelque chose comme: Bonjour ...

Pour ceux qui sont intéressés par une routine complète, ceci est mon réponse :

/**
 *  Returns a string abbreviation
 *  example: "hello world" -> "...orld" or "hell..." or "he...rd" or "h...rld"
 *
 *  style:
      0: clip left
      1: clip right
      2: clip middle
      3: pretty middle
 */
CString*
strabbr(
  CDC* pdc,
  const char* s,
  const int area_width,
  int style  )
{
  if (  !pdc || !s || !*s  ) return new CString;

  int len = strlen(s);
  if (  pdc->GetTextExtent(s, len).cx <= area_width  ) return new CString(s);

  int dots_width = pdc->GetTextExtent("...", 3).cx;
  if (  dots_width >= area_width  ) return new CString;

  // My algorithm uses 'left' and 'right' parts of the string, by turns.
  int n = len;
  int m = 1;
  int n_width = 0;
  int m_width = 0;
  int tmpwidth;
  // fromleft indicates where the clip is done so I can 'get' chars from the other part
  bool  fromleft = (style == 3  &&  n % 2 == 0)? false : (style > 0);
  while (  TRUE  ) {
    if (  n_width + m_width + dots_width > area_width  ) break;
    if (  n <= m  ) break; // keep my sanity check (WTF), it should never happen 'cause of the above line

    //  Here are extra 'swap turn' conditions
    if (  style == 3  &&  (!(n & 1))  )
      fromleft = (!fromleft);
    else if (  style < 2  )
      fromleft = (!fromleft); // (1)'disables' turn swapping for styles 0, 1

    if (  fromleft  ) {
      pdc->GetCharWidth(*(s+n-1), *(s+n-1), &tmpwidth);
      n_width += tmpwidth;
      n--;
    }
    else {
      pdc->GetCharWidth(*(s+m-1), *(s+m-1), &tmpwidth);
      m_width += tmpwidth;
      m++;
    }

    fromleft = (!fromleft); // (1)
  }

  if ( fromleft ) m--; else n++;

  // Final steps
  // 1. CString version
  CString*  abbr = new CString;
  abbr->Format("%*.*s...%*.*s", m-1, m-1, s, len-n, len-n, s + n);
  return abbr;

  /* 2. char* version, if you dont want to use CString (efficiency), replace CString with char*,
                       new CString with _strdup("") and use this code for the final steps:

  char* abbr = (char*)malloc(m + (len-n) + 3 +1);
  strncpy(abbr, s, m-1);
  strcpy(abbr + (m-1), "...");
  strncpy(abbr+ (m-1) + 3, s + n, len-n);
  abbr[(m-1) + (len-n) + 3] = 0;
  return abbr;
  */
}

Si vous voulez juste le format ellipsis « standard », ( « Bonjour ... ») vous pouvez utiliser la DrawText (ou le equivalient fonction MFC ) passant fonction DT_END_ELLIPSIS.

Découvrez aussi DT_WORD_ELLIPSIS (tronque un mot qui ne rentre pas dans le rectangle et ajoute ellipses) ou DT_PATH_ELLIPSIS (ce que l'explorateur fait pour afficher les chemins longs).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top