• <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>

            歲月流轉,往昔空明

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

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

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


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

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

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

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

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

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

            /****
             *  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()
                    {
                        
            //獲取當前節點能夠排布的最左位置,并預先安排當前節點。
                        float originLeft = lyrInfo_.GetLayoutableLeft(lyrLevel_);
                        rect_.X 
            = originLeft;

                        
            //根據當前結點的坐標,安排子結點,并需要根據子結點的安置情況重新調整父節點的安置
                        if (children_.Count > 0)
                        {
                            
            //計算子結點最左可以安放的位置
                            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);

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

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

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

                        
            //利用節點坐標設置該層其他子結點所能安放的最左位置,并設置一下當前層元素的最大高度
                        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)
                    {
                        
            //外輪廓,內容,連線
                        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 空明流轉 閱讀(1593) 評論(2)  編輯 收藏 引用

            評論

            # re: 將樹型數據結構轉換為圖片并自動排版 2008-09-13 15:49 陳梓瀚(vczh)
            嗯嗯,很好……  回復  更多評論
              

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

            久久久久国色AV免费观看| 欧美久久久久久精选9999| 久久综合色区| 亚洲精品无码专区久久同性男 | 亚洲级αV无码毛片久久精品| 少妇久久久久久被弄到高潮| 超级97碰碰碰碰久久久久最新| 国产A级毛片久久久精品毛片| 久久99国产综合精品| 日产久久强奸免费的看| 99久久精品国产高清一区二区| 香蕉久久夜色精品国产小说| 久久精品国产AV一区二区三区| 精品国产福利久久久| 亚洲天堂久久久| 国产精品成人久久久久久久| 亚洲AV无码久久精品狠狠爱浪潮| 精品久久久无码中文字幕| 久久亚洲精精品中文字幕| 久久久受www免费人成| 99久久婷婷国产综合亚洲| 久久国产色av免费看| 99久久综合狠狠综合久久| 久久久久久久97| 久久亚洲精精品中文字幕| 亚洲国产香蕉人人爽成AV片久久 | 精品久久久久久久中文字幕| 伊人久久综合精品无码AV专区| 日本亚洲色大成网站WWW久久 | 久久久久免费精品国产| 久久久久99精品成人片三人毛片 | 国产精品久久久久一区二区三区| 久久亚洲AV成人出白浆无码国产| 伊人久久国产免费观看视频| 久久亚洲色一区二区三区| 91亚洲国产成人久久精品| 2021少妇久久久久久久久久| 亚洲AV日韩精品久久久久久 | 久久免费精品视频| 国产99久久精品一区二区| 97精品国产91久久久久久|