这里做的比较简陋,可以美化下
把form设置为非顶级控件,直接放在tabcontrol里边,然后实现tabcontrol的拖拽移除tabpage显示form以及添加tabpage
mousemove的触发时机需要优化一下
这里是比较简单的实现方式,也比较丑,可以实现像QQ那样的效果,可以重绘tabcontrol控件,然后以同样的方式实现拖拽移除显示和添加tabpage
也可以实现类似timQQ那样的形式,可以用自定义控件左边用listview右边放容器,重绘listview控件然后实现拖拽显示和添加,这样做复杂一点,但是会好看很多····
public Form1() { InitializeComponent(); } private TabControl tabControl1 = new TabControl(); private bool StartMove = false; private bool flag = true; private TabPage MovePage = null; protected override void OnLoad(EventArgs e) { base.OnLoad(e); tabControl1.Dock = DockStyle.Fill; this.Controls.Add(tabControl1); this.Controls.SetChildIndex(tabControl1, 0); frm1ToolStripMenuItem.Click += delegate { var frm1 = new Form(); frm1.Text = "frm1"; var btn=new Button(); btn.Text = "btn"; btn.Click += delegate { MessageBox.Show("this is frm1"); btn.Text = "frm1"; }; frm1.Controls.Add(btn); addfrm(frm1); }; frm2ToolStripMenuItem.Click += delegate { var frm1 = new Form(); frm1.Text = "frm2"; var btn = new Button(); btn.Text = "btn"; btn.Click += delegate { MessageBox.Show("this is frm2"); }; frm1.Controls.Add(btn); addfrm(frm1); }; frm3ToolStripMenuItem.Click += delegate { var frm1 = new Form(); frm1.Text = "frm3"; var btn = new Button(); btn.Text = "btn"; btn.Click += delegate { MessageBox.Show("this is frm3"); }; frm1.Controls.Add(btn); addfrm(frm1); }; tabControl1.AllowDrop = true; Func<Point, TabPage> GetTabPageByTab = (point) => { for (int i = 0; i < this.tabControl1.TabPages.Count; i++) { if (tabControl1.GetTabRect(i).Contains(point)) { return this.tabControl1.TabPages[i]; } } return null; }; tabControl1.MouseDown += (o, eg) => { if (flag) { StartMove = true; MovePage=GetTabPageByTab(new Point(eg.X, eg.Y)); } flag = true; }; tabControl1.MouseUp += (o, eg) => { StartMove = false; }; tabControl1.SelectedIndexChanged += (o, eg) => { flag = false;//切换的时候因为失去焦点的原因,会触发down事件不触发up事件这里做屏蔽 }; tabControl1.MouseMove += (o, eg) => { if (StartMove && flag) { if (MovePage != null) { this.DoDragDrop(MovePage, DragDropEffects.None); } } }; tabControl1.ControlAdded += delegate { StartMove = false; flag = false; }; tabControl1.DragOver += (o, eg) => { eg.Effect = DragDropEffects.None; if (tabControl1.TabPages.Count < 2) return; TabPage page = (TabPage)eg.Data.GetData(typeof(TabPage)); var frm1 = page.Controls[0] as Form; frm1.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable; frm1.Parent = null; frm1.TopLevel = true; frm1.Owner = this; frm1.Location = new Point(eg.X, eg.Y); frm1.Show(); tabControl1.TabPages.Remove(page); MovePage = null; frm1.Move += (oo, ee) => { for (int i = 0; i < tabControl1.TabPages.Count; i++) { if (tabControl1.GetTabRect(i).Contains(this.PointToClient(frm1.Location))) { addfrm(frm1); } } }; }; } private void addfrm(Form frm) { if (tabControl1.Visible == false) tabControl1.Visible = true; bool flag = true; frm.TopLevel = false; frm.Dock = DockStyle.Fill; frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; frm.Owner = null; foreach (TabPage page in tabControl1.TabPages) { if (page.Controls.Count < 1) { page.Controls.Add(frm); page.Text=frm.Text; flag = false; frm.Show(); return; } } if (flag) { var page=new TabPage(frm.Text); page.Controls.Add(frm); tabControl1.TabPages.Add(page); frm.Show(); } }
之前闲的没事写的tabcontrol加载窗体,刚好最近要用到这个· 这里简单重绘一个·因为要该背景色 去边框之类的,网上查了很多·不太好使· 这里用简单粗暴的方式直接吧背景色刷成想要的 然后在填充其他要改变背景色的地方
using System.Windows.Forms; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace ExerciseUIPrj.controls { public partial class XTabControl : TabControl { Size defaultSize = new Size(); const int dheight = 10; public XTabControl() { InitializeComponent(); base.SetStyle( ControlStyles.UserPaint | // 控件将自行绘制,而不是通过操作系统来绘制 ControlStyles.OptimizedDoubleBuffer | // 该控件首先在缓冲区中绘制,而不是直接绘制到屏幕上,这样可以减少闪烁 ControlStyles.AllPaintingInWmPaint | // 控件将忽略 WM_ERASEBKGND 窗口消息以减少闪烁 ControlStyles.ResizeRedraw | // 在调整控件大小时重绘控件 ControlStyles.SupportsTransparentBackColor, // 控件接受 alpha 组件小于 255 的 BackColor 以模拟透明 true); // 设置以上值为 true base.UpdateStyles(); this.SizeMode = TabSizeMode.Fixed; // 大小模式为固定 FontChanged += XTabControl_FontChanged; defaultSize = TextRenderer.MeasureText("tabpage1", Font); Margin = new System.Windows.Forms.Padding(0); Padding = new Point(0, 0); Appearance = TabAppearance.Normal; SetItemSize(); } //public override Rectangle DisplayRectangle //{ // get // { // Rectangle rect = base.DisplayRectangle; // return new Rectangle(rect.Left - 2, rect.Top-2, rect.Width + 4, rect.Height + 4); // } //} public void SetItemSize() { if (Width >= 0 && TabCount > 0) { if (Alignment ==TabAlignment.Top || Alignment == TabAlignment.Bottom) { int width = (int)((Size.Width - 5) / (double)this.TabCount); this.ItemSize = new Size(width, defaultSize.Height + dheight); // 设定每个标签的尺寸 } else { int width = defaultSize.Width; foreach (TabPage t in TabPages) { var w = TextRenderer.MeasureText(t.Name, Font).Width; width = w > width ? w : width; } width = width + dheight; this.ItemSize = new Size(defaultSize.Height + dheight, width); // 设定每个标签的尺寸 //这里w和h是反的 } } } private void XTabControl_FontChanged(object sender, EventArgs e) { defaultSize = TextRenderer.MeasureText("tabpage1", Font); SetItemSize(); } Color dbackColor = Color.FromArgb(220, 220, 220); protected override void OnPaint(PaintEventArgs pe) { var g = pe.Graphics; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; g.FillRectangle(new SolidBrush(Color.White), pe.ClipRectangle);//所有背景全刷,直接刷成白色······ Rectangle rect = new Rectangle(); if (Alignment == TabAlignment.Left || Alignment == TabAlignment.Right) { rect = new Rectangle(0,0, ItemSize.Height+2, Height); g.FillRectangle(new SolidBrush(dbackColor), rect);//吧标签背景色统一填充了 } else { rect = new Rectangle(0, 0, Width, ItemSize.Height+2); // g.FillRectangle(new SolidBrush(dbackColor), rect); } for (int i = 0; i < this.TabCount; i++)//这里画标签,可以在里边画图片···这里只画文字··· { Rectangle bounds = this.GetTabRect(i); if (SelectedIndex == i) { g.FillRectangle(new SolidBrush(Color.White), bounds); } else { g.FillRectangle(new SolidBrush(dbackColor), bounds); } PointF textPoint = new PointF(); SizeF textSize = TextRenderer.MeasureText(this.TabPages[i].Text, this.Font); textPoint.X= bounds.X + (bounds.Width - textSize.Width) / 2; textPoint.Y = bounds.Y + (bounds.Height - textSize.Height) / 2; g.DrawString( this.TabPages[i].Text, this.Font, SystemBrushes.ControlText, textPoint.X, textPoint.Y); } } } }