Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > Опять progressbar


Автор: maxnoskov 7.2.2007, 10:54
есть главная форма, в которой выполняется работа с базой. Параллельно, в отдельном потоке хочу выводить окно с прогрессбаром. Почему данный код не работает:
Код

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private Form2 LoadForm = new Form2();
        private void Form1_Load(object sender, EventArgs e)
        {
            sqLiteDataAdapter1.Fill(dataSet11, "first");
        }
        
        private void ProcessDo()
        {
            LoadForm.progressBar1.Invoke(new MethodInvoker(delegate()
            {
            for (; ; )
            {
                if (LoadForm.progressBar1.Value >= LoadForm.progressBar1.Maximum) LoadForm.progressBar1.Value = 0;
                LoadForm.progressBar1.Value++;
            }
        }));
        }

        private void button1_Click(object sender, EventArgs e)
        {
            System.Threading.Thread thr = new System.Threading.Thread(ProcessDo);
            if (LoadForm == null) LoadForm = new Form2();
            LoadForm.Show();
            thr.Start();
            
            for (int i = 0; i < 100; i++)
            {
                DataRow NewDataRow = dataSet11.first.NewRow();
                dataSet11.first.Rows.Add(NewDataRow); 
            }
            sqLiteDataAdapter1.Update(dataSet11, "first");
            dataSet11.AcceptChanges();
            //ds.ReadXML(path);
            thr.Abort();
            LoadForm.Close();
            LoadForm.Dispose();
        }
    }


Автор: ivashkanet 7.2.2007, 10:59
Цитата

Код

            LoadForm.progressBar1.Invoke(new MethodInvoker(delegate()
            {
            for (; ; )
            {
                if (LoadForm.progressBar1.Value >= LoadForm.progressBar1.Maximum) LoadForm.progressBar1.Value = 0;
                LoadForm.progressBar1.Value++;
            }


 smile  smile  smile  smile  smile  smile 

Пручать основному потоку что-то сделать нужно очень в малых количествах и только если без этого действительно нельзя.

Код

            while (true)
            {
                LoadForm.progressBar1.Invoke(new MethodInvoker(delegate()
                {

                    if (LoadForm.progressBar1.Value >= LoadForm.progressBar1.Maximum) LoadForm.progressBar1.Value = 0;
                    LoadForm.progressBar1.Value++;
                }));

                Thread.Sleep(100); // останавливаем поток на 1/10 секунды
            }


Автор: maxnoskov 7.2.2007, 11:19
Тот же результат, появляется окно, но progressbar не бежит - мертвый

Автор: ivashkanet 7.2.2007, 11:25
Цитата
Код

            for (int i = 0; i < 100; i++)
            {
                DataRow NewDataRow = dataSet11.first.NewRow();
                dataSet11.first.Rows.Add(NewDataRow); 
            }
            sqLiteDataAdapter1.Update(dataSet11, "first");
            dataSet11.AcceptChanges();


Это называется чудеса на виражах:
Прогрессбар бежит в отдельном потоке, а вот тяжелая работа идет в потоке формы smile

Тебе нужно сделать наоборот: тяжелую работу вынести в отдельный поток, а прогресбар может даже бежать в той же самой форме

Автор: maxnoskov 7.2.2007, 11:32
Если не сложно, можно пример относительно данного случая smile 

Автор: ivashkanet 7.2.2007, 12:24
Даааа, не так все было просто как мне казалось smile 
Код

    public partial class Form1 : Form
    {
        ProgressForm _pForm;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _pForm = new ProgressForm();
            _pForm.Show();
            _pForm.StartPBar();

            Thread thr = new System.Threading.Thread(ProcessDo);
            thr.Start();
        }

        private void ProcessDo()
        {
            //for (int i = 0; i < 100; i++)
            //{
            //    DataRow NewDataRow = dataSet11.first.NewRow();
            //    dataSet11.first.Rows.Add(NewDataRow);
            //}
            //sqLiteDataAdapter1.Update(dataSet11, "first");
            //dataSet11.AcceptChanges();

            long j = 10;

            for (long i = 0; i < 2000000000; i++)
            {
                j += i;
                j -= i;
            }

            EndJob();
        }

        private void EndJob()
        {
            this.Invoke(new MethodInvoker(delegate()
            {
                _pForm.Close();
                _pForm.Dispose();

                MessageBox.Show("Job is done");
            }));
        }
    }


    public class ProgressForm : Form
    {
        ProgressBar _progressBar;
        Thread _thread;

        public ProgressForm()
        {
            _progressBar = new ProgressBar();
            this.SuspendLayout();

            _progressBar.Dock = DockStyle.Fill;

            this.ClientSize = new System.Drawing.Size(200, 20);
            this.Controls.Add(_progressBar);
            this.Name = "ProgressForm";
            this.Text = "Processing, please wait";
            this.FormClosing += new FormClosingEventHandler(ProgressForm_FormClosing);

            this.ResumeLayout(false);
        }

        public void StartPBar()
        {
            _thread = new System.Threading.Thread(ProcessPBar);
            _thread.Priority = ThreadPriority.AboveNormal;
            _thread.Start();
        }

        private void ProcessPBar()
        {
            try
            {
                while (true)
                {
                    IncreasePBar();

                    Thread.Sleep(100);
                }
            }
            catch (ThreadAbortException) {/* Просто способ завершения потока */}
        }

        public void IncreasePBar()
        {
            this.Invoke(new MethodInvoker(delegate()
            {
                if (_progressBar.Value >= _progressBar.Maximum)
                    _progressBar.Value = 0;
                _progressBar.Value++;
            }));
        }

        void ProgressForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Закрываем поток
            _thread.Abort();
            _thread.Join();
        }
    }


Я бы не делал отдельную форму для прогрессбара, а поместил бы его в строку состояния, например.

P.S. Приму любые замечания по коду.

Автор: maxnoskov 7.2.2007, 13:05
Спасибо большое, огромный респект. По поводу примечания, а как запхать progressbar в строку состояния. Я даже ни разу с таким не сталкивался

Автор: ivashkanet 7.2.2007, 14:15
Цитата(maxnoskov @  7.2.2007,  12:05 Найти цитируемый пост)
Спасибо большое, огромный респект

Не за что smile

Примечания:
1) Форму с баром нужно сделать поверх приложения. ShowDialog() не подходит, так как ждет завершения работы формы.
2) При закрытии основной формы вылетает эксепшин на IncreasePBar()ю Решение --- закрывать вторую форму при закрытии первой.
3) Вместо второго потока (для  прогресс бара) лучше использовать таймер

