我有一个WinForms控件,我想在其中显示两件事:
为了我们的目的,第1项并没有改变,我宁愿不必重新绘制它。
事物#2必须相对较快地重绘,因为当用户转动另一个控件时它会旋转。
在我的幻想中,我想把每个Thing放在自己的Graphics对象中,给#2一个透明的背景,然后用旋转变换点击#2以匹配用户控件设置。但我没有看到让Graphics对象透明的方法,也没有办法旋转已经绘制的对象。所以我可能要求Graphics做一些不是为它设计的东西。
这是我的问题:设置它的最佳方法是什么?我是否应该尝试重叠我的Graphics对象,或者是否有一些完全不同且更好的方法来执行此操作,而我却没有想到?
答案 0 :(得分:1)
GDI +不是保留模式,因此您需要在每个Paint上重绘整个控件。所以不幸的是,你不能只有两个“东西”,并将旋转应用于其中一个。 GDI +最好的选择可能是:
然后在Paint处理器中使用Graphics.DrawImage快速重绘#1,使用Graphics.RotateTransform设置旋转变换,并绘制线条。您应该能够使用双缓冲(ControlStyles.DoubleBuffer)使其显得平滑。
至于“完全不同”的方式,嗯,你所描述的“幻想”被称为Windows Presentation Foundation。 WPF确实有一个保留模式的图形系统,可能更方便地处理“旋转一层,同时保持另一层不变”。您可以使用ElementHost控件在WinForms中托管WPF。粗略的想法是使用Grid在Image上叠加Canvas,将Line对象添加到Canvas,将Canvas'RenderTransform设置为RotateTransform,并将RotateTransform的Angle绑定到其他控件的值。然而,这确实提出了项目考虑因素(目标平台,学习曲线)以及技术因素(加载WPF DLL的初始开销,互操作约束)。
答案 1 :(得分:1)
Windows绘图模型非常适合您的要求。它分离绘制背景(OnPaintBackground)和前景(OnPaint)。然而,这并不意味着您只能绘制一次背景并完成它。窗口表面无效调用两者。这首先要求使抗锯齿效果正常工作,它们只能对已知的背景颜色看起来很好。
使用它并在OnPaintBackground()覆盖中绘制Image。您可以通过分配BackgroundImage属性让Control自动执行此操作。您可能需要将DoubleBuffer属性设置为true以避免在绘制背景时看到的闪烁,暂时擦除前景像素。如果需要更新前景,请调用Invalidate()。
要完成,你的幻想实际上是可能的。您需要使用顶层分层窗口覆盖图像。使用设置了TransparencyKey属性的Form很容易获得。以下是一个示例实现:
using System;
using System.Drawing;
using System.Windows.Forms;
class OverlayedPictureBox : PictureBox {
private Form mOverlay;
private bool mShown;
public event PaintEventHandler PaintOverlay;
public OverlayedPictureBox() {
mOverlay = new Form();
mOverlay.FormBorderStyle = FormBorderStyle.None;
mOverlay.TransparencyKey = mOverlay.BackColor = Color.Magenta;
mOverlay.ShowInTaskbar = false;
}
protected void OnPaintOverlay(PaintEventArgs e) {
// NOTE: override this or implement the PaintOverlay event
PaintEventHandler handler = PaintOverlay;
if (handler != null) handler(this, e);
}
public void RefreshOverlay() {
// NOTE: call this to force the overlay to be repainted
mOverlay.Invalidate();
}
protected override void Dispose(bool disposing) {
if (disposing) mOverlay.Dispose();
base.Dispose(disposing);
}
protected override void OnVisibleChanged(EventArgs e) {
if (!mShown && !this.DesignMode) {
Control parent = this.Parent;
while (!(parent is Form)) parent = parent.Parent;
parent.LocationChanged += new EventHandler(parent_LocationChanged);
mOverlay.Paint += new PaintEventHandler(mOverlay_Paint);
mOverlay.Show(parent);
mShown = true;
}
base.OnVisibleChanged(e);
}
protected override void OnLocationChanged(EventArgs e) {
mOverlay.Location = this.PointToScreen(Point.Empty);
base.OnLocationChanged(e);
}
protected override void OnSizeChanged(EventArgs e) {
mOverlay.Size = this.Size;
base.OnSizeChanged(e);
}
void parent_LocationChanged(object sender, EventArgs e) {
mOverlay.Location = this.PointToScreen(Point.Empty);
}
private void mOverlay_Paint(object sender, PaintEventArgs e) {
OnPaintOverlay(e);
}
}
一个有趣的工件:最小化表格并再次恢复它看起来,呃,特别。