2009-12-02 4 views
2

J'ai un petit puzzle de dessin de texte sous Win32. J'essaie de dessiner quelques instructions pour les utilisateurs de mon application en haut de la fenêtre.Puzzle de dessin de texte Win32

S'il vous plaît se référer à la fenêtre suivante (j'ai changé la couleur de fond sur le texte afin que vous puissiez voir les limites)

Demonstration http://billy-oneal.com/forums/12-2-2009%203-46-15%20PM.png

J'utilise actuellement DrawTextEx pour dessiner le texte à ma fenêtre , mais le problème est qu'il ne remplit pas tout le RECTangle que je lui donne. dessin pas que la zone est très bien, jusqu'à ce que la fenêtre redimensionne:

Demonstration after resize http://billy-oneal.com/forums/12-2-2009%203-51-45%20PM.png

Lorsque le texte est de nouveau enveloppé en raison de la taille de la fenêtre, car DrawTextEx ne disparaît pas, il est de fond, ces objets sont des restes.

J'ai essayé d'utiliser FillRect pour remplir la zone derrière l'appel de dessin de texte, ce qui élimine les artefacts visuels, mais fait clignoter le texte constamment, car il est complètement effacé et complètement redessiné à l'affichage.

Des idées sur la façon dont on pourrait dessiner la zone ne contenant pas de texte avec la couleur de fond?

EDIT: Je voudrais éviter d'avoir à double tampon le formulaire si à l'application possible.

EDIT2: J'ai résolu le problème en redessinant seulement le texte lorsque je détecte que l'habillage change pendant un redimensionnement.

+0

ExtTextOut + ETO_OPAQUE (https://msdn.microsoft.com/en-us/library/dd162713(v=vs.85).aspx) –

Répondre

2

Eh bien, puisque personne ne semble savoir ce qu'il faut faire à ce sujet, je mis en œuvre ainsi:

std::vector<std::wstring> wrapString(HDC hDC, const std::wstring& text, const RECT& targetRect, HFONT font) 
{ 
    std::vector<std::wstring> result; 
    RECT targetRectangle; 
    CopyRect(&targetRectangle, &targetRect); 

    //Calculate the width of the bounding rectangle. 
    int maxWidth = targetRectangle.right - targetRectangle.left; 

    //Draw the lines one at a time 
    std::wstring currentLine; 
    for(std::wstring::const_iterator it = text.begin(); it != text.end(); currentLine.push_back(*it), it++) 
    { 
     if(*it == L'\r' || *it == L'\n') 
     { //Hard return 
      while(it != text.end() && (*it == L'\r' || *it == L'\n')) it++; 
      result.push_back(currentLine); 
      currentLine.clear(); 
     } 
     else 
     { //Check for soft return 
      SIZE sizeStruct; 
      GetTextExtentPoint32(hDC, currentLine.c_str(), static_cast<int>(currentLine.length()), &sizeStruct); 
      if (sizeStruct.cx > maxWidth) 
      { 
       std::wstring::size_type lineLength = currentLine.find_last_of(L' '); 
       if (lineLength == currentLine.npos) 
       { //Word is longer than a line. 
        for(;it != text.end() && !iswspace(*it);it++) currentLine.push_back(*it); 
       } 
       else 
       { //Clip word to line. 
        //Backtrack our scan of the source text. 
        it -= currentLine.length() - lineLength - 1; 
        //Remove the clipped word 
        currentLine.erase(lineLength); 
       } 
       result.push_back(currentLine); 
       currentLine.clear(); 
      } 
     } 
    } 
    //Last remaining text. 
    result.push_back(currentLine); 
    return result; 
} 

void DrawInstructionsWithFilledBackground(HDC hDC, const std::wstring& text, RECT& targetRectangle, HFONT font, COLORREF backgroundColor) 
{ 
    //Set up our background color. 
    int dcIdx = SaveDC(hDC); 
    HBRUSH backgroundBrush = CreateSolidBrush(backgroundColor); 
    SelectObject(hDC, backgroundBrush); 
    SelectObject(hDC, font); 
    SetBkColor(hDC, backgroundColor); 

    std::vector<std::wstring> lines(wrapString(hDC, text, targetRectangle, font)); 
    for(std::vector<std::wstring>::const_iterator it = lines.begin(); it!=lines.end(); it++) 
    { 
     RECT backgroundRect = targetRectangle; 
     DrawText(hDC, const_cast<LPWSTR>(it->c_str()), static_cast<int>(it->length()), &backgroundRect, DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE); 
     backgroundRect.left = backgroundRect.right; 
     backgroundRect.right = targetRectangle.right; 
     if (backgroundRect.right >= backgroundRect.left) 
     FillRect(hDC, &backgroundRect, backgroundBrush); 
     ExtTextOut(hDC, targetRectangle.left, targetRectangle.top, ETO_OPAQUE, NULL, it->c_str(), static_cast<UINT>(it->length()), NULL); 
     targetRectangle.top += backgroundRect.bottom - backgroundRect.top; 
    } 
    instructionsWrap = lines; 
    //Restore the DC to it's former glory. 
    RestoreDC(hDC, dcIdx); 
    DeleteObject(backgroundBrush); 
} 
4

Utilisez un double tampon? Dessinez tout sur une image bitmap et dessinez le bitmap sur la fenêtre.

Le scintillement est généralement un problème de double mise en mémoire tampon.

+0

Cela fonctionnerait, mais je voudrais éviter d'avoir à double buffer tout pour une opération aussi simple. J'ai travaillé très dur sur le reste de l'application pour ne pas avoir besoin de double buffer. Il semble dommage de gaspiller tout ça pour quelque chose d'aussi simple. –

+0

La CPU est-elle la ressource limitée ou la mémoire? Dans le cas de la première, vous pouvez être très restrictif sur * quand * pour mettre à jour votre fenêtre, c'est-à-dire pas plus souvent que toutes les 40ms. Si la mémoire est votre ressource limitée, je pense que nous devrions en savoir plus sur vos limites matérielles pour résoudre votre cas. – Pedery

2

Il existe de nombreuses solutions possibles et sans voir votre code, il est difficile de dire quelle méthode serait mieux que je suggère aurait donc jeter un oeil à this article on flicker free drawing

+0

J'ai lu cet article - le reste de l'application suit les directives ici. Le texte est la seule chose qui scintille. Tout le reste est bien. –

+0

Voulez-vous dire un scintillement constant, ou seulement pendant le redimensionnement? – BarrettJ

+0

Uniquement lors du redimensionnement. –

2

SetBkMode + SetBkColor?

+0

L'arrière-plan est tracé correctement derrière le texte.J'ai besoin d'un moyen pour que la fonction dessine aussi l'arrière-plan à gauche de chaque ligne pour remplir le rectangle où vont les instructions. –

-1

Get/Calculer le rect utilisé par l'appel DrawText et clip avec quelque chose comme ExcludeClipRect avant d'appeler FillRect

+1

Obtenir/Calculer le rect utilisé par le DrawText <- Vous voulez m'éclairer sur la façon dont une forme irrégulière peut être représentée comme un RECT? –

+0

Vous avez déjà un RECT que vous transmettez à DrawText (en l'appelant d'abord avec DT_CALCRECT ou une valeur "codée en dur") – Anders