Отображение узла HTML в дереве - проблема высоты - PullRequest
1 голос
/ 08 февраля 2009

Гррр так близко, но все еще терпит неудачу ...

Я отображаю это дерево во Flex, которое содержит два типа узлов:

  1. Обычные узлы, которые обычно отображаются как текст (потому что они есть!)
  2. Богатые (HTML) узлы - вот где все искажается

Обратите внимание, что моя проблема в том, что когда я динамически добавляю новый (HTML) узел к моему дереву.


Итак ... Как отобразить узлы HTML?

  1. Я подкласс TreeItemRenderer
  2. В этом подклассе я переопределяю set data () и добавляю текстовый дочерний элемент для моего рендерера

Поэтому у меня теперь есть:

[иконка] [метка]

[текстовый компонент]

Почему?

Метка по умолчанию - это чистый текстовый компонент, не поддерживающий HTML, поэтому дополнительный компонент: я хочу отобразить нового парня и забыть метку по умолчанию.

  1. (продолжение) Я переопределяю updateDisplayList() и, если узел богатый, я устанавливаю высоту метки на ноль, устанавливаю x и y моего компонента на label'x и и y.

Так ... что мне не хватает? Ах, да: мне нужно установить высоту моего узла, поскольку текст HTML может быть больше или меньше, чем его текстовый аналог.

  1. (продолжение) Я переопределяю measure()
  2. Если мой узел не богатый, я просто вызываю super.measure () и возвращаю
  3. Если оно равно , то я задаю ширину моего html-компонента (htmlComponent.width =licitWidth - super.label.x;) и его высота должна автоматически вычисляться.

Это дает мне довольно надежный ненадежный результат!

Когда я складываю / разворачиваю свое дерево, каждый раз, кажется, я получаю правильную высоту для моего HTML-узла. В другой раз я получаю высоту '4', которая является только заполнением компонента HTML без содержимого.

Я знаю, что я должен делать что-то довольно глупое здесь ... но я не уверен, что. Я опубликую свой код, если мой бессвязный текст слишком бессвязен, чтобы что-то понимать ...

