Wykorzystanie kontrolek NumericUpDown, ProgressBar, komponentu okna dialogowego FolderBrowserDialog oraz użycie wątków

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 2411 razy

Stwórzmy czym prędzej nowy projekt programu ImageResize, który będzie służył do generowania miniatur zdjęć znajdujących się w podanej lokalizacji i zapisywanie ich do specjalnie utworzonego folderu o nazwie sm_img. Na poniższym rysunku pokazany został widok okna programu.

Projekt okna programu
Rys. 1
Projekt okna tworzonego programu.

Ustawienie właściwości okna głównego (nr. 1 na rysunku 1):

Kontrolka TextBox (nr. 2 na rysunku 1):

Kontrolka Button (nr. 3 na rysunku 1):

Kontrolka NumericUpDown (nr. 4 na rysunku 1):

Kontrolka Button (nr. 5 na rysunku 1):

Kontrolka Label (nr. 6 na rysunku 1):

Kontrolka ProgressBar (nr. 7 na rysunku 1):

Komponent FolderBrowserDialog (nr. 8 na rysunku 1):

Tekst i rozmieszczenie dwóch pozostałych kontrolek Label widoczne jest na rysunku 1, toteż ich nie opisuję.

Pod kontrolkę 3 podpiąć należy zdarzenie Click:

private void bt_browse_Click(object sender, EventArgs e) { if (fb_dialog.ShowDialog() == DialogResult.OK) // wyświetlenie okna dialogowego Folder Browser i sprawdzenie, czy wciśnięto przycisk OK { tb_path.Text = fb_dialog.SelectedPath; // jeżeli przycisk OK został wciśnięty to pobrać należy ścieżkę do wskazanego folderu } }

Kontrolka 5 na rysunku 1 powinna zostać podpięta pod zdarzenie Click:

private void CreateImg_Click(object sender, EventArgs e) { System.Threading.Thread thr = new System.Threading.Thread(CreateImgFu); // tworzenie nowego obiektu wątku, parametrem konstruktora jest delegat CreateImgFu thr.Start(); // uruchomienie wątku }

Jak widać w powyższym kodzie tworzę nowy wątek i go uruchamiam. Wątkiem tym będzie działanie wewnątrz metody CreateImgFu, której kod będzie wyglądał następująco:

private void CreateImgFu() { EnableWnd(false); // blokowanie okna głównego, tak aby użytkownik nie mógł w nim klikać niczego if (System.IO.Directory.Exists(tb_path.Text)) // sprawdzanie poprawności ścieżki { string[] files_jpg = System.IO.Directory.GetFiles(tb_path.Text + (char)(92), "*.jpg"); // pobieranie listy plików jpg System.IO.Directory.CreateDirectory(tb_path.Text + "\\sm_img"); // tworzenie nowego folderu int counting = 0; // licznik przetworzonych obrazów foreach (string i in files_jpg) // iterowanko po ścieżkach dostępu { SetProgressValue( counting * 100 / files_jpg.Length); // ustawianie paska postępu SetProgressText("Przetwarzanie pliku: " + i); // ustawianie tekstu opisującego plik, kótry aktualnie jest przetwarzany if (System.IO.File.Exists(tb_path.Text + "\\sm_img" + (char)(92) + GetFileName(i))) // jeżeli dany plik już istnieje to nie chcemy go nadpisywać { continue; // więc przechodzimy do następnej iteracji bez wykonywania dalszego kodu pętli } Image img = Image.FromFile(i); // wczytywanie obrazka z pliku int max_size = (int)n_maxsize.Value; // pobieranie maksymalnego rozmiaru double k = (double)max_size / (double)(img.Width < img.Height ? img.Height : img.Width); // ustalanie współczynnika skali int width = (int)(img.Width * k); // obliczanie szerokości obrazu docelowego int height = (int)(img.Height * k); // obliczanie wysokości obrazu docelowego if (width > 0 && height > 0) // sprawdzanie, czy otrzymane wartości nie są czasem mniejsze lub równe 0 { Bitmap bmp = new Bitmap(img, width, height); // tworzę bitmapę na podstawie obrazka o podanych wymiarach bmp.Save(tb_path.Text + "\\sm_img" + (char)(92) + GetFileName(i), System.Drawing.Imaging.ImageFormat.Jpeg); // zapisuję obrazek z kompresją Jpeg } counting++; // zwiększam licznik o 1 } SetProgressValue(100); // na koniec progress bar na 100 ustawiam } EnableWnd(true); // odblokowuję okno }

W powyższym kodzie użyłem czterech dodatkowych metod, gdzie trzy z nich są wymagane w celu uzyskania dostępu do zmiennych w nowo utworzonym wątku. Kod źródłowy tych metod jest następujący:

private string GetFileName(string mpath) // wyciąganie nazwy pliku z podanej ścieżki { int index = mpath.LastIndexOf((char)(92)); string s = mpath.Substring(index + 1); return s; } private void EnableWnd(bool value) // włączanie / wyłączanie aktywności okna { if (InvokeRequired) // jeżeli metoda została wywołana w innym wątku niż w tym, w którym została utworzona to { Invoke(new Action<bool>(EnableWnd), value); // trzeba skorzystać z metody Invoke } else { Enabled = value; } } private void SetProgressText(string text) { if (InvokeRequired) { Invoke(new Action<string>(SetProgressText), text); } else { lb_progress.Text = text; } } private void SetProgressValue(int value) { if (InvokeRequired) { Invoke(new Action<int>(SetProgressValue), value); } else { pb_progress.Value = value; } }

Najtrudniejsze na sam koniec, czyli kompilacja programu i jego uruchomienie.

Program ImgCreator w akcji.
Rys. 2
Program ImgCreator w akcji.