我正在为视频使用开发时间轴用户控件。这是我工作的照片:
这里我有问题。当currentTime改变时,我必须更新UI。但当我使用this.Invalidate();它刷新了整个控制。但我想更新指针(灰色背景中的白线)。因为它导致控制在非常微小的时间变化时反复闪烁。 如何更新指针? 这是我的onPaint方法
private void OnPaint(object sender, System.Windows.Forms.PaintEventArgs e)
{
int width = this.Width;
int height = this.Height;
int Floor = height - FloorDistance;
Pen SecPen = new Pen(SecColor);
Pen MinPen = new Pen(MinColor);
SolidBrush TimeLineBrush = new SolidBrush(Color.Gray);
StringFormat stringFormat = new StringFormat();
SolidBrush TimesolidBrush = new SolidBrush(TimeColor);
SolidBrush BackBrush = new SolidBrush(TimlineBackColor);
SolidBrush PointerBrush = new SolidBrush(PointerColor);
stringFormat.FormatFlags = StringFormatFlags.DirectionVertical;
switch (Zoom)
{
case ZoomLEvel.Quarter:
width = (int)Math.Ceiling((TotalDuration / 900)) * ThickDistance;
break;
case ZoomLEvel.Minute:
width = (int)Math.Ceiling((TotalDuration / 60)) * ThickDistance;
break;
case ZoomLEvel.Secound:
width = (int)Math.Ceiling(TotalDuration) * ThickDistance;
break;
case ZoomLEvel.MiliSecound:
width = (int)Math.Ceiling(TotalDuration * 10) * ThickDistance;
break;
}
width += 11;
this.Width = width;
e.Graphics.FillRectangle(TimeLineBrush, 0, Floor, width, 3);
e.Graphics.FillRectangle(BackBrush, 0, 0, width, height - FloorDistance);
int x = ThickDistance;
int step = 0;
while (x <= width - ThickDistance)
{
if (step % 5 == 0)
{
e.Graphics.DrawLine(MinPen, x, Floor, x, Floor - _MinHeight);
// print time
string time = "";
double totalSecounds = 0;
PointF pointF = new PointF(x - 8, Floor + 5);
switch (Zoom)
{
case ZoomLEvel.Quarter:
totalSecounds = step * 900;
break;
case ZoomLEvel.Minute:
totalSecounds = step * 60;
break;
case ZoomLEvel.Secound:
totalSecounds = step;
break;
case ZoomLEvel.MiliSecound:
totalSecounds = step / 10d;
break;
}
time = (new TimeSpan(0, 0, 0, (int)totalSecounds, (int)(step % 10) * 100)).ToString(@"hh\:mm\:ss\:fff");
e.Graphics.DrawString(time, this.Font, TimesolidBrush, pointF, stringFormat);
}
else
e.Graphics.DrawLine(SecPen, x, Floor, x, Floor - _SecHeight);
x += ThickDistance;
step++;
}
int PointerTime = 0;//(int)Math.Floor(CurrentTime);
int pointerX = 0;
switch (Zoom)
{
case ZoomLEvel.Quarter:
PointerTime = (int)Math.Floor(CurrentTime / 900);
pointerX = PointerTime * ThickDistance;
break;
case ZoomLEvel.Minute:
PointerTime = (int)Math.Floor(CurrentTime / 60);
pointerX = PointerTime * ThickDistance;
break;
case ZoomLEvel.Secound:
PointerTime = (int)Math.Floor(CurrentTime);
pointerX = PointerTime * ThickDistance;
break;
case ZoomLEvel.MiliSecound:
PointerTime = (int)Math.Floor(CurrentTime * 10);
pointerX = PointerTime * ThickDistance;
break;
}
pointerX += 5;
e.Graphics.FillRectangle(PointerBrush, pointerX, 0, 2, height - FloorDistance);
}
答案 0 :(得分:2)
Invalidate()
方法的重载采用Rectangle
类型参数来定义要刷新的区域,称为剪切矩形。你应该传递指针的边界矩形(白线,所有边可能有10个像素的填充)。在OnPaint()
方法中,您应该检查e.ClipRectangle
属性以查找需要重绘的区域。现在对于所有绘图逻辑(e.Graphics。 DrawX()调用),您应该首先确认该元素是否与剪切区域相交(可以使用Rectangle.IntersectsWith()
轻松完成)。如果是,则应调用 DrawX 方法,否则不应该。
为避免闪烁,您应该将控件的DoubleBuffered
属性设置为True
。实现真正流畅的渲染还有很长的路要走。
此外,我发现您在OnPaint
方法中声明了很多画笔和笔,并且在使用后没有处理它们。我假设其中许多将一次又一次地被要求,所以你可能想要在类级别声明它们,然后将它们放在你控件的Dispose()
方法中。考虑到这是一个与视频相关的应用程序,这将为您节省一些处理。
希望有所帮助。