• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            歲月流轉(zhuǎn),往昔空明

            C++博客 首頁 新隨筆 聯(lián)系 聚合 管理
              118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks
            呃,怎么說呢,這個和vczh的同名文章是互為補充的。這是最近老板的要求,所以就寫了這么個東西。

            vczh的方法生成的樹是sparse的,而我這里樹則要緊湊一些,所使用的坐標系也與之不同。

            效果(看起來挺菜,哇咔咔)


            布局分為水平布局和豎直布局兩個部分,我這里先進行了水平布局再進行了豎直布局。

            一般來講緊湊的樹主要指同級節(jié)點方向上的緊湊性。由于這里樹是父節(jié)點在上,子結(jié)點在下,因此水平方向上的節(jié)點要盡量緊湊。那么便需要我將節(jié)點盡量往左布局。
            如果自左往右布置節(jié)點,那么很顯然,左邊的節(jié)點的位置一旦固定下來就不需要再行調(diào)整。
            同時,為了保持樹的美觀,父節(jié)點的水平中心應當是子結(jié)點的水平中心,這樣子結(jié)點就會對稱分布在父節(jié)點的下方,有利于美觀。
            然而父節(jié)點能正常布局的位置,子結(jié)點可能無法正常布局(子結(jié)點的寬度比父節(jié)點寬得多)。因此我們還需要調(diào)整子結(jié)點的布局。
            由于是自左向右布局的,此時子結(jié)點的左邊的節(jié)點都已經(jīng)確定了,正確的布局很容易便可以通過右移得到。
            為了保證正確性,還需要把父節(jié)點也右移。因為父節(jié)點的右邊沒有布局限制,因而可以放心的右移。這樣一直傳遞到根節(jié)點就可以了。
            那么很明顯,整體來說,布局順序就是,自下而上,自左而右。

            為了讓節(jié)點在布局的時候知道自己能被安排的最左位置,需要為每一層保存最左可布局位置的坐標。
            一旦有節(jié)點被安排妥當,便更新節(jié)點所在層次的最左可布局位置。后來的節(jié)點只要在這個位置的右方布局,就不會與已布置的節(jié)點沖突。

            豎直布局并不復雜,算出每一層的Top就可以了。

            代碼如下:
            using System;
            using System.Collections.Generic;
            using System.Text;
            using System.Drawing;

            //布局算法:
            //采用平行節(jié)點最左布局,父子節(jié)點對中布局的原則。

            /****
             *  void Layout(int lyr)
             *  {
             *     
             *  }
             * 
            ****
            */
            namespace CrowdTree
            {
                
            class LayoutTreeLayerInfo
                {
                    
            //可安排布局的最左坐標
                    private Dictionary<intfloat> lyrLefts = new Dictionary<int,float>();
                    
            private Dictionary<intfloat> heights = new Dictionary<int,float>();

                    
            public void Reset()
                    {
                        lyrLefts 
            = new Dictionary<intfloat>();
                        heights 
            = new Dictionary<intfloat>();
                    }

                    
            public float GetLayoutableLeft(int level)
                    {
                        
            if (lyrLefts.ContainsKey(level))
                        {
                            
            return lyrLefts[level];
                        }
                        
            return 0;
                    }

                    
            public void SetLayoutableLeft(int level, float left)
                    {
                        
            if (lyrLefts.ContainsKey(level))
                        {
                            lyrLefts[level] 
            = Math.Max(left, lyrLefts[level]);
                        }
                        
            else
                        {
                            lyrLefts[level] 
            = Math.Max(0, left);
                        }
                    }

                    
            public void SetLayoutLevelMinHeight(int level, float height)
                    {
                        
            if (heights.ContainsKey(level))
                        {
                            heights[level] 
            = Math.Max(heights[level], height);
                        }
                        
            else
                        {
                            heights[level] 
            = height;
                        }
                    }

                    
            public float GetLayoutLevelMinHeight(int level)
                    {
                        
            if (heights.ContainsKey(level))
                        {
                            
            return heights[level];
                        }
                        
            return 0;
                    }
                }

                
            class LayoutTreeNode
                {
                    
            protected LayoutTree owner_;
                    
            protected LayoutTreeLayerInfo lyrInfo_;
                    
            protected int lyrLevel_;
                    
            protected RectangleF rect_;
                    
            protected List<LayoutTreeNode> children_ = new List<LayoutTreeNode>();

                    
            public int Level
                    {
                        
            get { return lyrLevel_; }
                        
            set { lyrLevel_ = value; }
                    }

                    
            public LayoutTree Owner
                    {
                        
            get { return owner_; }
                        
            set { owner_ = value; }
                    }

                    
            public LayoutTreeLayerInfo LayerInfo
                    {
                        
            set { lyrInfo_ = value; }
                    }

                    
            public List<LayoutTreeNode> Children
                    {
                        
            get { return children_; }
                    }

                    
            public RectangleF Extent
                    {
                        
            get { return rect_; }
                    }

                    
            protected void LayoutHorizontal()
                    {
                        
            //獲取當前節(jié)點能夠排布的最左位置,并預先安排當前節(jié)點。
                        float originLeft = lyrInfo_.GetLayoutableLeft(lyrLevel_);
                        rect_.X 
            = originLeft;

                        
            //根據(jù)當前結(jié)點的坐標,安排子結(jié)點,并需要根據(jù)子結(jié)點的安置情況重新調(diào)整父節(jié)點的安置
                        if (children_.Count > 0)
                        {
                            
            //計算子結(jié)點最左可以安放的位置
                            float childrenTotalWidth = 0.0F;
                            
            foreach (LayoutTreeNode child in children_)
                            {
                                childrenTotalWidth 
            += child.Extent.Width;
                            }
                            childrenTotalWidth 
            += ((children_.Count - 1* owner_.HorizontalSpacer);
                            
            float childLeftest = originLeft + (rect_.Width / 2.0f- (childrenTotalWidth / 2.0F);

                            
            //設(shè)置子結(jié)點安放的最左位
                            lyrInfo_.SetLayoutableLeft(lyrLevel_ + 1, childLeftest);

                            
            //安放子結(jié)點
                            for (int idxChild = 0; idxChild < children_.Count; ++idxChild)
                            {
                                children_[idxChild].LayoutHorizontal();
                            }

                             
            //利用子結(jié)點重新對中安置當前節(jié)點
                            float center = (children_[0].Extent.Left + children_[children_.Count - 1].Extent.Right) / 2.0F;
                            rect_.X 
            = center - rect_.Width / 2.0F;
                        }

                        
            //利用節(jié)點坐標設(shè)置該層其他子結(jié)點所能安放的最左位置,并設(shè)置一下當前層元素的最大高度
                        lyrInfo_.SetLayoutableLeft(lyrLevel_, this.rect_.Right + owner_.HorizontalSpacer);
                        lyrInfo_.SetLayoutLevelMinHeight(lyrLevel_, 
            this.rect_.Height);
                    }

                    
            protected void LayoutVertical(float top)
                    {
                        rect_.Y 
            = top;
                        
            foreach (LayoutTreeNode child in children_)
                        {
                            child.LayoutVertical(top 
            + lyrInfo_.GetLayoutLevelMinHeight(lyrLevel_) + owner_.VerticalSpacer);
                        }
                    }

                    
            public void Layout()
                    {
                        LayoutHorizontal();
                        LayoutVertical(
            0.0f);
                    }

                    
            public virtual void CalculateSize(float maxWidth, Font font, Graphics g)
                    {
                    }

                    
            public virtual void CalculateSizeRecursive(float maxWidth, Font font, Graphics g)
                    {
                    }

                    
            public virtual void Draw(Graphics g) { }
                }

                
            class TextLayoutTreeNode: LayoutTreeNode
                {
                    
            private string text;
                    
            private StringFormat strFmt = new StringFormat();
                    
            private Font font;

                    
            public String Text
                    {
                        
            get { return text; }
                        
            set { text = value; }
                    }

                    
            public override void CalculateSize(float maxWidth, Font font, Graphics g)
                    {
                        strFmt.Alignment 
            = StringAlignment.Center;
                        strFmt.LineAlignment 
            = StringAlignment.Center;

                        rect_.Size 
            = g.MeasureString(text, font, (int)maxWidth, strFmt);
                        
            this.font = font;
                    }

                    
            public override void CalculateSizeRecursive(float maxWidth, Font font, Graphics g)
                    {
                        CalculateSize(maxWidth, font, g);
                        
            foreach (LayoutTreeNode node in children_)
                        {
                            node.CalculateSizeRecursive(maxWidth, font, g);
                        }
                    }

                    
            public override void Draw(Graphics g)
                    {
                        
            //外輪廓,內(nèi)容,連線
                        g.DrawRectangle(Pens.Black, Rectangle.Round(Extent));
                        g.DrawString(text, font, Brushes.Red, Extent);

                        
            foreach (LayoutTreeNode childNode in children_)
                        {
                            
            //繪制斜線
                            
                            
            float childX = (childNode.Extent.Left + childNode.Extent.Right) / 2.0F;
                            
            float childY = childNode.Extent.Top;
                            
                            
            float curX = (Extent.Left + Extent.Right) / 2.0f;
                            
            float curY = Extent.Bottom;

                            g.DrawLine(Pens.Black, 
            new PointF(childX, childY), new PointF(curX, curY));
                        }
                    }
                }

                
            class LayoutTree
                {
                    
            private float vertical_spacer;
                    
            private float horizontal_spacer;

                    
            private LayoutTreeNode root;
                    
            private LayoutTreeLayerInfo lyrInfo = new LayoutTreeLayerInfo();

                    
            public float VerticalSpacer
                    {
                        
            get { return vertical_spacer; }
                        
            set { vertical_spacer = value; }
                    }

                    
            public float HorizontalSpacer
                    {
                        
            get { return horizontal_spacer; }
                        
            set { horizontal_spacer = value; }
                    }

                    
            public LayoutTreeNode Root
                    {
                        
            get { return root; }
                        
            set { root = value; }
                    }

                    
            public void ResetLayout()
                    {
                        lyrInfo.Reset();
                    }

                    
            public T CreateNode<T> (LayoutTreeNode parent) where T:LayoutTreeNode, new()
                    {
                        T retNode 
            = new T();
                        
                        retNode.Owner 
            = this;
                        retNode.LayerInfo 
            = this.lyrInfo;

                        
            if (parent == null)
                        {
                            
            this.root = retNode;
                            retNode.Level 
            = 0;
                        }
                        
            else
                        {
                            parent.Children.Add(retNode);
                            retNode.Level 
            = parent.Level + 1;
                        }
                        
            return retNode;
                    }
                }
            }

            posted on 2008-09-13 12:42 空明流轉(zhuǎn) 閱讀(1593) 評論(2)  編輯 收藏 引用

            評論

            # re: 將樹型數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為圖片并自動排版 2008-09-13 15:49 陳梓瀚(vczh)
            嗯嗯,很好……  回復  更多評論
              

            # re: 將樹型數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為圖片并自動排版 2008-11-11 23:01 李華君(鯉魚潛水)
            路過,加油噢  回復  更多評論
              

            精品久久久久久99人妻| 亚洲国产成人精品91久久久| 亚洲国产精品成人久久| 亚洲成色999久久网站| 亚洲午夜久久久久久噜噜噜| 国产免费久久精品99久久| 久久国产色AV免费看| 一日本道伊人久久综合影| 18岁日韩内射颜射午夜久久成人 | 99久久精品国内| 久久久久久久波多野结衣高潮| 国产一区二区三精品久久久无广告| 久久精品亚洲男人的天堂| 国产女人aaa级久久久级| 久久久久久久综合狠狠综合| 国产精品久久久久久久久免费 | 日韩av无码久久精品免费| 久久久久免费精品国产| 久久精品国产亚洲一区二区| 国产精品久久久久无码av| 狠狠色丁香久久婷婷综合_中| 伊人 久久 精品| 久久人人爽人人爽人人片AV高清| 久久精品视频免费| 国产婷婷成人久久Av免费高清| 久久综合噜噜激激的五月天| 久久最新免费视频| 婷婷伊人久久大香线蕉AV | 久久久久亚洲AV成人网人人网站 | 亚洲国产精品无码久久久秋霞2 | 久久久综合香蕉尹人综合网| 久久精品国产亚洲AV无码娇色 | 一级a性色生活片久久无少妇一级婬片免费放 | 国产一级做a爰片久久毛片| 日韩精品无码久久久久久| 久久久久久久波多野结衣高潮 | 国产亚洲精品自在久久| 久久精品九九亚洲精品| 国产∨亚洲V天堂无码久久久| 久久久久99精品成人片欧美 | 久久狠狠一本精品综合网|