我想在C#中直接在桌面上绘图.从搜索一下,我最终使用Desktop HDC中的Graphics对象(null).然后,我正常使用这个Graphics对象绘制.
问题是当重绘屏幕的任何部分时,我的形状会丢失.我尝试了一个While循环,但它实际上最终绘制的速度与应用程序一样快,这不是桌面的更新速率.
通常,我需要将我的绘图代码放在"OnPaint"事件中,但桌面上不存在这样的事情.
我该怎么办?
示例代码:https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
这是我的绘图代码,用鼠标在图表上绘制自定义行.你能帮我做正确的方法吗?
namespace Grafi
{
public partial class Form1 : Form
{
bool isDrawing = false;
Point prevPoint;
public Form1()
{
InitializeComponent();
}
private void chartTemperature_MouseDown(object sender, MouseEventArgs e)
{
isDrawing = true;
prevPoint = e.Location;
}
private void chartTemperature_MouseMove(object sender, MouseEventArgs e)
{
Pen p = new Pen(Color.Red, 2);
if (isDrawing)
{
Graphics g = chartTemperature.CreateGraphics();
g.DrawLine(p, prevPoint, e.Location);
prevPoint = e.Location;
numOfMouseEvents = 0;
}
p.Dispose();
}
private void chartTemperature_MouseUp(object sender, MouseEventArgs e)
{
isDrawing = false;
}
} …
Run Code Online (Sandbox Code Playgroud) 我找到了一些我并不真正得到的东西:
protected override void OnPaint(PaintEventArgs e)
{
DrawChar(e.Graphics);
base.OnPaint(e);
}
void DrawChar(Graphics g)
{
if (body != null)
{
g.DrawImage(body, X, Y);
}
}
Run Code Online (Sandbox Code Playgroud)
假设"body"是空的 - 如果我删除DrawChar中的条件,程序从不绘制任何东西,我发现onPaint甚至不再被提升(例如,当调整大小或缩小和恢复窗口时).
编辑:重点是 - 如果DrawImage失败(你不知道调试器,它只是不绘制图像,例如当Image为null)时,应用程序中的OnPaint事件不再被引发.
因此解决了透明背景问题.现在,每次我展示表格(或必须重新粉刷),我都会有很多闪烁.有没有办法在油漆事件完成之前我无法更新屏幕,或者在绘制所有物体时以任何其他方式停止闪烁和闪烁的1/2秒?
答案:双重缓冲是要走的路.我已经在控件上进行了双缓冲,但必须在表单上进行设置.我虽然双缓冲只在你自己继承OnPaint时起作用.
目前我正在尝试做我认为简单的任务:
Panel
在Windows窗体中将图像绘制到控件的整个区域.(请忽略我可以使用该BackgroundImage
物业的那一刻)
要绘制的图像如下所示:
即一个黄色的盒子,周围有一个1像素的蓝色框架.
要绘制,我正在使用控件的Paint
事件Panel
:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(Resources.MyImage, panel1.ClientRectangle);
}
Run Code Online (Sandbox Code Playgroud)
这在最初显示表单时看起来很好:
调整窗体大小(以及对接面板)时,要么在缩小时缩小边缘...
...或者当它变得更大时它会绘制人工制品:
我很确定会有一些相当简单和直接的东西,但我真的无法理解其中的原因.
由于我忽略了ClipRectangle
并总是画出一切,我认为图像会一直缩放.
我的问题是:
Invalidate
每个调整大小)更新,解决方案:
感谢Ryan的回答,我找到了一个可以接受的解决方案.基本上我衍生自类Panel
,做过的重写OnPaintBackground
,也没有调用基方法.最后,我将以下代码添加到派生面板的构造函数中:
base.DoubleBuffered = true;
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
Run Code Online (Sandbox Code Playgroud) 我正在尝试进行ImageListBox
一种显示大量缩略图的控件,比如Picasa使用的缩略图.
这是我的设计:
我有一个FlowLayoutPanel
填充了很多UserControl
对象,例如4000.每个人都UserControl
被分配了一个Paint
事件代表.当Paint
事件被调用时,它会检查内存缓存缩略图,如果图像不在缓存中,它从磁盘检索它.
我有两个问题需要解决:
Paint
即使UserControl
不在视图中,WinForms似乎也会触发事件.实际上只有10个左右的控件FlowLayoutPanel.AutoScroll
可供查看,其余的不是(设置为true
).因此,它会尝试检索所有图像的缩略图,这需要很长时间.
添加UserControl
对象FlowLayoutPanel
需要花费相当长的时间,大约2-3秒.我可以忍受它,但我想知道是否有更好的方法来做到这一点:
UserControl[] boxes = new UserControl[N];
// populate array
panel.SuspendLayout();
panel.Controls.AddRange(boxes);
panel.ResumeLayout();
Run Code Online (Sandbox Code Playgroud)我已经在C#WinForms中创建了一个控件,并且在我的OnPaint()
处理程序中自定义绘图文本.使用我的表单中的以下代码将字体设置为Courier New:
FontFamily family = new FontFamily("Courier New");
this.myControl.Font = new Font(family, 10);
Run Code Online (Sandbox Code Playgroud)
在控件本身,字符串存储在realText
,我使用以下代码将其绘制到屏幕:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawString(realText, Font, new SolidBrush(ForeColor), ClientRectangle);
}
Run Code Online (Sandbox Code Playgroud)
一些随机示例文本的结果如下所示:http: //img219.imageshack.us/img219/1778/courier.png
如果你放大,你可以看到,例如,第一个'as'之间的空间不同于第二个'as'之间的空格(1个像素对2个像素).有没有人知道可能导致这种情况的原因,或者我如何防止它发生?我使用不同的字体绘制的间距有很多类似的怪异,但我认为它们都是同一问题的结果.
提前感谢您的任何想法.
我认为应该很容易创建一个ProgressBar
吸取一些文本的东西.但是,我不太清楚这里发生了什么......
我添加了以下两个覆盖:
protected override void OnPaintBackground(PaintEventArgs pevent)
{
base.OnPaintBackground(pevent);
var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis;
TextRenderer.DrawText(pevent.Graphics, "Hello", Font, Bounds, Color.Black, flags);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis;
TextRenderer.DrawText(e.Graphics, "Hello", Font, Bounds, Color.Black, flags);
}
Run Code Online (Sandbox Code Playgroud)
但是,我没有文本,甚至似乎都没有调用这些方法.这里发生了什么?
更新:由于到目前为止的两个答案,我已经得到它实际调用OnPaint
使用SetStyle(ControlStyles.UserPaint, true)
,我已经得到它通过发送new Rectangle(0, 0, Width, Height)
而不是在正确的地方绘制文本Bounds
.
我现在确实得到了文字,但是ProgressBar
它已经消失了...而且重点是将文本置于文本之上ProgressBar
.知道如何解决这个问题吗?
我在网站上看到了一些类似的问题,但没有一个真正帮助过我.
我有一个函数,当单击一个按钮时,它会在窗体上绘制几行,这些按钮的形状会根据用户在某些文本框中输入的值而变化.
我的问题是,当我最小化形式时,线条消失,我明白这可以通过使用OnPaint事件来解决,但我真的不明白如何.
任何人都可以给我一个简单的例子,使用函数在按下按钮时使用OnPaint事件绘制一些东西吗?
我在表单上有一个简单的面板,我正在使用 AutoScrollMinSize 和 AutoScroll 在面板上获取一些滚动条,一切正常。
我还有一个滚动事件,我用它来使整个面板区域无效,因为事实上它似乎只使左/右、上/下滚动时所需的位无效。除此之外,我使用与面板大小相同的 BufferedGraphics,然后执行 .Render(e.Graphics),因为我希望它在整个面板上绘制,就好像滚动条不存在一样。
现在,我遇到的问题是,滚动和绘制内容时似乎存在视觉上的滞后,我认为这是因为在滚动事件之前有一个我不熟悉的额外绘制/设置阶段调用或在该事件与调用的 Paint 事件之间进行。
如果我在绘制方法中有一个无效面板,您不会看到问题,但这更多地与多次调用绘制事件隐藏问题有关。
所以我认为我理解它的方式是,当你滚动时,引擎盖下的某个东西会做一个大矩形 blit 移动已经存在的内容,然后调用需要填充区域的矩形 invalidate 。
如果是这种情况,是否有任何围绕此问题的方法,例如抑制此阶段或我缺少的一些其他设置以消除跟上滞后?
PS:我还重写了 OnPaintBackground 方法,它是一个空存根。
c# ×10
onpaint ×10
winforms ×5
.net ×3
drawing ×3
controls ×2
autoscroll ×1
buffer ×1
drawstring ×1
events ×1
gdi ×1
overriding ×1
panel ×1