Прозрачный графический очистка буфера? - PullRequest
4 голосов
/ 14 января 2012

В настоящее время я работаю над проектом, в котором мне нужно использовать GDI + (System.Drawing). Я пытаюсь сделать многоцелевой измеритель (колесо в виде часов) с динамическими neeldes на нем.

Я не хочу рисовать фоновое изображение (со всеми отметками) в каждом кадре. Я решил это сейчас, установив его в качестве фонового изображения графического «контейнера», представляющего собой панель (имейте это в виду, возможно, мне придется сделать это по-другому).

Итак, я рисую иглы. Иглы в настоящее время обновляются 25 раз в секунду (я мог бы оптимизировать это, чтобы он обновлялся только при необходимости). Проблема, однако, в том, что мне нужно очистить буфер перед началом работы с новым кадром, чтобы фоновое изображение покрылось фоновым цветом буфера. Очевидно, я этого не хочу.

Я попытался установить цвет фона буфера на Color.Transparent, но вместо этого он дает буферу цвет в соответствии с ключом прозрачности родителя (в моем случае он получается черным).

Вот мой текущий код, используемый для рисования игл (в классе Wheel):

    /// <summary>
    /// Draws the wheel and the needles.
    /// </summary>
    public void Draw()
    {
        Graphics.Clear(Color.Transparent);

        // Draws all needles, works fine
        foreach (Needle Ndl in Needles)
        {
            Ndl.Draw(ref this.Graphics);
        }

        // Draws the little circle in the center of the wheel. Looks only.
        Graphics.FillEllipse(new Pen(Color.White).Brush, new Rectangle(120, 120, 16, 16));
    }

Да, я следовал правилам переполнения стека, я сделал свою домашнюю работу. Другие люди решили эту проблему, просто рисуя изображение в каждом кадре, используя BitBlt, что очень удобно для моего мозга.

Я очень непредубежден в этом вопросе, поэтому, если вы считаете, что я все равно должен использовать BitBlt, и вы знаете, где я могу найти несколько исчерпывающих подробных примеров, я обязательно сделаю это с BitBlt. Конечно, было бы еще лучше, если бы существовали решения без использования BitBlt или если в любом случае не имеет смысла использовать его здесь.

Можно ли сделать фон буфера прозрачным или я должен использовать совершенно другой подход?

Примечание. Я не хочу использовать XNA, так как это приложение будет в основном использоваться в целях обслуживания на простых / старых компьютерах, поэтому я не хочу иметь ничего общего с распространяемыми файлами.

1 Ответ

1 голос
/ 16 января 2012

Вы можете поместить свое базовое изображение в PictureBox. Тогда ваш код может обработать событие Paint в PictureBox, чтобы нарисовать ваши иглы. Таким образом, вам не нужно беспокоиться о прозрачности или медленной работе Graphics.Clear (): ваш код просто должен вычислить положение игл.

В качестве быстрого теста я написал небольшое приложение Forms, которое создает часы с часовой стрелкой (красная), секундной стрелкой (жадность) и миллисекундной стрелкой (синяя). Минутная стрелка не получает уважения и, следовательно, не показывается. Фон представляет собой изображение черного прямоугольника со скругленными углами, созданного в GIMP.

Clock with millisecond hand

Чтобы смоделировать вашу среду, я добавил таймер с интервалом 10 миллисекунд (100 циклов в секунду). Когда обрабатывается событие Timer.Tick, перерисовка PictureBox вызывается принудительно.

Я отредактировал код, чтобы оставить только код для миллисекундной стрелки:

    public Form1()
    {
        InitializeComponent();

        pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);

        Center = new PointF((float)pBox1.Width / 2, (float)pBox1.Height / 2);

        MillisecondLength = (float)pBox1.Width / 4;  //length of millisecond hand

        timer1.Interval = 10;  
        timer1.Enabled = true;
        timer1.Tick += new EventHandler(timer1_Tick);
    }

    PointF Center;

    float MillisecondLength;
    Pen MillisecondsPen = new Pen(Brushes.Blue, (float)3);

    double HALF_PI = Math.PI / 2;
    double TWO_PI = 2 * Math.PI;

    double millisecondHandAngle(DateTime dt)
    {
        //12 o'clock is at the top! (- PI / 2)
        return TWO_PI * dt.Millisecond / 1000 - HALF_PI;
    }

    void pBox1_Paint(object sender, PaintEventArgs e)
    {
        DateTime dt = DateTime.Now;         
        double mangle = millisecondHandAngle(dt);

        SizeF millisecondOffset = new SizeF(
            (float)(MillisecondLength * Math.Cos(mangle)), 
            (float)(MillisecondLength * Math.Sin(mangle))
        );

        PointF endMillisecond = PointF.Add(Center, millisecondOffset);

        e.Graphics.DrawLine(MillisecondsPen, Center, endMillisecond);
    }

    void timer1_Tick(object sender, EventArgs e)
    {
        pBox1.Invalidate();
    }

Хотя это не показано в этом коде, я добавил System.Diagnostics.Stopwatch и переменную счетчика, чтобы вычислить фактическую частоту кадров, которая на моем старом ноутбуке достигала пика около 64 кадров в секунду. Даже если вы установите очень малый интервал таймера, существует максимальная скорость перерисовки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...