2009-12-29 3 views
1

меня есть элемент управления WinForms, на котором я хочу, чтобы отобразить две вещи:Перекрытие System.Drawing.Graphics объекты

  1. Основополагающим изображение тщательно загружается бит за битом от внешнего устройства ввода; и
  2. Серия вызовов DrawLine, которые создают визуальный шаблон над этим изображением.

Вещь № 1, для наших целей, не изменяется, и я не хочу ее перерисовывать.

Вещь № 2 должна быть перерисована относительно быстро, поскольку она вращается, когда пользователь поворачивает другой элемент управления.

В моей фантазии я хочу поместить каждую вещь в свой собственный объект Graphics, дать # 2 прозрачный фон и просто нажать # 2 с вращательным преобразованием в соответствии с настройкой пользовательского управления. Но я не вижу способа сделать объект Graphics прозрачным, а также способ повернуть то, что уже нарисовано на нем. Поэтому я, вероятно, попрошу Graphics сделать то, для чего он не предназначен.

Вот мой вопрос: что лучше всего настроить? Должен ли я пытаться перекрывать объекты Graphics, или есть какой-то совершенно другой и лучший способ сделать это, о котором я не думаю?

ответ

1

Модель окраски Windows подходит для ваших требований. Он отделяет рисование фона (OnPaintBackground) с переднего плана (OnPaint). Это, однако, не означает, что вы можете рисовать только один раз и делать это с ним. Недействительность поверхности окна вызывает оба. Это, прежде всего, необходимо, чтобы эффекты сглаживания работали должным образом, они могут только хорошо выглядеть против известного цвета фона.

Пунт это и нарисуйте изображение в переопределении OnPaintBackground(). Вы можете позволить Control сделать это автоматически для вас, назначив свойство BackgroundImage.Вероятно, вам нужно установить для свойства DoubleBuffer значение true, чтобы избежать мерцания, которое вы увидите при рисовании фона, временно вытирая пиксели переднего плана. Вызовите Invalidate(), если вам нужно обновить передний план.

Чтобы быть полной, ваша фантазия на самом деле возможна. Вам нужно будет наложить изображение с помощью многослойного окна. Это легко получить с помощью формы, чье свойство TransparencyKey установлено. Вот пример реализация:

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

один интересный артефакт: сведение к минимуму формы и восстановить его снова выглядит, эм, особенная.

1

GDI + не сохранен в режиме ожидания, поэтому вам нужно будет перерисовать весь элемент управления на каждой краске. К сожалению, вы не можете просто иметь две «вещи» и применить поворот к одному из них. Ваш лучший выбор с GDI +, вероятно, является:

  • Магазин № 1 в изображении объекта. (Вы можете предварительно визуализировать элементы с помощью Graphics.FromImage, либо на основе предварительно сконфигурированного битового изображения .)
  • Магазин №2 как набор пар координат.

Затем в обработчике Paint перерисовывайте # 1 быстро используя Graphics.DrawImage, установите поворотное преобразование, используя Graphics.RotateTransform, и нарисуйте свои линии. Вы должны иметь возможность сделать это гладким, используя двойную буферизацию (ControlStyles.DoubleBuffer).

Что касается «совершенно разных» способов сделать это, то «фантазия», которую вы описываете, называется Windows Presentation Foundation. WPF имеет графическую систему с сохраненным режимом и может более удобно обрабатывать «вращать один слой, сохраняя при этом другую константу». И вы можете разместить WPF в WinForms с помощью элемента управления ElementHost. Грубая идея состояла бы в том, чтобы использовать сетку для наложения холста на изображение, добавить объекты линии к холсту, установить Canvas 'RenderTransform в RotateTransform и привязать угол RotateTransform к другому значению элемента управления. Однако это повышает требования к проекту (целевая платформа, кривая обучения), а также технические (начальные накладные расходы на загрузку библиотек WPF, ограничения взаимодействия).

+0

Оба ответа были потрясающими. Я должен был выбрать один. :-( – catfood

Смежные вопросы