Das mit den vielen Bilder ist auch durch ein Zufall entstanden, ich habe von einem Freund eine Ordner bekommen.
In den Ordner packt er alle Bilder von seinen SD-Karten hinein. Der Ordner beinhaltet 2800 Bilder.
Das habe ich erst mitbekommen als das Exception
kam, abgesehen davon das es sehr lange gedauert hat.
Er ist Hobby Fotograf.
Das Programm an dem ich bastel ist eigentlich für Ihn gedacht damit er die Bilder von den SD-Karten in seine Ordner Struktur einsortieren kann und gleichzeitig die Dateien Umbenennt.
Nur leider mit einem ListView, wenn ein Eintrag selektiert wird ein kleines Vorschaubild angezeigt. Etwas mühselig, weil man nicht sehen kann welche Bilder zu einer Gruppe gehören.
Von der Idee mit den Thumbnails Ansicht weis er noch nichts. Wenn ich es hinbekomme erleichtert es Ihm die Arbeit.
Noch mal vielen Dank für deine Hilfestellung.
Der nächste schritt ist mehrfach Selektieren und Caching (Sqlite).
PS: Kannst Du mir Bücher empfehlen in den mehr auf den Internen Ablauf eingehen (Bevorzugt in Deutsch)
Okay 20 Jahre ist wirklich alt.
Diesen teil hatte ich bei Listview abgeschaut und um es besser verstehen zu können habe ich es in abgespeckter Form nach gebaut. Dabei geht es darum wenn einer Liste etwas hinzugefügt wird wie das Listview davon informiert wird und sich neu Zeichnet. Das verwendete Kollektion hat kein Array aber dafür einen owner und damit kann dann eine Methode im Listview aufgerufen werden.
Ich habe inzwischen die beiden Oldies ArrayList und HasTable durch List<T> ersetzt.
Meinst du "Dimensions" (anstatt "Dimentions")?
Ja, danke für den Hinweis ich hab es geändert.
In der ersten Version hatte ich das Grid von dir verwendet. Bei einem Testlauf flog ein Exception
„Handle kann nicht erstellt werden. Das passiert etwa bei 1244 Einträgen.
Auch hier zum Lernen habe ich ein versuch mit OnPaint
und selber Zeichnen probiert.
Mit der OnPaint
version hat es geklappt. Ich vermute das die Anzahl an Controls
überschritten wurde.
Das mit dem AutoScrollMinSize
klappt super auch hier ein dickes Dank.
Ein Frage habe ich noch und zwar hatte ich Probleme das DoubleBuffered
auf true
zustellen.
Die Ursache war das ich Graphics
in einen Using-Block
gepackt habe, auf einer Seite im Netz habe ich dann gelesen das DoubleBuffered das Graphics Ojekt bracht. Jetzt habe ich den Using-Block entfernt aber wie und wo Dispose ich das Graphics-Objkt?
Nachtrag
PictureListView.cs
hat zu viele Zeichen des wegen im Anhang
Die Berechnung für das Scrollen wie kann man das besser und einfacher machen?
Wahrscheinlich nicht das Testprogramm das du dir vorgestellt hast.
Hallo Th69
habe eine neues einfachen Versuchs Projekt angelegt.
In deinem letzten post hast du auf [FAQ] Flackernde Controls vermeiden / Schnelles, flackerfreies Zeichnen hingewiesen.
Also habe ich ein Klasse erstellt die von Control
ableitet und die OnPaint
überschrieben.
Das Zeichnen sowie Scrollen und Selektieren habe ich hinbekommen mehr schlecht als Recht.
Mein Code sieht Katastrophal aus und es bedarf noch die eine oder andere Verbesserung.
PictureListItem.cs
public class PictureListItem
{
private string _textDimentions;
private string _textName;
private Image _thumb;
public string TextName
{
get { return _textName; }
set { _textName = value; }
}
public string TextDimentions
{
get { return _textDimentions; }
set { _textDimentions = value; }
}
private string _textDate;
public string TextDate
{
get { return _textDate; }
set { _textDate = value; }
}
public Image Thumbnail
{
get
{
return _thumb;
}
set
{
_thumb = value;
}
}
public bool Selected { get; set; }
private Rectangle _bounds;
public Rectangle Bounds
{
get { return _bounds; }
set
{
if(!value.Equals(_bounds))
_bounds = value;
}
}
private int _index = -1;
public int Index
{
get { return _index; }
set { _index = value; }
}
public PictureListItem(string textName, string textDimentions, string textDate, Image thumb)
{
_textName = textName ?? throw new ArgumentNullException(nameof(textName));
_textDimentions = textDimentions ?? throw new ArgumentNullException(nameof(textDimentions));
_textDate = textDate ?? throw new ArgumentNullException(nameof(textDate));
_thumb = thumb ?? throw new ArgumentNullException(nameof(thumb));
}
}
}
ImageFolder.cs
Der Zeit werden die Thumbnails noch on-the-fly erzeugt.
Auch die Thumbnail größe ist noch Statisch
public class ImageFolder
{
const string JPGPATTERN = "*.jpg";
public ImageFolder() { }
public PictureListItem[] GetThumbnails(string folder)
{
if(folder == null)
throw new ArgumentNullException(nameof(folder));
return GetThumbnails(new DirectoryInfo(folder));
}
public PictureListItem[] GetThumbnails(DirectoryInfo folder)
{
if( folder == null) throw new ArgumentNullException(nameof (folder));
var files = folder.GetFiles(JPGPATTERN);
List<PictureListItem> result = new List<PictureListItem>();
if(files.Length > 0)
{
//for(int i = 0; i < 35; i++)
foreach(var file in files)
{
//var file = files[i];
var img = PictureUtils.GetImage(file.FullName);
var thumb = PictureUtils.ShrinkImage(img, 209, 173);
var fileName = file.Name;
var fileDate = GetFormatedFileDate(file.CreationTime);
var imgDimentions = GetImageDimentions(img.Size, file.Length);
result.Add(new PictureListItem(fileName, imgDimentions, fileDate, thumb));
img.Dispose();
}
return result.ToArray();
}
return Enumerable.Empty<PictureListItem>().ToArray();
}
private string GetFormatedFileDate(DateTime creationTime)
{
return creationTime.ToString("dd.MM.yyyy hh:mm:ss");
}
private string GetFileSize(long length)
{
return ((float)Math.Ceiling((double)length / 1024)).ToString("N0") + " Kb";
}
private string GetImageDimentions(Size size, long length)
{
return $"{size.Width}x{size.Height} - {GetFileSize(length)}";
}
}
Vielen Dank für die weiteren Infos.
Was meinst du mit Testprogramm oder anders gefragt wie soll das Programm aussehen?
Gerade bei Bildern sollte man Caching in Betracht ziehen, damit die Skalierung nicht jedesmal on-the-fly beim Zeichnen passiert.
Ich bin davon ausgegangen das beim neu Zeichnen die Bildgröße bereits feststeht (Picturebox, Thumbnail).
Mit FileStream(...)
hole ich den Stream
und mit Image.FromStream(s)
bekomme ich das Image.
In einem finally-Block
wird der Stream
geschlossen
Das Image übergebe ich der Methode ShrinkImage(...)
und bekomme das Thumbnail.
Die ShrinkImage
Methode bekommt noch die Breite und die Höhe für die Berechnung, diese stehen aber erst zur Laufzeit zu Verfügung. Vom Grid
den ColumnWidth
entspricht 4 Bilder pro Zeile.
Am Ende der ShrinkImage
-Methode dispose ich das Original Image.
Mit den entsprechenden Daten (thumb, dateiname, bildgröße, dateidatum) wird dann das UserControl
in meinem fall PictureFrame
gebaut.
Das Caching von Bildern hab ich mich noch nicht mit beschäftigt, kommt auch auf meine Todo-Liste.
Hier ein kleiner zwischen stand.
Beim umsetzen bin ich folgendermaßen vorgegangen.
Zu erst habe ich ein User-Control
erstellt das der Darstellung dem von XnView entspricht.
Dem User-Control
wurde ein Dateiname übergeben und intern wurde das Thumbnail berechnet und in der Größe angepasst. Die PictureBox
Zentriert. Und die Label's
bekamen noch die Bildinformation.
Die Logik steckte jetzt im User-Control
, dar man Logik und UI von einander trennt, habe ich die Logik in eine eigene Datei gepackt.
Zum Testen habe ich dem Grid ein paar User-Controls hinzugefügt bis auf einige Schönheitsfehler, die konnte ich zum Glück beheben, sah das ganze schon gut aus.
Das Selektieren habe ich hinbekommen, allerdings immer nur ein Bild.
Multi-Selektion gestaltet sich dagegen etwas schwieriger, soweit bin ich noch nicht.
Es gibt noch viel Punkte an den ich noch arbeiten muss, Zum einen die Geschwindigkeit, die Anzahl der Bilder ist begrenzt.
Wie groß ist die maximale Anzahl an Control
die der Auflistung Controls
hinzugefügt werden kann?
Ich vermute mal das bei der Listen Darstellung im Hintergrund mit Virtuellen-Listen gearbeitet wird und nur der Teil der sich im Sichtbaren Bereich befindet Dargestellt wird.
Dafür fehlen mir leider die Kenntnisse, gibt es für diese Technik eigentlich Bücher?
Bevorzugt in Deutsch.
Okay das ist erst mal der Aktuelle stand.
Hallo BlonderHans,
vielen Dank für den Link, ich werde es mir anschauen. Leider habe ich so meine Probleme mit Englischen. Kann etwas dauern.
Hallo Th69,
dir auch vielen Dank für deine hinweise und das Grid Beispiel.
Ich werde jetzt am Wochenende mich damit beschäftigen, habe Dank dir genügend Stoff und Anregung.
evtl. ist aber auch ein eigenes Container-Control dafür intern erstellt.
Hier dachte ich an OnPaint z.B. wenn man von ListView ableitet.
In der Grid-Datei Leitest du von Panel ab und erbst damit Controls was die Sache etwas leichter macht.
Über den fortschritt werde ich hier noch berichten, die ein oder andere Frage werde ich mit Sicherheit noch haben.
Hallo Th69,
Ja das TableLayoutPanel ist damit gemeint.
Ob es die richtige Wahl ist weis ich nicht, war halt mein erster Gedanke.
Anstelle eines Listviews.
Du erwähnst ein Container-Control das eine Auflistung von User-Controls an nehmen kann.
Vermutlich bin ich dann auch für das Zeichnen oder Darstellen der Element Verantwortlich?
Eine frage zum Thema MVP ist es in der Praxis üblich das im Model auch Forms-Objekte wie z.B. ListViewItems oder andere Forms-Controls erzeugt werden und an die Form übergeben werden?
Hallo Th69,
sorry habe ich vergessen UI-Technologie ist WinForms und MVP.
Man könnte von Listview ableiten, das habe bisher nur einmal gemacht. Da habe ich in einer spalte eine ProgressBar gezeichnent.
Also lag ich gar nicht so falsch mit TabLayout und dann ein eigenes User-Control pro Feld.
Spätestens beim Selektieren werde ich mit Sicherheit noch mal nachfragen.
Wie schon erwähnt. mach ich das im Hobby Bereich und für solche speziellen aufgaben fehlt mir das Fachwissen.
Ich möchte aber gerne etwas mehr in die Materie einsteigen, und bin für jeden Tipp oder hinweis dankbar.
Hallo zusammen,
mich würde Interessieren wie das in der Praxis umgesetzt wird. Zu Lernen und Verstehen wie das ganze zusammen Funktioniert.
Ich nehme mal XnView als beispiel. Im Programm können die Ansichten umgeschaltet werden von einfachen Listen- und Thumbnails- Ansicht.
Erste versuche mit einem Listview und der LargeImageList habe ich hinbekommen.
Ein Beispiel dafür habe ich im Netz gefunden.
Dabei zeigte sich das man nicht viel Einfluss auf die Darstellung der Bilder hat, wie Breit- und Hoch- Format.
Ein Idee ging in Richtung TabLayout, nur wie kann man dann einzelne oder Gruppen von Bilder Selektieren?
Ich bin ein Hobby Programmierer, und wenn ich so manchen Quellcode auf GitHub anschaue, stelle ich fest das ich noch weit davon entfernt bin.
Vielen Dank, Stefan