简体   繁体   English

如何更改 Winforms 中选项卡控件的背景颜色?

[英]How do I change background colour of tab control in Winforms?

Is there a way to change the background colour of a tab control in winforms, so that it does not have the white border around it?有没有办法在winforms中更改选项卡控件的背景颜色,使其周围没有白色边框?

I have tried a few different ways, but they all result in the same white border being displayed.我尝试了几种不同的方法,但它们都导致显示相同的白色边框。

TabControl has very poor support for customization. TabControl对自定义的支持很差。 I've used this custom tab control with good success.我已经成功地使用了这个自定义选项卡控件 The code is pretty usable if you want to change the look as I did.如果您想像我一样更改外观,该代码非常有用。

First of all you need to make a deriving class from TabControl.首先,您需要从 TabControl 创建一个派生类。 So far so good but now it gets dirty.到目前为止一切顺利,但现在它变脏了。

Because TabControl won't call OnPaint , we have do override WndProc to handle the WM_PAINT message.因为 TabControl 不会调用OnPaint ,所以我们必须重写WndProc来处理 WM_PAINT 消息。 In there we go ahead and paint our background with the color we like.在那里,我们继续用我们喜欢的颜色绘制背景。

 protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if(m.Msg == (int) WindowsMessages.Win32Messages.WM_PAINT)
        {
            using (Graphics g = this.CreateGraphics())
            {
                //Double buffering stuff...
                BufferedGraphicsContext currentContext;
                BufferedGraphics myBuffer;
                currentContext = BufferedGraphicsManager.Current;
                myBuffer = currentContext.Allocate(g,
                   this.ClientRectangle);

                Rectangle r = ClientRectangle;

                //Painting background
                if(Enabled)
                    myBuffer.Graphics.FillRectangle(new SolidBrush(_backColor), r);
                else
                    myBuffer.Graphics.FillRectangle(Brushes.LightGray, r);

                //Painting border
                r.Height = this.DisplayRectangle.Height +1; //Using display rectangle hight because it excludes the tab headers already
                r.Y = this.DisplayRectangle.Y - 1; //Same for Y coordinate
                r.Width -= 5;
                r.X += 1;

                if(Enabled)
                    myBuffer.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 133, 158, 191), 1), r);
                else
                    myBuffer.Graphics.DrawRectangle(Pens.DarkGray, r);

                myBuffer.Render();
                myBuffer.Dispose();

                //Actual painting of items after Background was painted
                foreach (int index in ItemArgs.Keys)
                {
                    CustomDrawItem(ItemArgs[index]);
                }

            }
        }    
    }

Im doing further drawing in this method so it looks a little overkill for this problem but just ignore the unnecessary stuff.我在这个方法中做进一步的绘制,所以对于这个问题看起来有点矫枉过正,但只是忽略了不必要的东西。 Also notice the foreach loop.还要注意foreach循环。 I'll come to this later.我稍后会谈到这个。

The Problem is that TabControl paints its items (the tab headers) before its own WM_PAINT so our background will be drawn on top, which renders them invisible.问题是TabControl在其自己的 WM_PAINT之前绘制其项目(选项卡标题),因此我们的背景将被绘制在顶部,这使得它们不可见。 To solve this I made an EventHandler for DrawItem which looks as the following:为了解决这个问题,我为DrawItem创建了一个EventHandler ,如下所示:

    private void DrawItemHandler(object sender, DrawItemEventArgs e)
    {
        //Save information about item in dictionary but dont do actual drawing
        if (!ItemArgs.ContainsKey(e.Index))
            ItemArgs.Add(e.Index, e);
        else
            ItemArgs[e.Index] = e;
    }

I am saving the DrawItemEventArgs into a dictionary (which is called "ItemArgs" in my case) so I can access them later.我将DrawItemEventArgs保存到字典中(在我的情况下称为“ItemArgs”),以便以后可以访问它们。 Thats where the foreach from a few seconds ago comes into play.这就是几秒钟前的foreach发挥作用的地方。 It calls a method where I am painting the tab headers which takes the DrawItemEventArgs which we saved before as a parameter to paint the items in correct state and position.它调用一个方法,我在其中绘制选项卡标题,该方法将我们之前保存的DrawItemEventArgs作为参数以正确的状态和位置绘制项目。

So, in a nutshell we are intercepting the Drawing of tab headers to delay it until we are finished drawing the background.因此,简而言之,我们正在拦截选项卡标题的绘制以延迟它,直到我们完成绘制背景。

This solution is not optimal but it works and its the only thing you can do to get more control over TabControl (lol) without painting it from scratch.这个解决方案不是最佳的,但它可以工作,并且它是唯一可以做的事情来获得对TabControl的更多控制(lol),而无需从头开始绘制它。

I can only think of changing Appearance property to Buttons我只能想到将 Appearance 属性更改为 Buttons

MSDN TabControl Appearance MSDN TabControl 外观

Easier still (IMO): add a paint handler to the TabPage (not the top level TabControl, but the TabPage(s) within it, then paint the background rectangle in the color you want.更简单(IMO):将绘制处理程序添加到 TabPage(不是顶级 TabControl,而是其中的 TabPage,然后以您想要的颜色绘制背景矩形。

  1. Either in the designer or "by hand", add a Paint event handler to the TabPage:在设计器中或“手动”中,将 Paint 事件处理程序添加到 TabPage:

     Page1.Paint += tabpage_Paint; // custom paint event so we get the backcolor we want
  2. In the paint method, paint the page rectangle the color you want (in my case, I want it to follow the standard BackColor):在paint方法中,将页面矩形绘制成你想要的颜色(在我的例子中,我希望它遵循标准的BackColor):

     // force the tab background to the current BackColor private void tabpage_Paint(object sender, PaintEventArgs e) { SolidBrush fillBrush = new SolidBrush(BackColor); e.Graphics.FillRectangle(fillBrush, e.ClipRectangle); }

Drop a Panel on top of (not inside) the tab control and set the color in the properties.将面板放在选项卡控件的顶部(而不是内部)并在属性中设置颜色。 Call Panelx.Hide() and Panelx.Show() as needed.根据需要调用 Panelx.Hide() 和 Panelx.Show()。

Unfortunately, the back color property is handled when the control is drawn.不幸的是,在绘制控件时会处理背景颜色属性。 My suggestion is to do what I have done and create a user control to mimic the tab controller.我的建议是做我所做的并创建一个用户控件来模仿标签控制器。

I used a menu strip as the tabs and had a second user control docked as fill to the parent user control.我使用菜单条作为选项卡,并将第二个用户控件停靠为父用户控件的填充。 In the second user control, I was able to add whatever I needed for said tab.在第二个用户控件中,我能够为所述选项卡添加我需要的任何内容。

The part that is harder with it is that you have to build all the functionality to make it work as a tab control.更难的部分是您必须构建所有功能以使其用作选项卡控件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM