zoukankan      html  css  js  c++  java
  • ColorListBox

    介绍 还有另一个颜色 列表框吗?有很多文章是关于列表框控件着色和代码示例的。本文与其他文章的不同之处在于,所有这些文章及其附带的代码都只是演示。做出自己的判断: 水平滚动条消失了。只有小于控制宽度的固定长度的字符串可以被显示。如果控件的大小被调整了呢? 如果您尝试使用鼠标滚轮,您可能会注意到,当滚动滚轮移动时,所选项目会不规律地上下移动。 可重写的方法OnPaint()和OnPaintBackGround()根本不起作用。他们对这些事件不感兴趣。背景只能通过Windows消息绘制。 . net ListBox控件工作得很好,但是作为进一步派生的基类,它从根本上是有缺陷的。这个问题的根源在于Windows API的列表框。。net列表框只是这个控件的包装。解决方案是什么?我们可以从头开始编写控件,或者尝试使用现有的控件并尝试解决这些问题。基本上,这篇文章是一本关于如何克服这些问题的手册。 的代码 控件是从UserControl派生的。它有一个列表框和一个水平滚动条作为它的成员。为了使它的所有者绘制,我们需要一个绘制项目的方法。在此之前,原始控件的DrawMode必须设置为DrawMode. ownerdrawvariable。这将禁用该项的原始绘制,并且方法MeasureItem()将被激活。DrawItem代码如下。除了几行之外,它或多或少是简单的。隐藏,收缩,复制Code

    protected void DrawListBoxItem(Graphics g, 
                Rectangle bounds, int Index, bool selected)
    {    
        if (Index == -1)
            return;
    
        if (bounds.Top < 0)
            return;
    
        if (bounds.Bottom > (listBox.Bottom + listBox.ItemHeight))
            return;
    
        Graphics gr = null;
    
        if (UseDoubleBuffering)
        {
            gr = DoubleBuff.BuffGraph;
        }
        else
        {
            gr = g;
        }
    
        int IconIndex;
        Color TextColor;
        string Text = GetObjString(Index, out IconIndex, out TextColor);
    
        Image img = null;
    
        if (selected)
        {
            if (listBox.Focused)
            {
                using(Brush b = new SolidBrush(_HighLightColor)) 
                {
                    gr.FillRectangle(b, 0, 
                        bounds.Top + 1, listBox.Width, bounds.Height - 1);
                }
            }
            else
            {
                using(Brush b = new SolidBrush(Color.Gainsboro))
                {
                    gr.FillRectangle(b, 0, 
                        bounds.Top, listBox.Width, bounds.Height);
                }
            }
    
            if (listBox.Focused)
            {
                using(Pen p = new Pen(Color.RoyalBlue))
                {
                    gr.DrawRectangle(p, new Rectangle(0, 
                        bounds.Top, listBox.Width, bounds.Height));
                }
            }
        }
    
        if (IconIndex != -1 && imageList1 != null) 
        {
            img = imageList1.Images[IconIndex];
            Rectangle imgRect = new Rectangle(bounds.Left - DrawingPos, 
                                bounds.Top , img.Width, img.Height);
            gr.DrawImage(img, imgRect, 0, 0, img.Width, 
                                img.Height, GraphicsUnit.Pixel); 
        }
    
        using(Brush b = new SolidBrush(TextColor))
        {
            gr.DrawString(Text, this.Font, b, 
                new Point(bounds.Left - DrawingPos + 
                XOffset_forIcon + 2, bounds.Top + 2));    
        }
    }

    下面是用于激活和调整滚动条大小的代码:复制Code

    private void ResizeListBoxAndHScrollBar()
    {
        listBox.Width = this.Width;
    
        if (listBox.Width > (MaxStrignLen + XOffset_forIcon + 15))
        {
            hScrollBar1.Visible = false;
            listBox.Height = this.Height;
        }
        else
        {
            hScrollBar1.Height = 18;
            listBox.Height = this.Height - this.hScrollBar1.Height;
            hScrollBar1.Top = this.Height - this.hScrollBar1.Height - 1;
            hScrollBar1.Width = this.Width;    
    
            hScrollBar1.Visible = true;
            hScrollBar1.Minimum = 0;
            hScrollBar1.Maximum = MaxStrignLen  + XOffset_forIcon + 15;
            hScrollBar1.LargeChange = this.listBox.Width; 
            hScrollBar1.Value = 0;
        }        
    }

    这是所有吗?现在我们有了项目绘制和滚动条的代码。不幸的是,它更加复杂,这就是为什么ColorListBox的其他实现没有在商业应用程序中使用的原因。我们刚刚创建的控件在调整大小或有时水平滚动条移动时闪烁。无论您的应用程序有多好,只要GUI上有一个闪烁的控件,就会使产品看起来不专业。它破坏了整个画面。 如何才能解决这个问题呢?有一种众所周知的消除闪烁的技术。它被称为双缓冲。其思想是,实际的绘图发生在内存中,当它完成时,图像被复制到GUI中。让我们使用这个技巧。为此,我们编写了《双刃剑》。它从控件创建一个位图图像,并在需要时刷新它。隐藏,收缩,复制Code

    public class DoubleBuffer : IDisposable
    {
        private    Graphics    graphics;
        private Bitmap        bitmap;
        private Control        _ParentCtl;
        private Graphics    CtlGraphics;
    
        public DoubleBuffer(Control ParentCtl)
        {
            _ParentCtl = ParentCtl;
            bitmap    = new Bitmap(_ParentCtl.Width , _ParentCtl.Height);
            graphics = Graphics.FromImage(bitmap);
            CtlGraphics = _ParentCtl.CreateGraphics();
        }
    
        public void CheckIfRefreshBufferRequired()
        {
            if ((_ParentCtl.Width != bitmap.Width) || 
                (_ParentCtl.Height != bitmap.Height))
            {
                RefreshBuffer();
            }
        }
    
        public void RefreshBuffer()
        {
            if (_ParentCtl == null)
                return;
    
            if (_ParentCtl.Width == 0 || _ParentCtl.Height == 0)// restoring event
                return;
    
            if (bitmap != null)
            {
                bitmap.Dispose();
                bitmap = null;
            }
    
            if (graphics != null)
            {
                graphics.Dispose();
                graphics = null;
            }
    
            bitmap    = new Bitmap(_ParentCtl.Width, _ParentCtl.Height);
            graphics = Graphics.FromImage(bitmap);
    
            if (CtlGraphics != null)
            {
                CtlGraphics.Dispose(); 
            }
            
            CtlGraphics = _ParentCtl.CreateGraphics();
        }
    
        public void Render()
        {
            CtlGraphics.DrawImage(
                bitmap, 
                _ParentCtl.Bounds,
                0, 
                0, 
                _ParentCtl.Width, 
                _ParentCtl.Height, 
                GraphicsUnit.Pixel);
        }
    
        public Graphics BuffGraph 
        {
            get 
            { 
                return graphics; 
            }
        }    
    
        #region IDisposable Members
    
        public void Dispose()
        {
            if (bitmap != null)
            {
                bitmap.Dispose(); 
            }
    
            if (graphics != null)
            {
                graphics.Dispose();  
            }
    
            if (CtlGraphics != null)
            {
                CtlGraphics.Dispose(); 
            }
        }
    
        #endregion
    }

    现在我们不直接在GUI上绘制项目。我们把它们画在一个基于内存的位图上。但我们的控制系统仍在闪烁。为什么?还有一个步骤——原始控件重新绘制背景。但是如何停止这样做呢?正如我前面提到的,overridable方法OnPaintBackGround()没有连接到事件,重写它们不会执行任何操作。鉴于以上所述,阻止原始背景绘制的唯一方法是在WndProc()方法中阻止WM_ERASEBKGND事件。我们必须重写专门为该类创建的WndProc()。 车轮滚动 鼠标滚轮事件处理也应该得到修复。最明智的方法是阻止WM_MOUSEWHEEL事件并将其转换为垂直滚动条事件。使用Windows API SendMessage()直接发送新创建的事件。隐藏,收缩,复制Code

    private void GetXY(IntPtr Param, out int X, out int Y)
    {
        byte[] byts = System.BitConverter.GetBytes((int)Param);
        X = BitConverter.ToInt16(byts, 0);
        Y = BitConverter.ToInt16(byts, 2);
    }
    
    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case (int)Msg.WM_ERASEBKGND:
    
                if (_BlockEraseBackGnd)
                {
                    return;
                }
            
                break;
    
            case (int)Msg.WM_MOUSEWHEEL:
    
                int X;
                int Y;
    
                _BlockEraseBackGnd = false;
    
                GetXY(m.WParam, out X, out Y);
    
                if (Y >0)
                {
                    SendMessage(this.Handle, (int)Msg.WM_VSCROLL, 
                                      (IntPtr)SB_LINEUP,IntPtr.Zero);
                }
                else
                {
                    SendMessage(this.Handle, (int)Msg.WM_VSCROLL, 
                                      (IntPtr)SB_LINEDOWN,IntPtr.Zero);
                }
                return;
    
            case (int)Msg.WM_VSCROLL:                
            case (int)Msg.WM_KEYDOWN:
            
                _BlockEraseBackGnd = false;
    
                if (UpdateEv != null)
                {
                    UpdateEv(null, null); 
                }
                break;
        }
    
        base.WndProc (ref m);
    
    }

    填充控制 填充控件的主要方法是public void AddItem(对象项,int IconIndex, Color TxtColor)。其中项可以是任何具有ToString()方法的类。您可以创建自己的类并重写ToString()方法,也可以简单地使用字符串。隐藏,复制Code

    public void AddItem(object Item, int IconIndex, Color TxtColor)
    {
        ObjectHolder oh = new ObjectHolder(IconIndex, Item, TxtColor);
        
        UseDoubleBuffering = false;
        listBox.Items.Add(oh);    
        ResizeListBoxAndHScrollBar();
    }

    内部列表框和HScrollBar是公开的,可以访问它们。 最后的联系 新的控件现在可以正常工作了。剩下的最后一件事是控件的外观。在Windows 2000上,它看起来很正常,但在Windows XP上,它看起来像下面的截图: 垂直滚动条有XP风格,但水平滚动条有标准外观。要更改这一点,必须应用清单。基本上,清单文件指定公共控件驻留的DLL。隐藏,收缩,复制Code

    <?xmlversion="1.0"encoding="UTF-8"standalone="yes"?>
    <assemblyxmlns="urn:schemas-microsoft-com:asm.v1"manifestVersion="1.0"> 
    <assemblyIdentityversion="1.0.0.0"processorArchitecture="X86"name=""type="win32"/> 
    <description>Your app description here</description> 
    <dependency> 
        <dependentAssembly> 
            <assemblyIdentitytype="win32"name="Microsoft.Windows.Common-Controls"version="6.0.0.0"processorArchitecture="X86"publicKeyToken="6595b64144ccf1df"language="*"/> 
        </dependentAssembly> 
    </dependency> 
    </assembly>

    清单文件必须位于应用程序启动的同一目录中。为了避免在run目录中出现这个不方便的文件,清单可以直接注入到可执行程序集中。为了自动化此任务,已经编写了实用程序dotnetmanifest .exe。您可以使用此实用程序将清单直接注入程序。 控件的完整源代码和最新二进制文件可以在这里的工具箱部分以及dotnetmanifest .exe中找到。 本文转载于:http://www.diyabc.com/frontweb/news366.html

  • 相关阅读:
    Flex4之关于Embed外部资源的使用方法总结
    Flex tree的开发 后台数据连接
    Flex4之Tree开发
    Flex自定义组件开发
    解决AS3请求数据的“安全沙箱冲突”问题
    purMVC代码备份
    译:如何配置Red5应用程序
    关于RED5——配置文件详解
    关于socket使用Amf直接进行对象传输的
    垃圾回收机制
  • 原文地址:https://www.cnblogs.com/Dincat/p/13443851.html
Copyright © 2011-2022 走看看