Цитата(maxnoskov @  7.2.2007,  12:05 Найти цитируемый пост)
Я даже ни разу с таким не сталкивался

Я тоже не пробовал. Но У MSDN, Word и др. эта хрень есть smile

Так же можно попробовать вместо формы использовать usercontrol (прогрессбар и немного места вокруг него, как на Винграде) и делать ему BringToFront()

Автор: maxnoskov 7.2.2007, 15:08
Можно в принципе вынести progressbar в statusStrip и юзать ее на форме. Но так как основным потоком должен идти какой-то процесс - не прогресс, я не знаю как мне в основном потоке циклически запустить прогресс и как его убить - как я узнаю, что основной процесс уже завершился? 

Автор: ivashkanet 7.2.2007, 15:10
Цитата(maxnoskov @  7.2.2007,  14:08 Найти цитируемый пост)
Но так как основным потоком должен идти какой-то процесс - не прогресс

Этот процесс лучше выделить в отдельный поток
Цитата(maxnoskov @  7.2.2007,  14:08 Найти цитируемый пост)
как я узнаю, что основной процесс уже завершился

EndJob()

Автор: Berserk 7.2.2007, 15:19
А если есть желание поработать с потоками, то можно кинуть на форму BackgroundWorker. Неплохо описано http://www.rsdn.ru/article/dotnet/WinForms20.xml. Можно код с примером скачать.

Автор: maxnoskov 7.2.2007, 16:03
Решил проблему - вынес progressbar в statusStrip. Запускаю его по таймеру. А основной процесс в отдельном потоке. Когда основной процесс заканчивается - останавливаю таймер.
P.S. отдельная благодарность -  ivashkanet. Без него бы не справился smile 

Автор: ivashkanet 7.2.2007, 16:11
maxnoskov, о, оно самое.
Для закрытия вопроса положи сюда код, а.

Автор: maxnoskov 9.2.2007, 10:19
Конечно, закрываю вопрос:
Код

 public partial class Form1 : Form
    {
        private System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();//Создаем таймер
        Thread _thread1 = null;
        
        public Form1()
        {
            InitializeComponent();
         }
        
        private void button1_Click(object sender, EventArgs e)
        {
            timer2.Interval = 10;
            timer2.Start();
            _thread1 = new Thread(Process);
            _thread1.Start();
            this.Invoke(new MethodInvoker(delegate()
                  {
                      toolStripStatusLabel1.Text = "Подождите...";
                  }));
            
        }

        private void Thread_exit()
        {
            if (_thread1 != null)
            {
                  timer2.Stop();//Вырубаем таймер
                  this.Invoke(new MethodInvoker(delegate()
                  {
                      toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
                      toolStripStatusLabel1.Text = "Операция завершена";
                  }));
                 _thread1.Abort();//Убиваем поток
                _thread1.Join();
            }
            
        }

        void Process()//Здесь тот процесс, который будет выполнятся в дополнительном потоке
        {
            for (int i = 0; i < 50; i++)
            {
                DataRow NewDataRow = dataSet11.first.NewRow();
                dataSet11.first.Rows.Add(NewDataRow);
            }
            sqLiteDataAdapter1.Update(dataSet11, "first");
            dataSet11.AcceptChanges();
            Thread_exit();
            
        }
        
        private void timer2_Tick(object sender, EventArgs e)//Здесь работает прогрессбар
        {
            if (this.toolStripProgressBar1.Value + 1 == this.toolStripProgressBar1.Maximum)
                this.toolStripProgressBar1.Value = 0;
            else
                this.toolStripProgressBar1.Value++;
            Thread.Sleep(10);
        }
    }

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

Автор: maxnoskov 15.2.2007, 14:29
Цитата(Berserk @ 7.2.2007,  15:19)
А если есть желание поработать с потоками, то можно кинуть на форму BackgroundWorker. Неплохо описано http://www.rsdn.ru/article/dotnet/WinForms20.xml. Можно код с примером скачать.

Да, с BackgroundWorker получилось даже красивее. Спасибо за ссылку.
Цитата

Единственная проблема - это то, что другие объекты на форме являются активными. Ну например меню. Если не хочется, чтобы во время операции пользователь совершал другие действия - ну не смотрит он на прогрессбар или не хоче смотреть. Надо эти элементы закрывать. 

А ларчик то просто открывается. В смысле проблемы нет - подвязываемся на FormClosing и делаем Enable = false для меню пока работает доп. поток 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)