当前位置:  开发笔记 > 编程语言 > 正文

在面板内部的控件上绘图(C#WinForms)

如何解决《在面板内部的控件上绘图(C#WinForms)》经验,为你挑选了4个好方法。

我知道这个问题被问了好几次,但到目前为止我还没有找到一个好的解决方案.

我有一个其他控件的面板.
我想在它上面和在面板中的所有控件上绘制一条线

我遇到了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()处理程序中.
我应该尝试把它放在其他地方吗?
- 这也会在面板顶部设置另一个控件时产生问题.(抓住鼠标点击等..)

任何帮助将不胜感激!

**编辑:黑线是我试图做的样本.(用过的窗户油漆来涂漆)

替代文字



1> MusiGenesis..:

事实证明这比我想象的要容易得多.谢谢你不接受我的任何其他答案.这是创建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}));


"好密集的单行"总是一件坏事.

2> MusiGenesis..:

如果您希望线条只是一条简单的水平线或垂直线,请在主面板上放置另一个面板(禁用以便它不会拾取任何鼠标事件),将其高度(或宽度)设置为3或4像素(或无论你想要什么,并把它带到前面.如果您需要在运行期间更改线的位置,则只需移动面板并使其可见且不可见.以下是它的外观:

替代文字

你甚至可以点击你喜欢的任何地方,线条根本不会干涉.这条线完全被绘制在任何类型的控件上(尽管ComboBox或DatePicker的下拉部分仍然显示在该行的上方,无论如何这都是好的).蓝线是同样的东西,但发送回来.



3> MusiGenesis..:

是的,这可以做到.问题是面板和它上面的控件都是独立的窗口(在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事件,至少不是你是我的话.希望这不会是一个问题.



4> Matt Brunell..:

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);
}

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有