none
BufferedGraphics. Не получается нарисовать прямоугольник так, чтобы он не мерцал. Справка MSDN не помогает. RRS feed

  • Вопрос

  • Здравствуйте! Есть такая проблема, я пишу к своей программе одну функцию, которая будет примерно из себя представлять, то что из себя представляют "Ножницы" в Windows 7. До этого я рисовал прямоугольник, но он мерцал сильно из-за того, что форма сразу заполнялась жёлтым цветом, как бы стерала прошлый прямоугольник, чтобы не оставал на форме много прошлых прямоугольников. Это проект чисто, чтобы научиться делать, то что у меня сейчас не получается и потом исспользовать его в своей программе. Идея такая. Жму на кнопку, сворачивается главное окно, делается скриншот. Открывается окно formBack растягивается на весь экран и становиться поверх всех окон, вырисовывает на себе скриншот. Сразу же после этого растягивается на весь экран form1 с прозрачностью 30%, жёлтым фоном и свойством TransparencyKey == Color.White; Далее я выделяю область курсором мыши, отрисовываю прямоугольник, заливаю его белым цветом, чтобы он внутри стал прозрачным и соответстенно выделялся, тем что внутри прямоугольника видно скриншот в нормальном цвете, как в "Ножницы", в Windows 7. Вот я, что только не пробовал, что толь читал, не получается у меня это сделать и всё. Помогите, кто умеет пожалуйста. Вот исходники

    У меня не получается тепеь вообще отрисовать прямоугольник.  я что-то не совсем понимаю, что и для чего BufferedGraphics и BufferedGraphicsContext, читал описание и т.д. Всё равно не понятно, что они делают физически (если так можно выразиться). Я понимаю так: рисуется что мне надо не выводя на экран, а потом готовое выводиться. Но этого мало, чтобы заставить работать код. Не на одном форуме не ответили на этот вопрос.

    Здесь возможно некоторые увидят лишнее, что-то, я просто очень много раз код менял. Вот код:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace WindowsFormsApplication8
    {
        public partial class Form1 : Form
        {
            Bitmap bmp;
            Rectangle rectSelected; //прямоугольник которым выделяют
            Rectangle rectBack; //прямоугольник для заливки всего окна
            Size size;
            Point clickPoint;
            Point nowPoint;
            Graphics gr;
            Pen pen;
            SolidBrush brushWhite, brushBack; //кисти
            Form formBack; //форма, которая будет содержать на себе скриншот
            public BufferedGraphics bufferedGraphics;
            public BufferedGraphicsContext bufferedGraphicsContext;
    
            public Form1()
            {
                InitializeComponent();
                gr = Graphics.FromHwnd(this.Handle);
                this.bufferedGraphicsContext = BufferedGraphicsManager.Current;
                this.bufferedGraphicsContext.MaximumBuffer = new Size(this.Width, this.Height);
                this.bufferedGraphics = bufferedGraphicsContext.Allocate(gr,
                    new Rectangle(new Point(rectSelected.X, rectSelected.Y), new Size(rectSelected.Width + 1, 
                rectSelected.Height + 1)));
    
                 //this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
                 //    ControlStyles.AllPaintingInWmPaint, true);
                
            }
    
            /// <summary>
            /// Загрузка формы
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void Form1_Load(object sender, EventArgs e)
            {
                size = new Size(0, 0);
                clickPoint = new Point(0, 0);
                nowPoint = new Point(0, 0);
                rectSelected = new Rectangle(nowPoint, size);
               
                formBack = new FormBackground(); //форма для скриншота, позади жёлтой формы находиться
                brushWhite = new SolidBrush(Color.White); //для заполнения внутренней части выделяемого прямоугольника, чтобы
                //жёлтое окно стало прозрачным внутри прямоугольника
                brushBack = new SolidBrush(Color.FromArgb(255, 255, 192)); 
    
                pen = new Pen(Color.Blue, 2); //то чем рисуется выделяемая область
                rectBack = Screen.PrimaryScreen.Bounds; 
            }
    
            /// <summary>
            /// Перейти в режим выделения области на экране для последующего её сохранения в файл
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void button1_Click(object sender, EventArgs e)
            {
    
                this.WindowState = FormWindowState.Minimized;
                formBack.WindowState = FormWindowState.Minimized;
                formBack.FormBorderStyle = FormBorderStyle.None;
                formBack.TopMost = true;
                formBack.ControlBox = false;
    
                this.TransparencyKey = Color.White;
                this.BackColor = Color.FromArgb(255, 255, 192);
                this.FormBorderStyle = FormBorderStyle.None;
                this.TopMost = true;
                this.button1.Visible = false;
                this.btnClose.Visible = true;
                this.Opacity = 0.3; 
                this.contextMenuStrip1.Items[0].Enabled = true;
                this.Cursor = Cursors.Cross; //заменяет курсор крестиком
        
                for (int i = 0; i < 1; i++)
                {
                    Thread.Sleep(500);
                }
                CreateScreenshot();
                formBack.BackgroundImage = bmp;
    
                formBack.WindowState = FormWindowState.Maximized;
                this.WindowState = FormWindowState.Maximized;
                this.Visible = true;
                formBack.Visible = true;
                this.Activate();
    
               // bmpScreenshot.Save(Application.StartupPath + "\\" + "ScreenShot.png", ImageFormat.Png);
            }
    
            /// <summary>
            /// Происходит перед закрытием формы
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                //if (MessageBox.Show("Вы хотите завершить работу программы?", "Выйти из программы?", MessageBoxButtons.YesNo)
                //    == DialogResult.Yes)
                //{
                //}
                //else
                //{
                //    e.Cancel = true;
                //}
            }
    
            /// <summary>
            /// Отпускание кнопки мыши на форме
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void Form1_MouseUp(object sender, MouseEventArgs e)
            {
                //Bitmap bmp = new Bitmap(rectSelected.Width, rectSelected.Height);
                //Graphics gfxScreenshot;
                //gfxScreenshot = Graphics.FromImage(bmp);
                //gfxScreenshot.CopyFromScreen(rectSelected.Location, Point.Empty, bmp.Size);
                //bmp.Save(Application.StartupPath +"\\"+ "image.bmp", ImageFormat.Bmp);
                this.Cursor = Cursors.Default; //восстановить курсор по умолчанию
            }
    
            /// <summary>
            /// Зажатие кнопки мыши на форме
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void Form1_MouseDown(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left) //если нажата левая кнопка мыши
                {
                    clickPoint.X = e.Location.X;
                    clickPoint.Y = e.Location.Y;
                }
            }
    
            /// <summary>
            /// Движение мыши по форме
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void Form1_MouseMove(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    //gr.DrawRectangle(pen, rectSelected); //рисуем прямоугольник которым выделяем область
    
                    nowPoint.X = e.X;
                    nowPoint.Y = e.Y;
                    if (nowPoint.X > clickPoint.X)
                    {
                        size.Width = nowPoint.X - clickPoint.X; //вычитаем из места где был первый клик текущее 
                        rectSelected.X = clickPoint.X;
                    }
                    else
                    {
                        size.Width = clickPoint.X - nowPoint.X;
                        rectSelected.X = clickPoint.X - size.Width;                    
                    }
    
                    if (nowPoint.Y > clickPoint.Y)
                    {
                        size.Height = nowPoint.Y - clickPoint.Y;
                        rectSelected.Y = clickPoint.Y;
                    }
                    else
                    {
                        size.Height = clickPoint.Y - nowPoint.Y;
                        rectSelected.Y = clickPoint.Y - size.Height;
                    }
    
                    rectSelected.Width = size.Width;
                    rectSelected.Height = size.Height;
    
                    this.bufferedGraphicsContext.MaximumBuffer = new Size(size.Width + 1, size.Height + 1);
                    this.bufferedGraphics = bufferedGraphicsContext.Allocate(gr,
                        new Rectangle(new Point(clickPoint.X, clickPoint.Y), new Size(size.Width + 1, size.Height + 1)));
    
                    Rectangle rectSel = new Rectangle(rectSelected.X, rectSelected.Y, rectSelected.Width, rectSelected.Height);
                    Rectangle rectBackground = new Rectangle(0, 0, formBack.Width, formBack.Height);
                    bufferedGraphics.Graphics.DrawRectangle(Pens.Red, rectSel);
                    bufferedGraphics.Graphics.FillRectangle(brushWhite, rectSelected);
                    bufferedGraphics.Graphics.FillRectangle(brushBack, rectBackground);
                    bufferedGraphics.Render(gr);
                }
            }
    
            /// <summary>
            /// Нажатие по кнопке "Закрыть"
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void btnClose_Click(object sender, EventArgs e)
            {
                this.Close();
            }
    
            /// <summary>
            /// Восстановить вид окна на начальный
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void вернутьОбратноToolStripMenuItem_Click(object sender, EventArgs e)
            {
                this.FormBorderStyle = FormBorderStyle.FixedSingle;
                this.TopMost = false; //сделать НЕ поверх всех окон
                this.WindowState = FormWindowState.Normal; //стиль окна "Нормальный"
                this.button1.Visible = true; 
                this.btnClose.Visible = false;
                this.contextMenuStrip1.Items[0].Enabled = false;
            }
    
    
            /// <summary>
            /// Выйти из приложения
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void выходToolStripMenuItem_Click(object sender, EventArgs e)
            {
                Application.Exit(); //выход из приложения
            }
    
            public void CreateScreenshot()
            {
                Bitmap bmpScreenshot;
                Graphics gfxScreenshot;
                bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
                gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0,
                    Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
                bmp = new Bitmap(bmpScreenshot);
            }
        }
    }
    • Изменен тип I.Vorontsov 26 марта 2010 г. 6:45
    • Перемещено Tagore Bandlamudi 2 октября 2010 г. 21:57 MSDN Forums consolidation (От:Разработка Windows-приложений)
    25 марта 2010 г. 16:47

