更好的是,或在不同的方式编码类似的函数的优势



我正在为GUI编写代码(用c++),现在我关心的是文本的行组织。我遇到的一个问题是代码变得很长很混乱,我开始进入一个n^2的场景,对于我为文本表示添加的每个选项,我必须写的函数的数量是它的平方。在尝试解决这个问题时,出现了一个特殊的设计选择,我不知道更好的方法,也不知道它们之间的优缺点:

我有两个在流程中非常相似的方法,即迭代相同的对象,考虑相同的约束,但最终在此流程之间执行不同的操作。对于任何感兴趣的人来说,这些方法呈现文本,并确定是否有任何文本由于围绕其他对象或仅仅是在行尾而溢出。

这些函数需要被复制和重写为左、右或居中的文本,它们有不同的流程,所以无论我做什么设计选择都会重复三次。

基本上,我可以继续我现在所拥有的,这是两个独立的方法来处理这些不同的动作,或者我可以将它们合并到一个函数中,其中有if语句来确定是否渲染文本或找出是否有文本溢出。

是否有一种被普遍接受的正确方法来做这件事?否则,需要考虑哪些权衡,哪些迹象可能表明一种方法应该使用而不是另一种方法?有没有别的方法可以做我错过的事?

我已经编辑了几次,试图使它更容易理解,但如果它不是请问我一些问题,这样我可以编辑和解释。我也可以贴出这两种不同方法的源代码,但它们使用了很多函数和对象,要花很长时间才能解释清楚。

//编辑:源代码//

功能1:

无效GUITextLine:: renderleftshift (const GUIRenderInfo&renderInfo) {如果(m_renderLines.empty ())返回;

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 (){

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是两个float结构的std::vector,其中。s_x =渲染可以开始的位置,。s_y =渲染空间的大小-不是,它本质上是'renderLine'的宽度,而不是它的结束位置。

m_text是GUIText对象的std::vector,它包含一个文本字符串和一些数据,如样式、颜色、大小等。它还包含s_font,一个对font对象的引用,它执行渲染,计算字形的宽度,等等。

希望这能澄清一切

在这种情况下没有普遍接受的方法。然而,在任何编程场景中,常见的做法是删除重复的代码。我认为你被如何按方向划分代码卡住了,当方向对结果的改变太大而无法进行这种划分时。在这些情况下,关注三种算法的共同部分,并将它们划分为任务。

当我为MFC复制WinForms流布局控制时,我做了类似的事情。我处理了两种类型的对象:固定位置(你的图片等)和自动位置(你的文字)。

在您提供的示例中,我可以列出示例的常见部分。

Write Line (direction)

  • bool TestPlaceWord (direction)//如果不能将单词放在前一个单词的旁边,则返回false
  • bool WrapPastObject (direction)//如果超出行返回false
  • bool WrapLine (direction)//如果没有足够的新行空间返回false。

无论你面对的是什么方向,这些都将被执行。

最终,每个方向的算法差异太大,无法再简化了。

如何实现访问者模式?听起来这可能就是你想要的东西。

相关内容

  • 没有找到相关文章

最新更新