0

私は (C++ で) GUI のコードを書いていますが、今は行単位でのテキストの構成に関心があります。私が抱えている問題の 1 つは、コードが非常に長くなり、混乱を招くことです。テキスト プレゼンテーションに追加するすべてのオプションに対して、必要な関数の数が ^2 のシナリオに陥り始めています。 write はその 2 乗です。これに対処しようとして、特定の設計上の選択肢が出てきましたが、より良い方法、またはそれらの間の長所または短所の程度はわかりません。

フローが非常に似ている 2 つのメソッドがあります。つまり、同じ制約を考慮して同じオブジェクトを反復しますが、最終的にはこのフロー間で異なる操作を実行します。誰にとっても興味深いことに、メソッドはテキストをレンダリングし、テキストが他のオブジェクトの周りにラップされているか、単に行の終わりにあるためにテキストが行からオーバーフローしているかどうかをそれぞれ判断します。

これらの関数は、フローが異なる左、右、または中央のテキスト用にコピーして書き直す必要があるため、私が行うデザインの選択は 3 回繰り返されます。

基本的には、これらの異なるアクションを処理するための 2 つの別々の方法である、現在持っているものを継続することも、それらを 1 つの関数にマージすることもできます。テキストオーバーフロー。

これについて一般的に受け入れられている正しい方法はありますか?それ以外の場合、関係するトレードオフは何ですか?ある方法を他の方法よりも使用する必要があることを示す可能性のある兆候は何ですか? 私が見逃したことを行う他の方法はありますか?

私はこれを数回編集して理解しやすくしましたが、そうでない場合は、編集して説明できるようにいくつか質問してください. 2 つの異なるメソッドのソース コードを投稿することもできますが、それらは説明に時間がかかりすぎる多くの関数とオブジェクトを使用しています。

// 編集: ソースコード //

機能 1:

void GUITextLine::renderLeftShifted(const GUIRenderInfo& renderInfo) { if(m_renderLines.empty()) return;

Uint iL = 0;

Array2t<float> renderCoords;
renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[0].s_x;
renderCoords.s_y = renderInfo.s_offset.s_y + m_y;
float remainingPixelsInLine = m_renderLines[0].s_y;

for (Uint iTO= 0;iTO != m_text.size();++iTO)
{
    if(m_text[iTO].s_pixelWidth <= remainingPixelsInLine)
    {
        string preview = m_text[iTO].s_string;

        m_text[iTO].render(&renderCoords);
        remainingPixelsInLine -= m_text[iTO].s_pixelWidth;
    }

    else
    {
        FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();

        float characterWidth = 0;

        Uint iFirstCharacterOfRenderLine = 0;

        for(Uint iC = 0;;++iC)
        {
            if(iC == m_text[iTO].s_string.size()) 
            {
                // wrap up
                string renderPart = m_text[iTO].s_string;
                renderPart.erase(iC, renderPart.size());
                renderPart.erase(0, iFirstCharacterOfRenderLine);
                m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
                    &renderCoords);
                break;
            }

            characterWidth += m_text[iTO].s_font->getWidthOfGlyph(intData,
                m_text[iTO].s_string[iC]);

            if(characterWidth > remainingPixelsInLine) 
            {
                // Can't push in the last character
                // No more space in this line

                // First though, render what we already have:

                string renderPart = m_text[iTO].s_string;
                renderPart.erase(iC, renderPart.size());
                renderPart.erase(0, iFirstCharacterOfRenderLine);
                m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
                    &renderCoords);


                if(++iL != m_renderLines.size())
                {
                    remainingPixelsInLine = m_renderLines[iL].s_y;
                    renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[iL].s_x;

                    // Cool, so now try rendering this character again
                    --iC;
                    iFirstCharacterOfRenderLine = iC;
                    characterWidth = 0;
                }
                else
                {

                    // Quit

                    break;
                }
            }
        }
    }
}

// Done! }

機能 2:

ベクトル GUITextLine::recalculateWrappingContraints_LeftShift() { m_pixelsOfCharacters = 0;

float pixelsRemaining = m_renderLines[0].s_y;

Uint iRL = 0;

// Go through every text object, fiting them into render lines
for(Uint iTO = 0;iTO != m_text.size();++iTO)
{
    // If an entire text object fits in a single line
    if(pixelsRemaining >= m_text[iTO].s_pixelWidth)
    {
        pixelsRemaining -= m_text[iTO].s_pixelWidth;
        m_pixelsOfCharacters += m_text[iTO].s_pixelWidth;
    }

    // Otherwise, character by character
    else
    {
        // Get some data now we don't get it every function call
        FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();

        for(Uint iC = 0; iC != m_text[iTO].s_string.size();++iC)
        {
            float characterWidth = m_text[iTO].s_font->getWidthOfGlyph(intData, '-');

            if(characterWidth < pixelsRemaining)
            {
                pixelsRemaining -= characterWidth;
                m_pixelsOfCharacters += characterWidth;
            }

            else // End of render line! 
            {
                m_pixelsOfWrapperCharacters += pixelsRemaining; // we might track how much wrapping px we use

                // If this is true, then we ran out of render lines before we ran out of text. Means we have some overflow to return
                if(++iRL == m_renderLines.size())
                {
                    return harvestOverflowFrom(iTO, iC);
                }

                else
                {
                    pixelsRemaining = m_renderLines[iRL].s_y;
                }
            }
        }

    }
}

vector<GUIText> emptyOverflow;
return emptyOverflow; }

したがって、基本的に render() は renderCoordinates をパラメーターとして取り、そこからレンダリングする必要がある場所のグローバル位置を取得します。calcWrappingConstraints は、割り当てられたスペースを超えるオブジェクト内のテキストの量を計算し、そのテキストを関数として返します。

m_renderLines は 2 つの float 構造の std::vector です。ここで、.s_x = レンダリングを開始できる場所、.s_y = レンダリングのためのスペースの大きさ - ではなく、'renderLine' の本質的な幅であり、終了場所ではありません。

m_text は、テキストの文字列と、スタイル、色、サイズなどのデータを含む GUIText オブジェクトの std::vector です。また、レンダリングを実行したり、グリフの幅を計算したりするフォント オブジェクトへの参照である s_font の下にも含まれています。

うまくいけば、これで問題が解決します。

4

2 に答える 2

1

ビジターパターンの実装はどうですか?それはあなたが求めているようなものかもしれないように思えます。

于 2011-12-02T15:04:19.173 に答える
1

この場合、一般的に受け入れられている方法はありません。ただし、どのプログラミング シナリオでも一般的な方法は、重複したコードを削除することです。方向によって結果が変わりすぎてこの分割を行うことができない場合、コードを direction で分割する方法に行き詰まっていると思います。このような場合は、3 つのアルゴリズムの共通部分に注目し、それらをタスクに分割します。

MFC の WinForms フロー レイアウト コントロールを複製したときに、同様のことを行いました。固定位置 (写真など) と自動位置 (言葉) の 2 種類のオブジェクトを扱いました。

あなたが提供した例では、あなたの例の共通部分をリストできます。

行を書く (方向)

  • bool TestPlaceWord (direction) // 前の単語の隣に単語を配置できない場合は false を返します
  • bool WrapPastObject (direction) // 行外の場合は false を返します
  • bool WrapLine (direction) // 新しい行のスペースがなくなると false を返します。

これらのそれぞれは、あなたが直面している方向に関係なく実行されます.

最終的に、各方向のアルゴリズムはあまりにも異なっているため、それ以上単純化することはできません。

于 2011-12-02T15:21:32.167 に答える