Ответы

  • Да уж, делал вообще наугад. Вчера посидел внимательно посмотрел примеры в справке и поял, как вообще буфер работает. н же прорисовывает какртину, а потом только выводит. Сделал, теперь всё работает на ура. Может всё таки в тонкости я не вник, да и пока особо не высматривал, что к чему времени неыло . Ну вот получилось у меня так:

            /// <summary>
            /// Отрисовываем всё в буфере
            /// </summary>
            public void DrawTOBuffer()
            {   //выставляем размер буфера "весь экран"
                bufferGraphicsContext.MaximumBuffer = new Size(this.Width + 1, this.Height + 1);
                
                bufferGraphics = bufferGraphicsContext.Allocate(gr,
                     new Rectangle(0, 0, this.Width + 1, this.Height + 1)); //создаём буфер
    
                bufferGraphics.Graphics.FillRectangle(brushBack, rectBack); //стераем прошлый рисунок
                bufferGraphics.Graphics.DrawRectangle(pen, rectSelected); //рисуем новый прямоугольник
                bufferGraphics.Graphics.FillRectangle(br, rectSelected); //заливаем его цветом
            }

    В обработчике MouseMove:

            /// <summary>
            /// Движение мыши по форме
            /// </summary>
            /// <param name="sender">Отправитель</param>
            /// <param name="e">Аргументы</param>
            private void Form1_MouseMove(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    nowPoint.X = e.X;
                    nowPoint.Y = e.Y;
                    if (nowPoint.X > clickPoint.X)
                    {
                        size.Width = nowPoint.X - clickPoint.X; //вычитаем из места где был первый клик текущее 
                        rectSelected.X = clickPoint.X;
                    }
                    else
                    {
                        size.Width = clickPoint.X - nowPoint.X;
                        rectSelected.X = clickPoint.X - size.Width;                    
                    }
    
                    if (nowPoint.Y > clickPoint.Y)
                    {
                        size.Height = nowPoint.Y - clickPoint.Y;
                        rectSelected.Y = clickPoint.Y;
                    }
                    else
                    {
                        size.Height = clickPoint.Y - nowPoint.Y;
                        rectSelected.Y = clickPoint.Y - size.Height;
                    }
                    
                    rectSelected.Width = size.Width;
                    rectSelected.Height = size.Height;
                   
                    DrawTOBuffer(); //Производим отрисовку в буфере
                    bufferGraphics.Render(); //выводим, то что отрисовалось в буфере
                }
            }

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

                this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
                gr = Graphics.FromHwnd(this.Handle);
                bufferGraphicsContext = new BufferedGraphicsContext();
                bufferGraphicsContext = BufferedGraphicsManager.Current;
    Окаывается это прое простого всё делается. Я просто вообще не понмал, что делают эти классы BufferedGraphics и BufferedGraphicsContext
    • Помечено в качестве ответа I.Vorontsov 26 марта 2010 г. 6:45
    26 марта 2010 г. 5:33