Autor |
Beitrag |
Raven280438
Beiträge: 99
|
Verfasst: Sa 02.10.10 21:49
Hi,
ich zeichne in eine PictureBox viele kleine Bilder, ca. 32x32px.
Wenn die PictureBox über den ganzen Bildschirm geht dauert das Ganze schonmal gut eine Sekunde.
Ich speichere die Images schon in einem Dictionary.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Dictionary<string, Image> cache = new Dictionary<string, Image>(); [...]
if (!cache.Keys.Contains(verzeichnis + bild)) { Image img = Image.FromFile(verzeichnis + bild); cache.Add(verzeichnis + bild, img); }
e.Graphics.DrawImage(cache[verzeichnis + bild], punkt); |
Gibt es eine Möglichkeit, das ganze noch zu beschleunigen?
Gruß
|
|
Greenberet
Beiträge: 339
Erhaltene Danke: 20
Win 10
C# (VS 2012), C++ (VS 2012/GCC), PAWN(Notepad++), Java(NetBeans)
|
Verfasst: So 03.10.10 00:51
Wenn sich die Bilder nicht ändern:
alle Bilder am Anfang einmalig in ein großes Bild zeichnen anschließend nur noch das große Bild zeichnen.
zusätzlich könntest du "verzeichnis + bild" schonmal in "bildpfad" abspeichern, das jedes mal zusammenzusetzen dauert halt auch seine Zeit.
|
|
Th69
Beiträge: 4777
Erhaltene Danke: 1054
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: So 03.10.10 12:33
Und Pfade solltest du mittels
C#-Quelltext 1:
| Path.Conmbine(verzeichnis, bild); |
zusammensetzen.
Da du die Bilder ja alle dynamisch zeichnest, solltest du auch eher ein "Panel" anstatt einer "PictureBox" nehmen.
Du benutzt auch das Dictionary beim Auslesen unperformant - statt "Keys.Contains" besser direkt
C#-Quelltext 1:
| cache.ContainsKey(...); |
Und zuletzt noch:
mittels "Image.FromFile" lockst du die Bilddatei, bis das Image wieder mittels "Dispose" freigegeben wird. Besser ist es dann einen Stream zu benutzen:
C#-Quelltext 1: 2:
| Stream stream = new MemoryStream(File.ReadAllBytes(path)); Image img = Image.FromStream(stream); |
Solltest du ein Image nicht mehr benötigen, d.h. aus dem Cache entfernen, so solltest du dann zusätzlich noch "image.Dispose()" aufrufen (generell sollte für alle Objekte, welche IDisposable implementieren Dispose() aufgerufen werden!).
|
|
Raven280438
Beiträge: 99
|
Verfasst: So 03.10.10 12:48
Hi,
danke für die Hinweise, leider gibt das immernoch keinen Geschwindigkeitsschub.
Wie kann ich kleine Bilder in ein Großes zeichnen? Damit hab ich noch keine Erfahrung.
Im Moment zeichne ich nur die Bilder, die auch wirklich angezeigt werden, da die PictureBox mehr Bilder hat, als sie anzeigen kann (also mit Scrollbars).
Da müsste ich bei jedem Scrollen auch das große Bild neu zeichnen.
Gruß
|
|
Raven280438
Beiträge: 99
|
Verfasst: So 03.10.10 18:19
Hi,
kann man das ganze auch mit DirectX lösen? Ich hab da garkeine Erfahrung drin.
Oder hat jemand noch eine Idee, wie ich das Ganze beschleunigen kann?
Gruß
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 03.10.10 18:33
Du kannst viel mit DX machen, aber das wäre hier etwas überdimensioniert.
Beschreibe doch einmal genauer was mit den Bildern passieren soll. Sollen diese dynamisch anders angeordnet werden oder bleiben diese wie sie sind?
Du kannst zum Beispiel einige Bilder in ein größeres zusammenfassen und dann diese größeren beim Scrollen entsprechend benutzen. Dadurch fällt schon einmal einiges an Aufwand weg.
|
|
Raven280438
Beiträge: 99
|
Verfasst: So 03.10.10 19:28
Hi,
also ich bin grade dabei, C# zu lernen. Als großes Lern-Projekt arbeite ich im Moment an einem Map-Editor für ein 2D RPG was ich später mal mit DirectX programmieren will
Nicht kommerzielles, einfach nur zum Lernen.
Dazu hab ich eine 2-Dimensionale Liste mit den Hintergrund-Texturen.
C#-Quelltext 1:
| private List<List<string>> grundebene = new List<List<string>>(); |
Später kommen noch andere Ebenen hinzu, die übereinander gezeichnet werden sollen.
Meine Paint-Funktion für die PictureBox sieht im Moment so aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72:
| private int tile_size = 32; private int tiles_width; private int tiles_height; private int hOffset = 0; private int vOffset = 0; private int hscroll = 0; private int vscroll = 0; private static Dictionary<string, Image> cache = new Dictionary<string, Image>();
private void pBMap_Paint(object sender, PaintEventArgs e) { Font drawFont = new System.Drawing.Font("Arial", 8); SolidBrush drawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black); Pen raster = new Pen(Color.Black);
double d_start_i = hscroll / tile_size; int start_i = Convert.ToInt32(Math.Floor(d_start_i));
double d_start_j = vscroll / tile_size; int start_j = Convert.ToInt32(Math.Floor(d_start_j));
double d_ende_i = this.pBMap.Width / tile_size; int ende_i = Convert.ToInt32(Math.Floor(d_ende_i)) + 10 + start_i; if (ende_i > tiles_width) ende_i = tiles_width;
double d_ende_j = this.pBMap.Height / tile_size; int ende_j = Convert.ToInt32(Math.Floor(d_ende_j)) + 10 + start_j; if (ende_j > tiles_height) ende_j = tiles_height;
int x = 0; for (int i = start_i; i < ende_i; i++) { int y = 0; for (int j = start_j; j < ende_j; j++) { Point punkt = new Point(x - hOffset, y - vOffset); String grundebene_textur = grundebene[i][j]; String bild = Path.Combine(textur_verzeichnis,grundebene_textur); if (Directory.Exists(textur_verzeichnis) && grundebene_textur.Length > 0) { FileInfo fi = new FileInfo(bild); if (fi.Exists) { if (!cache.ContainsKey(bild)) { Stream stream = new MemoryStream(File.ReadAllBytes(bild)); Image img = Image.FromStream(stream);
cache.Add(bild, img); } for (int z = 0; z < 11; z++) { e.Graphics.DrawImage(cache[bild], punkt); } } } e.Graphics.DrawRectangle(raster, x - hOffset, y - vOffset, tile_size, tile_size); e.Graphics.DrawString(i.ToString() + ":" + j.ToString(), drawFont, drawBrush, x - hOffset + 3, y - vOffset + 3); y += tile_size; } x += tile_size; } } |
Die PictureBox hat 2 Scrollbars:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| private void hScrollBar1_Scroll(object sender, ScrollEventArgs e) { this.hscroll = this.hScrollBar1.Value; if (this.hScrollBar1.Value > 0) { this.hOffset = this.hScrollBar1.Value % this.tile_size; } else { this.hOffset = 0; } this.pBMap.Refresh(); }
private void vScrollBar1_Scroll(object sender, ScrollEventArgs e) { this.vscroll = this.vScrollBar1.Value; if (this.vScrollBar1.Value > 0) { this.vOffset = this.vScrollBar1.Value % this.tile_size; } else { this.vOffset = 0; } this.pBMap.Refresh(); } |
Später soll dann noch das MouseMove ausgewertet werden, und um die Tile auf der die Maus ist ein rotes Viereck gezeichnet werden. Aber so weit bin ich noch nicht
Falls sich jemand die Zeit nimmt, und sich das Projekt ansehen will, ich habs mal testweise hier hochgeladen:
www.roman-drechsel.de/Upload/ST.rar
Vielleicht hilft das jemand weiter.
Gruß
|
|
jaenicke
Beiträge: 19284
Erhaltene Danke: 1742
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 03.10.10 19:32
Raven280438 hat folgendes geschrieben : | Später kommen noch andere Ebenen hinzu, die übereinander gezeichnet werden sollen. |
Ok, dann wäre DirectX schon sinnvoll, denn das kümmert sich dann selbst um die Darstellung und Überlappung der Ebenen usw., außerdem kommen bei solch einem Editor vielleicht ja auch noch Effekte usw. hinzu.
|
|
Raven280438
Beiträge: 99
|
Verfasst: So 03.10.10 19:46
Hi,
das hab ich mir gedacht
Kann man DirectX auch nur für einen bestimmten Bereich in einem Form nutzen? Ich würde gerne die Scrollbars weiter dafür nutzen und nichts eigenes dafür programmieren müssen.
Ich hab im Internet bisher nur Beispiele gefunden, die einen kompletten Form mit DirectX erstellen.
Folgendes Tutorial habe ich gefunden:
www.euclideanspace.c...9cs/basics/index.htm
Da wird aber mit Fullscreen gearbeitet. Wie kann ich das auf Windowed umstellen? Wenn ich
C#-Quelltext 1:
| dddevice.SetCooperativeLevel(this, CooperativeLevelFlags.Normal); |
einstelle, bekomm ich einen Fehler, sobald ich das Programm starte, in der Zeile:
C#-Quelltext 1:
| psurface = new Surface(sdesc, dddevice); |
Ich hab mir schon ein Buch zu C# und DirectX bestellt, aber das kommt erst nächste Woche
Gruß
|
|
|