**** РЕДАКТИРОВАТЬ: вот исходный код моего рендерера Как видите, только узлы 'notes' используют HTML. Я добавляю дочерний элемент htmlComponent, который будет отображать форматированный текст, в то время как метка по умолчанию имеет нулевой размер и исчезает. Это определенно очень сырой код, так как он в процессе!

    package com.voilaweb.tfd
{
    import mx.collections.*;
    import mx.controls.Text;
    import mx.controls.treeClasses.*;
    import mx.core.UITextField;
    import mx.core.UIComponent;
    import flash.text.TextLineMetrics;

    public class OutlinerRenderer extends TreeItemRenderer
    {
        private function get is_note():Boolean
        {
            return ('outlinerNodeNote' == XML(super.data).name().localName);
        }

        override public function set data(value:Object):void
        {
            super.data = value;
            var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
            if(!htmlComponent)
            {
                htmlComponent = new Text();
                htmlComponent.name = "htmlComponent";
                addChild(htmlComponent);
            }
            if(is_note)
                htmlComponent.htmlText = XML(super.data).attribute('nodeText');
            else
                htmlComponent.htmlText = null;
            setStyle('verticalAlign', 'top');
        }

 /*
  * Today we've learnt a valuable lesson: there is no guarantee of when createChildren() will be invoked.
  * Better be dirty and add children in set data()
        override protected function createChildren():void
        {
            super.createChildren();
            var htmlComponent:Text = new Text();
            htmlComponent.name = "htmlComponent";
            addChild(htmlComponent);
        }
*/
        override protected function measure():void
        {
          if(is_note)
          {
            super.measure();
            var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
            //Setting the width of the description field
            //causes the height calculation to happen
            htmlComponent.width = explicitWidth - super.label.x;
            //We add the measuredHeight to the renderers measured height
            //measuredHeight += (htmlComponent.measuredHeight - label.measuredHeight);
            // Note the silly trick here...hopefully in the future I figure out how to avoid it
            //
            // Here is what happens: we check if measuredHeight is equal to decoration such as margin, insets...rather than that + some height
            // If so, then we need to come up with an actual height which we do by adding textHeight to this height

            // Note that I care about text being equal to margin etc but do not have proper access to these
            // For instance UITextField.TEXT_HEIGHT_PADDING == 4 but is not accessible
            // I am going to check if "<10" that will cover this case...
            trace("For text " + htmlComponent.htmlText);
            trace("width = " + htmlComponent.getExplicitOrMeasuredWidth()+" x height = " + htmlComponent.getExplicitOrMeasuredHeight());
            var m:TextLineMetrics = htmlComponent.measureHTMLText(htmlComponent.htmlText);
            //if(10 > htmlComponent.measuredHeight && !isNaN(htmlComponent.explicitHeight))
            //htmlComponent.explicitHeight = m.height + htmlComponent.measuredHeight;
            //if(htmlComponent.measuredHeight < 10) htmlComponent.explicitHeight = 50;

            //measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - super.label.getExplicitOrMeasuredHeight());
            measuredHeight += (htmlComponent.getExplicitOrMeasuredHeight() - label.getExplicitOrMeasuredHeight());
            trace("m:"+m.height+" Height: " + htmlComponent.getExplicitOrMeasuredHeight());
          }
          else
          {
            super.measure();
          }
        }     

        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
        {
            super.updateDisplayList(unscaledWidth, unscaledHeight);
            label.height = label.getExplicitOrMeasuredHeight(); // If you tell me my height, then I shall use my variable height!

            graphics.clear();

            if(is_note)
            {
                label.height = 0;
                var htmlComponent:Text = super.getChildByName("htmlComponent") as Text;
                htmlComponent.x = label.x;
                htmlComponent.y = label.y;
                htmlComponent.height = htmlComponent.getExplicitOrMeasuredHeight();

                graphics.beginFill(0x555555);
                graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
                graphics.endFill();
            }

            var complete:XMLList = XML(super.data).attribute('complete');
            if(complete.length() > 0 && true == complete[0])
            {
                var startx:Number = data ? TreeListData(listData).indent : 0;
                if(disclosureIcon)
                    startx += disclosureIcon.measuredWidth;
                if(icon)
                    startx += icon.measuredWidth;
                graphics.lineStyle(3, getStyle("color"));
                var y:Number = label.y + label.getExplicitOrMeasuredHeight() / 2;
                graphics.moveTo(startx, y);
                graphics.lineTo(startx + label.getExplicitOrMeasuredWidth(), y);
            }
        }
    }
}

Ответы [ 3 ]

1 голос
/ 18 марта 2010

Вы сделали ложное предположение о компоненте метки в рендере по умолчанию - он способен отображать HTML-контент. У меня этот рендерер работает:

public class HtmlTreeItemRenderer extends TreeItemRenderer {
    override protected function commitProperties():void {
        super.commitProperties();
        label.htmlText = data ? listData.label : "";
        invalidateDisplayList();
    }
}
0 голосов
/ 12 декабря 2009

Попробуй.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
           width="100%" height="100%" verticalScrollPolicy="off"
           horizontalScrollPolicy="off">

<mx:Script>
   <![CDATA[
      import mx.core.UITextField;

      private var texto:UITextField;

      override protected function createChildren():void
      {
         super.createChildren();

         texto = new UITextField();

         texto.setColor(0xFFFFFF);

         texto.multiline = true;
         texto.wordWrap = true;

         texto.autoSize = TextFieldAutoSize.LEFT;

         this.addChild(texto);

         //texto.text = data.title;
      }


      override public function set data(value:Object):void
      {
         super.data = value;
         if (value)
         {
          texto.htmlText = value.title;
          this.invalidateDisplayList();
         }
      }

      override protected function measure():void
      {
        super.measure();
      }

      override protected function updateDisplayList(unscaledWidth:Number,
                                       unscaledHeight:Number):void
      {
         super.updateDisplayList(unscaledWidth, unscaledHeight);

         if (texto)
          texto.width = this.width;
      }
   ]]>
</mx:Script>   

</mx:Canvas>
0 голосов
/ 11 февраля 2009

Конечно, было бы полезно, если бы вы могли опубликовать некоторый код.

Мне было интересно, почему вы используете собственный рендеринг HTML. Это потому, что вы хотите отобразить значок рядом с ярлыком, так как упоминаете [icon] [label]? Если это так, вам, вероятно, лучше использовать iconField или iconFunction.

Еще одна вещь, которая приходит на ум, это свойство variableRowHeight. Возможно, вам придется установить это, если ваши узлы имеют разную высоту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...