我正在做一个自定义控件(继承自VisualBasic.PowerPacks.LineShape
),它应该像标准一样绘制,但也会在其附近显示一个Icon。
所以,我刚刚覆盖OnPaint
这样:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
base.OnPaint(e);
}
现在,一切都很好,但是当我的控制移动时,图标仍然会在古老的地方绘制。
有没有办法正确地绘画?
alt text http://lh4.ggpht.com/_1TPOP7DzY1E/S5gXmp7xYiI/AAAAAAAADHI/pa1OhpKYSoM/Untitled-2.png 真实的项目情况
alt text http://lh6.ggpht.com/_1TPOP7DzY1E/S5jSluxvtDI/AAAAAAAADHw/EUz0Tfet-rw/s800/Capture2.png
using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;
namespace LineShapeTest
{
///
/// Test Form
///
public class Form1 : Form
{
IconLineShape myLine = new IconLineShape();
ShapeContainer shapeContainer1 = new ShapeContainer();
Panel panel1 = new Panel();
public Form1()
{
this.panel1.Dock = DockStyle.Fill;
// load your back image here
this.panel1.BackgroundImage =
global::WindowsApplication22.Properties.Resources._13820t;
this.panel1.Controls.Add(shapeContainer1);
this.myLine.StartPoint = new Point(20, 30);
this.myLine.EndPoint = new Point(80, 120);
this.myLine.Parent = this.shapeContainer1;
MouseEventHandler panelMouseMove =
new MouseEventHandler(this.panel1_MouseMove);
this.panel1.MouseMove += panelMouseMove;
this.shapeContainer1.MouseMove += panelMouseMove;
this.Controls.Add(panel1);
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
myLine.StartPoint = e.Location;
}
}
}
///
/// Test LineShape
///
public class IconLineShape : LineShape
{
Icon myIcon = SystemIcons.Exclamation;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
base.OnPaint(e);
}
}
}
Nota Bene ,对于lineShape:
Parent = ShapeContainer
Parent.Parent = Panel
在OnPaint的这个变种中,我们有痕迹:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Graphics g = Parent.Parent.CreateGraphics();
g.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
base.OnPaint(e);
}
alt text http://lh4.ggpht.com/_1TPOP7DzY1E/S5j29lutQ0I/AAAAAAAADH4/4yEnZd_hPjA/s800/Capture3.png
在OnPaint的这个变体中,我们有 闪烁图像 :
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Parent.Parent.Invalidate(this.Region, true);
Graphics g = Parent.Parent.CreateGraphics();
g.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
base.OnPaint(e);
}
alt text http://lh5.ggpht.com/_1TPOP7DzY1E/S5j4Bam7hiI/AAAAAAAADIA/1hQWKyV8Fr0/s800/Capture4.png
此变体效果很好,但是......来自IconLineShape类的外部:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Region r = myLine.Region;
myLine.StartPoint = e.Location;
panel1.Invalidate(r);
}
}
///
/// Test LineShape
///
public class IconLineShape : LineShape
{
Icon myIcon = SystemIcons.Exclamation;
Graphics parentGraphics;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
parentGraphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
base.OnPaint(e);
}
protected override void OnParentChanged(System.EventArgs e)
{
// Parent is a ShapeContainer
// Parent.Parent is a Panel
parentGraphics = Parent.Parent.CreateGraphics();
base.OnParentChanged(e);
}
}
即使这解决了测试示例的问题,我需要在控件内部完成此控件,因为我无法强制此控件的外部“客户端”不要忘记保存旧区域并使父项无效每次改变位置......
答案 0 :(得分:1)
您是否尝试清除缓冲区(使用背景颜色绘制填充矩形)?还要确保将剪裁区域重置为控件的大小,然后绘制图标,然后调用父级绘制。
答案 1 :(得分:1)
尝试更改表单的以下函数以使之前图标所在的缓冲区无效,从而删除其余的(untestet代码):
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point oldPos = myLine.StartPoint;
myLine.StartPoint = e.Location;
this.Invalidate(new Recangle(oldPos.X, oldPos.Y, myLine.Width, myLine.Height));
}
}
如果这不起作用,请尝试:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
myLine.StartPoint = e.Location;
this.Refresh();
}
}
由于性能问题(整个缓冲区被清除),可能不建议使用此方法,但没有其他工作正常...
答案 2 :(得分:1)
添加另一个完全不同的(希望再次工作:-)解决方案。由于我不知道“代码必须在课堂内”的要求,所以这是后续工作。
Axiom:永远不要在OnPaint或OnPaintBackground中调用Invalidate()
或Refresh()
,因为您(总是)会以infinite loop结束。
所以我们必须为他们找到另一个地方。我试图在Visual Studio中编译你的类,但我找不到类LineShape(Microsoft.VisualBasic.PowerPacks.Vs.dll没有做到这一点),所以再次untestet代码。
我做了什么?
-
public class Form1 : Form
{
IconLineShape myLine = new IconLineShape();
ShapeContainer shapeContainer1 = new ShapeContainer();
Panel panel1 = new Panel();
public Form1()
{
this.panel1.Dock = DockStyle.Fill;
// load your back image here
this.panel1.BackgroundImage =
global::WindowsApplication22.Properties.Resources._13820t;
this.panel1.Controls.Add(shapeContainer1);
this.myLine.StartPoint = new Point(20, 30);
this.myLine.EndPoint = new Point(80, 120);
this.myLine.Parent = this.shapeContainer1;
this.Controls.Add(panel1);
}
}
public class IconLineShape : LineShape
{
Icon myIcon = SystemIcons.Exclamation;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
base.OnPaint(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (draggable &&
e.Button == MouseButtons.Left &&
!this.StartPoint.Equals(e.Location))
{
Region r = this.Region.Clone();
this.StartPoint = e.Location;
// try solution 1
this.Invalidate(r);
// solution 2; walk up to the upmost parent and refresh
// as said before, this.Invalidate() is to be preferred
Control currentParent = this.Parent;
while (currentParent.Parent != null)
{
currentParent = currentParent.Parent;
}
currentParent.Refresh();
}
}
private bool draggable = true;
public bool Draggable
{
get { return this.draggable; }
set { this.draggable = value; }
}
}
请提供反馈。
答案 3 :(得分:0)
最后,最后添加PictureBox
而不是自己绘制图标。
using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;
namespace LineShapeTest
{
///
/// Test Form
///
public class Form1 : Form
{
IconLineShape myLine = new IconLineShape();
ShapeContainer shapeContainer1 = new ShapeContainer();
Panel panel1 = new Panel();
public Form1()
{
this.panel1.Dock = DockStyle.Fill;
// load your back image here
//this.panel1.BackgroundImage =
//global::WindowsApplication22.Properties.Resources._13820t;
this.panel1.BackColor = Color.White;
this.panel1.Controls.Add(shapeContainer1);
this.myLine.StartPoint = new Point(20, 30);
this.myLine.EndPoint = new Point(80, 120);
this.myLine.Parent = this.shapeContainer1;
MouseEventHandler panelMouseMove =
new MouseEventHandler(this.panel1_MouseMove);
this.panel1.MouseMove += panelMouseMove;
this.shapeContainer1.MouseMove += panelMouseMove;
this.Controls.Add(panel1);
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
myLine.StartPoint = e.Location;
}
}
}
///
/// Test LineShape
///
public class IconLineShape : LineShape
{
Icon myIcon = SystemIcons.Exclamation;
PictureBox pictureBox = new PictureBox();
public IconLineShape()
{
pictureBox.Image = Bitmap.FromHicon(myIcon.Handle);
pictureBox.Size = myIcon.Size;
pictureBox.Visible = true;
}
protected override void OnMove(System.EventArgs e)
{
base.OnMove(e);
pictureBox.Location = this.StartPoint;
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
pictureBox.Invalidate();
}
public override bool HitTest(int x, int y)
{
return base.HitTest(x, y) |
pictureBox.RectangleToScreen(
pictureBox.DisplayRectangle).Contains(new Point(x, y));
}
protected override void OnParentChanged(System.EventArgs e)
{
// Parent is a ShapeContainer
// Parent.Parent is a Panel
pictureBox.Parent = Parent.Parent;
base.OnParentChanged(e);
}
}
}
感谢大家的参与!
答案 4 :(得分:0)
你是否在自定义控件上执行此操作?
删除“频闪仪”效果
Public Sub New()
Me.SetStyle(ControlStyles.ResizeRedraw Or _
ControlStyles.DoubleBuffer Or _
ControlStyles.UserPaint Or _
ControlStyles.AllPaintingInWmPaint, _
True)
Me.UpdateStyles()
End Sub
答案 5 :(得分:-1)
这有帮助吗?看来你太过追赶LineShape了。对我来说,从RectangleShape派生更有意义。我把它包裹在帮助细节的帮手中。这个帮助器是我用来将控件关联在一起而不创建“复合控件”的标准技术,这通常更容易。
using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;
namespace LineShapeTest {
public partial class Form1 : Form {
/* Designer support through
* Create Panel
* Set panel's background image
* Add LineShape
* Add IconShape
* Create IconicLineShapeHelper
*/
public Form1() {
InitializeComponent();
IconicLineShapeHelper arbitrary1 = new IconicLineShapeHelper(lineShape1, iconShape1);
IconicLineShapeHelper arbitrary2 = new IconicLineShapeHelper(lineShape2, iconShape2);
}
private Panel panel1;
private ShapeContainer shapeContainer1;
private LineShape lineShape1;
private IconShape iconShape1;
private ShapeContainer shapeContainer2;
private LineShape lineShape2;
private IconShape iconShape2;
#region [ Form1.Designer.cs ]
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
private void InitializeComponent() {
this.lineShape1 = new Microsoft.VisualBasic.PowerPacks.LineShape();
this.panel1 = new System.Windows.Forms.Panel();
this.shapeContainer1 = new Microsoft.VisualBasic.PowerPacks.ShapeContainer();
this.iconShape1 = new LineShapeTest.IconShape();
this.shapeContainer2 = new Microsoft.VisualBasic.PowerPacks.ShapeContainer();
this.lineShape2 = new Microsoft.VisualBasic.PowerPacks.LineShape();
this.iconShape2 = new LineShapeTest.IconShape();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// lineShape1
//
this.lineShape1.Name = "lineShape1";
this.lineShape1.X1 = 13;
this.lineShape1.X2 = 88;
this.lineShape1.Y1 = 11;
this.lineShape1.Y2 = 34;
//
// panel1
//
this.panel1.BackgroundImage = global::LineShapeTest.Properties.Resources._13820t;
this.panel1.Controls.Add(this.shapeContainer1);
this.panel1.Location = new System.Drawing.Point(27, 24);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(162, 122);
this.panel1.TabIndex = 1;
//
// shapeContainer1
//
this.shapeContainer1.Location = new System.Drawing.Point(0, 0);
this.shapeContainer1.Margin = new System.Windows.Forms.Padding(0);
this.shapeContainer1.Name = "shapeContainer1";
this.shapeContainer1.Shapes.AddRange(new Microsoft.VisualBasic.PowerPacks.Shape[] {
this.iconShape1,
this.lineShape1});
this.shapeContainer1.Size = new System.Drawing.Size(162, 122);
this.shapeContainer1.TabIndex = 0;
this.shapeContainer1.TabStop = false;
//
// iconShape1
//
this.iconShape1.BorderStyle = System.Drawing.Drawing2D.DashStyle.Custom;
this.iconShape1.Location = new System.Drawing.Point(88, 64);
this.iconShape1.Name = "iconShape1";
this.iconShape1.Size = new System.Drawing.Size(32, 32);
//
// shapeContainer2
//
this.shapeContainer2.Location = new System.Drawing.Point(0, 0);
this.shapeContainer2.Margin = new System.Windows.Forms.Padding(0);
this.shapeContainer2.Name = "shapeContainer2";
this.shapeContainer2.Shapes.AddRange(new Microsoft.VisualBasic.PowerPacks.Shape[] {
this.iconShape2,
this.lineShape2});
this.shapeContainer2.Size = new System.Drawing.Size(292, 266);
this.shapeContainer2.TabIndex = 2;
this.shapeContainer2.TabStop = false;
//
// lineShape2
//
this.lineShape2.Name = "lineShape2";
this.lineShape2.X1 = 48;
this.lineShape2.X2 = 123;
this.lineShape2.Y1 = 187;
this.lineShape2.Y2 = 210;
//
// iconShape2
//
this.iconShape2.Location = new System.Drawing.Point(136, 220);
this.iconShape2.Name = "iconShape2";
this.iconShape2.Size = new System.Drawing.Size(75, 23);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.panel1);
this.Controls.Add(this.shapeContainer2);
this.Name = "Form1";
this.Text = "Form1";
this.panel1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
}
#endregion
public class IconicLineShapeHelper {
ShapeContainer _container;
LineShape _line;
IconShape _icon;
public IconicLineShapeHelper(LineShape line, IconShape icon) {
_container = line.Parent;
_line = line;
_icon = icon;
_container.MouseMove += new MouseEventHandler(_container_MouseMove);
}
void _container_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
_line.StartPoint = e.Location;
_icon.Location = e.Location;
}
}
}
public class IconShape : RectangleShape {
Icon _icon = SystemIcons.Exclamation;
public IconShape() {
this.Size = new System.Drawing.Size(32, 32);
this.BorderStyle = System.Drawing.Drawing2D.DashStyle.Custom;
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
e.Graphics.DrawIcon(_icon, this.Location.X, this.Location.Y);
base.OnPaint(e);
}
}
}