我知道这个问题被问了好几次,但到目前为止我还没有找到一个好的解决方案.
我有一个其他控件的面板.
我想在它上面和在面板中的所有控件上绘制一条线
我遇到了3种类型的解决方案(其中没有按照我想要的方式工作):
获取桌面DC并在屏幕上绘图.
如果它们与表格重叠,这将吸引其他应用程序.
覆盖面板的"CreateParams":
=
protected override CreateParams CreateParams { get { CreateParams cp; cp = base.CreateParams; cp.Style &= ~0x04000000; //WS_CLIPSIBLINGS cp.Style &= ~0x02000000; //WS_CLIPCHILDREN return cp; } }
//注意我也尝试过禁用WS_CLIPSIBLINGS
然后绘制OnPaint()行.但是......由于面板的OnPaint在其中的控件的OnPaint之前被调用,因此内部控件的绘制仅在该行顶部绘制.
我见过有人建议使用消息过滤器来收听WM_PAINT消息,并使用定时器,但我不认为这个解决方案要么是"良好实践",要么是有效的.
你会怎么做 ?确定内部控件在X ms后完成绘图,并将定时器设置为X ms?
此屏幕截图显示了WS_CLIPSIBLINGS和WS_CLIPCHILDREN关闭的面板.
蓝线在Panel的OnPaint上绘制,只是被文本框和标签绘制.
红色线条仅仅涂在上面,因为它没有从面板的OnPaint上绘制(它实际上是由于点击了按钮而绘制的)
第3步:创建透明图层并在该图层的顶部绘图.
我使用以下方法创建了一个透明控件:
protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT return cp; } }
问题仍然存在,将透明控件置于Panel及其所有控件之上.
我尝试使用"BringToFront()"把它带到前面,但它似乎没有帮助.
我把它放在Line控件的OnPaint()处理程序中.
我应该尝试把它放在其他地方吗?
- 这也会在面板顶部设置另一个控件时产生问题.(抓住鼠标点击等..)
任何帮助将不胜感激!
**编辑:黑线是我试图做的样本.(用过的窗户油漆来涂漆)
事实证明这比我想象的要容易得多.谢谢你不接受我的任何其他答案.这是创建Fline的两步过程(f loating line - 抱歉,已经晚了):
步骤1:将UserControl添加到项目中并将其命名为"Fline".将以下内容添加到using语句中:
using System.Drawing.Drawing2D;
第2步:将以下内容添加到Fline的Resize事件中:
int wfactor = 4; // half the line width, kinda // create 6 points for path Point[] pts = { new Point(0, 0), new Point(wfactor, 0), new Point(Width, Height - wfactor), new Point(Width, Height) , new Point(Width - wfactor, Height), new Point(0, wfactor) }; // magic numbers! byte[] types = { 0, // start point 1, // line 1, // line 1, // line 1, // line 1 }; // line GraphicsPath path = new GraphicsPath(pts, types); this.Region = new Region(path);
编译,然后将Fline拖到表单或面板上.重要提示:默认的BackColor与表单相同,因此将Fline的BackColor更改为Red或其他显而易见的(在设计器中).关于这一点的一个奇怪的怪癖是,当你在设计器中拖动它时,它会显示为一个坚固的块直到你释放它 - 这不是一个大问题.
此控件可以出现在任何其他控件的前面或后面.如果将Enabled设置为false,它仍然可见,但不会干扰下面控件上的鼠标事件.
当然,您需要为您的目的增强此功能,但这显示了基本原则.您可以使用相同的技术来创建您喜欢的任何形状的控件(我对此的初始测试创建了一个三角形).
更新:这也是一个很好的密集单行.只需将它放在UserControl的Resize事件中:
this.Region=new Region(new System.Drawing.Drawing2D.GraphicsPath(new Point[]{new Point(0,0),new Point(4,0),new Point(Width,Height-4),new Point(Width,Height),new Point(Width-4,Height),new Point(0,4)},new byte[]{0,1,1,1,1,1}));
如果您希望线条只是一条简单的水平线或垂直线,请在主面板上放置另一个面板(禁用以便它不会拾取任何鼠标事件),将其高度(或宽度)设置为3或4像素(或无论你想要什么,并把它带到前面.如果您需要在运行期间更改线的位置,则只需移动面板并使其可见且不可见.以下是它的外观:
你甚至可以点击你喜欢的任何地方,线条根本不会干涉.这条线完全被绘制在任何类型的控件上(尽管ComboBox或DatePicker的下拉部分仍然显示在该行的上方,无论如何这都是好的).蓝线是同样的东西,但发送回来.
是的,这可以做到.问题是面板和它上面的控件都是独立的窗口(在API意义上),因此所有单独的绘图表面.没有一个绘图表面可以用来获得这种效果(除了顶层屏幕表面,并且它被认为是不礼貌的).
该(cough- 破解 -cough)关键是要绘制控件下方的面板上线,并借鉴其在每个控件本身,造成这(当您单击按钮和移动鼠标,这将持续存在,甚至):
创建一个winforms项目(默认情况下应该带有Form1).在面板上添加一个面板(名为"panel1")和两个按钮("button1"和"button2"),如图所示.在表单的构造函数中添加此代码:
panel1.Paint += PaintPanelOrButton; button1.Paint += PaintPanelOrButton; button2.Paint += PaintPanelOrButton;
然后将此方法添加到窗体的代码中:
private void PaintPanelOrButton(object sender, PaintEventArgs e) { // center the line endpoints on each button Point pt1 = new Point(button1.Left + (button1.Width / 2), button1.Top + (button1.Height / 2)); Point pt2 = new Point(button2.Left + (button2.Width / 2), button2.Top + (button2.Height / 2)); if (sender is Button) { // offset line so it's drawn over the button where // the line on the panel is drawn Button btn = (Button)sender; pt1.X -= btn.Left; pt1.Y -= btn.Top; pt2.X -= btn.Left; pt2.Y -= btn.Top; } e.Graphics.DrawLine(new Pen(Color.Red, 4.0F), pt1, pt2); }
需要在每个控件的Paint事件中绘制类似的东西,以便该行保持不变.在.NET中直接绘制控件很容易,但是当有人点击按钮或将鼠标移到它上面时,无论你绘制什么都会被擦除(除非它在Paint事件中永久重绘,如此处所示).
请注意,为此,要绘制的任何控件都必须具有Paint事件.我相信你必须修改这个样本才能达到你的需要.如果您想出一个很好的通用功能,请发布.
更新:此方法不适用于滚动条,文本框,组合框,列表视图,或基本上任何文本框类型的东西作为其一部分(并不是因为它只偏移上面示例中的按钮 - 你只是无法绘制文本框的顶部,至少不是来自它的Paint事件,至少不是你是我的话.希望这不会是一个问题.
Windows窗体面板是控件的容器.如果你想在面板中的其他控件之上绘制一些东西,那么你需要的是另一个控件(在z顺序的顶部).
幸运的是,您可以创建具有非矩形边框的窗体控件.看看这个技术:http: //msdn.microsoft.com/en-us/library/aa289517(VS.71).aspx
要在屏幕上绘制内容,请使用标签控件,然后关闭AutoSize.然后附加到Paint事件并设置Size和Region Properties.
这是一个代码示例:
private void label1_Paint(object sender, PaintEventArgs e) { System.Drawing.Drawing2D.GraphicsPath myGraphicsPath = new System.Drawing.Drawing2D.GraphicsPath(); myGraphicsPath.AddEllipse(new Rectangle(0, 0, 125, 125)); myGraphicsPath.AddEllipse(new Rectangle(75, 75, 20, 20)); myGraphicsPath.AddEllipse(new Rectangle(120, 0, 125, 125)); myGraphicsPath.AddEllipse(new Rectangle(145, 75, 20, 20)); //Change the button's background color so that it is easy //to see. label1.BackColor = Color.ForestGreen; label1.Size = new System.Drawing.Size(256, 256); label1.Region = new Region(myGraphicsPath); }