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

Stronę tą wyświetlono już: 309 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):

  • (Name) - ImCreator;
  • Text - ImCreator;
  • MinimumSize - 799; 265;
  • MaximumSize - 799; 265;
  • Size - 799; 265.

Kontrolka TextBox (nr. 2 na rysunku 1):

  • (Name) - tb_path;
  • Location - 7; 35;
  • Size - 746; 20

Kontrolka Button (nr. 3 na rysunku 1):

  • (Name) - bt_browse;
  • Location - 754; 35;
  • Size - 25; 19

Kontrolka NumericUpDown (nr. 4 na rysunku 1):

  • (Name) - n_maxsize;
  • Maximum - 2000;
  • Minimum - 10;
  • Value - 800;
  • Location - 189; 70;
  • Size - 120; 20

Kontrolka Button (nr. 5 na rysunku 1):

  • (Name) - CreateImg;
  • Location - 7; 107;
  • Size - 771; 25

Kontrolka Label (nr. 6 na rysunku 1):

  • (Name) - lb_progress;
  • Text - Postęp;
  • Location - 11; 144;
  • Size - 40; 13

Kontrolka ProgressBar (nr. 7 na rysunku 1):

  • (Name) - pb_progress;
  • Location - 7; 169;
  • Size - 770; 48;

Komponent FolderBrowserDialog (nr. 8 na rysunku 1):

  • (Name) - fb_dialog;

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:

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

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

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

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:

Listing 3
  1. private void CreateImgFu()
  2. {
  3. EnableWnd(false); // blokowanie okna głównego, tak aby użytkownik nie mógł w nim klikać niczego
  4. if (System.IO.Directory.Exists(tb_path.Text)) // sprawdzanie poprawności ścieżki
  5. {
  6. string[] files_jpg = System.IO.Directory.GetFiles(tb_path.Text + (char)(92), "*.jpg"); // pobieranie listy plików jpg
  7. System.IO.Directory.CreateDirectory(tb_path.Text + "\\sm_img"); // tworzenie nowego folderu
  8. int counting = 0; // licznik przetworzonych obrazów
  9. foreach (string i in files_jpg) // iterowanko po ścieżkach dostępu
  10. {
  11. SetProgressValue( counting * 100 / files_jpg.Length); // ustawianie paska postępu
  12. SetProgressText("Przetwarzanie pliku: " + i); // ustawianie tekstu opisującego plik, kótry aktualnie jest przetwarzany
  13. 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ć
  14. {
  15. continue; // więc przechodzimy do następnej iteracji bez wykonywania dalszego kodu pętli
  16. }
  17. Image img = Image.FromFile(i); // wczytywanie obrazka z pliku
  18. int max_size = (int)n_maxsize.Value; // pobieranie maksymalnego rozmiaru
  19. double k = (double)max_size / (double)(img.Width < img.Height ? img.Height : img.Width); // ustalanie współczynnika skali
  20. int width = (int)(img.Width * k); // obliczanie szerokości obrazu docelowego
  21. int height = (int)(img.Height * k); // obliczanie wysokości obrazu docelowego
  22. if (width > 0 && height > 0) // sprawdzanie, czy otrzymane wartości nie są czasem mniejsze lub równe 0
  23. {
  24. Bitmap bmp = new Bitmap(img, width, height); // tworzę bitmapę na podstawie obrazka o podanych wymiarach
  25. bmp.Save(tb_path.Text + "\\sm_img" + (char)(92) + GetFileName(i), System.Drawing.Imaging.ImageFormat.Jpeg); // zapisuję obrazek z kompresją Jpeg
  26. }
  27. counting++; // zwiększam licznik o 1
  28. }
  29. SetProgressValue(100); // na koniec progress bar na 100 ustawiam
  30. }
  31. EnableWnd(true); // odblokowuję okno
  32. }

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:

Listing 4
  1. private string GetFileName(string mpath) // wyciąganie nazwy pliku z podanej ścieżki
  2. {
  3. int index = mpath.LastIndexOf((char)(92));
  4. string s = mpath.Substring(index + 1);
  5. return s;
  6. }
  7. private void EnableWnd(bool value) // włączanie / wyłączanie aktywności okna
  8. {
  9. if (InvokeRequired) // jeżeli metoda została wywołana w innym wątku niż w tym, w którym została utworzona to
  10. {
  11. Invoke(new Action<bool>(EnableWnd), value); // trzeba skorzystać z metody Invoke
  12. }
  13. else
  14. {
  15. Enabled = value;
  16. }
  17. }
  18. private void SetProgressText(string text)
  19. {
  20. if (InvokeRequired)
  21. {
  22. Invoke(new Action<string>(SetProgressText), text);
  23. }
  24. else
  25. {
  26. lb_progress.Text = text;
  27. }
  28. }
  29. private void SetProgressValue(int value)
  30. {
  31. if (InvokeRequired)
  32. {
  33. Invoke(new Action<int>(SetProgressValue), value);
  34. }
  35. else
  36. {
  37. pb_progress.Value = value;
  38. }
  39. }

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

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

Komentarze