Graphische Matrix anlegen zur Ausgabe von schwarz/weiß Feldern

  • VB6

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Himalius.

    Graphische Matrix anlegen zur Ausgabe von schwarz/weiß Feldern

    Hallo erstmal.

    Ich bin seit mehreren Tagen dabei mir "Conway's Game of Life " zu programmieren.
    Ich hatte es schon einmal komplett gelöst, allerdings hatte ich nur 25x25 Felder (Textfelder), die ich mit Visual Studio selbst reingezeichnet hab.
    Und zwar hatten alle den Namen "Fld" udn waren mit Indizes folgendermaßen durchnummeriert:
    0 1 2 3 4 ... 24
    100 101 102 103 ... 124
    200 201 202 203 ... 224
    .
    .
    .
    2400 2401 2402 2403...2424
    Da dies aber zu wenig Felder waren, um eine gute Darstellung und einen guten Ablauf zu bekommen, wollte ich die Textfelder kleiner machen, um mehr zu machen.
    Allerdings lassen sich Textfelder nicht auf eine Größe von 25x25 Pixeln verkleinern.
    Deshalb bin ich zu Shapes gewechselt.
    Da ich aber keine Lust habe 625 (später 62.500) Shapes einzeln von Hand im Fenster einzufügen, wollte ich die Shapes im Code erstellen.
    Und genau da ist mein Problem.
    Ich krieg es nicht hin, die Shapes alle mit gleichem Namen und den richtigen Indizes anzulegen.


    Quellcode

    1. Private Sub Form_Load()
    2. Dim i As Integer, j As Integer
    3. Dim Index
    4. For i = 0 To 24
    5. For j = 0 To 24
    6. Index = i * 100 + j
    7. Dim shape As shape
    8. Set shape = shape
    9. Set shape.Index = Index 'Hier bringt er mir die Meldung "Ungültige Verwendung einer Eigenschaft"
    10. shape(Index).FillColor = RGB(255, 255, 255)
    11. shape(Index).BorderColor = RGB(255, 255, 255)
    12. shape(Index).BackColor = RGB(255, 255, 255)
    13. shape(Index).Left = 100 + i * 250
    14. shape(Index).Top = 100 + j * 250
    15. End Sub


    Ich habe schon alles mögliche probiert und überall nach Lösungen gesucht, konnte aber nichts finden, dass mir geholfen hat.

    MfG
    Himalius

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Himalius“ ()

    Hallo Himalius,

    Allerdings lassen sich Textfelder nicht auf eine Größe von 25x25 Pixeln verkleinern.

    Das hängt von der Schriftgrösse und Schriftart ab.

    Ändere den Code mal so:

    Visual Basic-Quellcode

    1. Private Sub Form_Load()
    2. Dim i As Integer, j As Integer
    3. Dim Index As Integer
    4. Index = 0
    5. For i = 0 To 24
    6. For j = 0 To 24
    7. If Index > 0 Then Load Shape1(Index)
    8. With Shape1(Index)
    9. .FillColor = RGB(255, 255, 255)
    10. .BorderColor = RGB(255, 255, 255)
    11. .BackColor = RGB(255, 255, 255)
    12. .Move 100 + i * 250, 100 + j * 250, 240, 240
    13. .Visible = True
    14. End With
    15. Index = Index + 1
    16. Next j
    17. Next i
    18. End Sub

    Du musst zur Entwurfszeit ein Shape mit dem Namen Shape1 erstellen und
    bei Index eine 0 eintragen.

    Visual Basic-Quellcode

    1. Dim shape As shape

    Eine Variable niemals Shape nennen. Das ist ein reserviertes Basicwort.

    Da ich aber keine Lust habe 625 (später 62.500) Shapes einzeln von Hand im Fenster einzufügen, wollte ich die Shapes im Code erstellen.

    62500 Shapes wird nicht funktionieren. Ein Control-Array kann maximal 32768 (2^15) Elemente haben.
    Die beste Lösung ist es, alles in eine Picturebox zu zeichnen.
    Gruss,

    Neptun
    Das mit dem

    Quellcode

    1. Index = Index + 1
    spricht aber gegen die Verteilung der Indizes wie ich sie geplant hab.
    Ich hab die ganze Matrix noch mal als Matrixvariable

    Quellcode

    1. Dim Matrix_alt(-1 To 25, -1 To 25) As Boolean
    2. Dim Matrix_neu(-1 To 25, -1 To 25) As Boolean


    Die -1 und 25 brauch ich als unsichtbaren Rahmen.

    Da ich über diese Variable die einzelnen Wahrheitswerte/Zustände der Felder auslese und hier eine 25x25 Form vorgegeben habe muss/will ich die auch bei der Vergabe der Indizes beibehalten.

    0 1 2 3 ... 24
    100 101 102 103 ... 124
    200 201 202 203 ... 224
    .
    .
    .
    2400 2401 2402 2403...2424
    Die Idee mit der Picturebox ist mir auch schon über den Weg gelaufen, aber die hab ich nicht umgesetzt gekriegt.

    MfG
    Hallo Himalius,
    ändere den Code so:

    Visual Basic-Quellcode

    1. For i = 0 To 24
    2. For j = 0 To 24
    3. Index = i * 100 + j
    4. If Index <> 0 Then Load Shape1(Index)
    5. With Shape1(Index)
    6. .FillColor = RGB(255, 255, 255)
    7. .BorderColor = RGB(255, 255, 255)
    8. .BackColor = RGB(255, 255, 255)
    9. .Move 100 + i * 250, 100 + j * 250, 240, 240
    10. .Visible = True
    11. End With
    12. Next j
    13. Next i
    Gruss,

    Neptun
    Achso, ok, da hätte ich auch selber drauf kommen können :)
    Trotzdem natürlich danke für die Hilfe.

    Zu voreilig geschossen...

    Aber wie funktioniert das mit der Picturebox?
    Ich hab mir das ja auch mal als Alternative angeschaut, aber ich bin damit nicht zurecht gekommen.

    MfG

    Edit:

    Quellcode

    1. Private Sub Form_Load()
    2. Dim i As Integer, j As Integer, Index As Integer
    3. 'dim shape1 as shape
    4. For i = 0 To 24
    5. For j = 0 To 24
    6. Index = i * 100 + j
    7. If Index <> 0 Then Load shape1(Index) 'Hier bringt er mir die Meldung "Sub oder Function nicht definiert".
    8. With shape1(Index)
    9. .FillColor = RGB(255, 255, 255)
    10. .BorderColor = RGB(255, 255, 255)
    11. .BackColor = RGB(255, 255, 255)
    12. .Move 100 + i * 250, 100 + j * 250, 240, 240
    13. .Visible = True
    14. End With
    15. Next j
    16. Next i
    17. End Sub


    Ich habs dann mal mit "dim shape1 as shape" probiert - also nicht auskommentiert, da bringt er mir die meldung "Falsche Anzahl an Argumenten oder ungültige Zuweisung zu einer Eigenschaft".

    Was läuft falsch?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Himalius“ ()

    wtf, mach doch einen 2D array!
    game of life ist doch das, wo eine zelle im nächsten zyklus die umgebenen zum "leben" erweckt, wenn es aber mehr als 2 lebende nachbarn sind stirbt die zelle.. so iwie

    also erstelle dir einen 2D array vom typ boolean. eine lebende zelle ist true, eine nicht lebende false.
    zeichnen tust du das ganze auf eine bitmap:

    for x = 0 to MaßX
    for y = 0 to MayY
    if Array(x,y) = true then
    bitmap.setpixel(x,y,black)
    else
    bitmap.setpixel(x,y,white)
    next
    next

    bei vb6 konnte man glaubich mit setpixel auch direkt auf eine form zeichnen, wäre ja noch besser (hat ja auch autoredraw).
    auf jeden fall ist die darstellung BESSER als mittels controls!
    Ich hab die Werte für die Felder ja in einem 2D-Array drin liegen

    Himalius schrieb:

    Quellcode

    1. Dim Matrix_alt(-1 To 25, -1 To 25) As Boolean
    2. Dim Matrix_neu(-1 To 25, -1 To 25) As Boolean

    aber das mit der ausgabe als grafik will mir nicht in einer vernünftigen weise gelingen - außer in von hand angelegten textfeldern...
    also unter vb.net würde ich das so zeichnen:

    Visual Basic-Quellcode

    1. Dim SizeX As Integer = 100
    2. Dim SizeY As Integer = 100
    3. Dim array(SizeX - 1, SizeY - 1) As Boolean
    4. 'zufällige werte erzeugen
    5. For x = 0 To SizeX - 1
    6. For y = 0 To SizeY - 1
    7. array(x, y) = CBool(Math.Round(Rnd))
    8. Next
    9. Next
    10. 'zeichenn
    11. Dim Bit As New Bitmap(SizeX, SizeY)
    12. For x = 0 To SizeX - 1
    13. For y = 0 To SizeY - 1
    14. If array(x, y) = True Then
    15. Bit.SetPixel(x, y, Color.Black)
    16. Else
    17. Bit.SetPixel(x, y, Color.White)
    18. End If
    19. Next
    20. Next
    21. Button1.Image = Bit



    VB6 Code

    Visual Basic-Quellcode

    1. For x = 0 To SizeX - 1
    2. For y = 0 To SizeY - 1
    3. If array(x, y) = True Then
    4. Me.PSet (x,y), vbWhite
    5. Else
    6. Me.PSet (x,y), vbBlack
    7. End If
    8. Next
    9. Next



    unter VB6 gibts glaubich eine viel einfachere funktion, die direktes zeichnen auf controls ermöglicht. ich glaube Pset hieß die funktion... du kannst also statt auf die bitmap zu zeichnen (die bitmap einfach weglassen) direkt auf die form zeichnen. frm.pset... müsste eigentlich funktionieren
    Dann noch so ne kleine Anmerkung:
    Du solltest GoL auf keinen Fall mit Matrizen programmieren (ich vermute mal du machst das so wg dem Matrix_alt und Matrix_neu)
    Stell dir mal folgendes Szenario vor:
    du hast deine 60.000 Zellen und stellst ganz unten links ne Gleiterkanone rein, die Gleiter in Richtung rechte obere Ecke schießt.
    Dann musst du nach wenigen Generationen schon eine riesige Matrix berechnen, die eig sowieso zum größten Teil leer ist.
    Es ist zwar am einfachsten mit zwei Matrizen und Abgleichen zu programmieren, wird aber nicht effizient laufen.

    In Wikipedia (unter Conways GoL) gibt es nen Pseudo-Code gugg dir mal den an, so kannst du die Zellen einzeln berechnen (nur die die sowieso an sind).

    Du kennst bestimmt auch Golly-2.2. da kannst du auch den Code einsehen.

    Ich leite gerade zufällig Projekttage in unserer Schule genau zu diesem Thema^^
    wie meinst du das, "nur die die sowieso an sind"?
    ist doch bei einer matrix (2dimensionaler boolean array) doch immer der selbe rechenaufwand sofern sich die größe des spielfelds nicht ändert?!
    ich hab das mal so gemacht:

    lebt die zelle (x,y) dann
    prüfe ob sie weniger als 2 oder mehr als 3 lebende nachbarn hat. trifft dies zu stirbt sie

    ist die zelle (x,y) tot
    prüfe ob sie 3 lebende nachbarn hat, wenn ja, dann lebt die zelle ab jetzt wieder
    Hallo Himalius,
    was das Control-Array betrifft, sieh dir mal das Beispiel im Anhang an.
    Mit der Picturebox geht's so:

    Visual Basic-Quellcode

    1. ' Controls: 1 * Picturebox
    2. Private Feld As Integer
    3. Private Breite As Integer
    4. Private Hoehe As Integer
    5. Private Sub Form_Load()
    6. Dim i As Integer, j As Integer
    7. Feld = 16 ' Feldgrösse in Pixeln
    8. Breite = 20 ' Anzahl Felder horizontal
    9. Hoehe = 20 ' Anzahl Felder vertikal
    10. Me.ScaleMode = vbPixels ' Einheit Pixel
    11. With Picture1
    12. .BorderStyle = vbBSNone ' kein Rahmen
    13. .ScaleMode = vbPixels ' Einheit Pixel
    14. .Move 4, 4, Feld * Breite + 1, Feld * Hoehe + 1 ' Grösse
    15. .AutoRedraw = True ' Beständiges Bild
    16. .BackColor = vbWhite ' Hintergrundfarbe
    17. For i = 0 To Breite
    18. Picture1.Line (i * Feld, 0)-(i * Feld, .ScaleHeight), vbBlack
    19. Next i
    20. For i = 0 To Hoehe
    21. Picture1.Line (0, i * Feld)-(.ScaleWidth, i * Feld), vbBlack
    22. Next i
    23. .FillStyle = vbFSSolid ' Ausgefüllt zeichnen
    24. .FillColor = vbBlack ' Füllfarbe schwarz
    25. For i = 0 To Breite - 1
    26. For j = 0 To Hoehe - 1
    27. If Rnd < 0.5 Then
    28. ' Stein zeichnen
    29. Picture1.Circle (i * Feld + Feld / 2, j * Feld + Feld / 2), Feld / 2 - 2, vbBlack
    30. End If
    31. Next j
    32. Next i
    33. .FillStyle = vbFSTransparent ' Transparent zeichnen
    34. End With
    35. End Sub
    Dateien
    • GOL.zip

      (1,52 kB, 92 mal heruntergeladen, zuletzt: )
    Gruss,

    Neptun
    Ich hab die Darstellung mit der PictureBox von Neptun jetzt mal verwendet.
    Nach ein bisschen Anpassung funktioniert das jetzt auch.
    Hab nur ein paar Details geändert z.B.:
    -Ich bestimme zuerst per Zufall die Belegung der Felder und schreibe das in mein 2D-Array "Matrix_alt(x,y)".
    Danach setz ich das mit einer eigenen Prozedur ins Bild um.
    -Ich hab auch die Feldgröße und Anzahl public als Konstanten im Kopf deklariert, weil die ja während der Laufzeit gleich bleiben und ich die aber in verschiedenen Prozeduren brauche.

    Allerdings hab ich noch ein paar Probleme, die sich mir verschließen:
    -Wenn ich transparent zeichne hab ich nur weiße Kreise mit schwarzem Rand und wenn ich nicht transparent zeichne hab ich diese Kreise plus jeweils ein Feld drunter nochmal ein voller schwarzer Kreis.
    --> Ich habs hingekriegt. Musste deklarieren welche Farbe der Kreis haben sollte, bevor ich Ihn zeichne.
    -Wie kann ich die einzelnen Felder ansprechen, dass sich, wenn ich drauf klicke, deren Inhalt ändert (An/Aus)? Bei den Textfeldern hab ich einfach überprüft wo im Fenster ich hingeklickt hab und die Koordinaten des Klicks mit den Positionen der Textfelder verglichen. Dann hab ich über den Index des Feldes in der Matrix_alt(x,y) den Status (True/False) überprüft, geändert und das Feld geändert.


    MfG

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Himalius“ ()

    Hallo Himalius,
    das geht so:

    Visual Basic-Quellcode

    1. Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    2. Dim XPos As Long, YPos As Long
    3. XPos = X \ Feld
    4. YPos = Y \ Feld
    5. Matrix_alt(XPos, YPos) = 1 - Matrix_alt(XPos, YPos)
    6. End Sub

    Der Scalemode der Picturebox muss auf Pixel stehen. Eventuell muss das
    geänderte Feld neu gezeichnet werden (kommt auf den Programmaufbau an).
    Gruss,

    Neptun
    Der Code kehrt den Inhalt der Variablen um.
    Du kannst auch das schreiben:
    Für Löschen:

    Visual Basic-Quellcode

    1. Matrix_alt(XPos, YPos) = 0

    Für Setzen:

    Visual Basic-Quellcode

    1. Matrix_alt(XPos, YPos) = 1

    Für Umdrehen:

    Visual Basic-Quellcode

    1. Matrix_alt(XPos, YPos) = Matrix_alt(XPos, YPos) Xor 1

    Bei Boolean-Variablen das Ganze mit True und False und Umdrehen
    mit Not.

    Feld war übrigens die Grösse eines Feldes in Pixeln.
    Gruss,

    Neptun
    Wieder was dazu gelernt.

    Verwende Boolean-Variablen, also Not.
    Ich hatte das bei meiner Textfeldvariante mit einer If-Anweisung gemacht.

    Und Feld wusst ich noch, was das war :)

    Die Textfeldvariante könnt ich ja mal als exe-File hochladen, falls einer sehen will, wie das aussah.


    EDIT: 22. Juli 2011 14:52
    Hab die manuelle Änderung der Zustände jetzt auch hinbekommen.
    Habs mit

    Visual Basic-Quellcode

    1. Picture1_MouseDown(...)

    gemacht. Koordinaten auf Indizes runtergerechnet, dann gings.

    Ich versuch jetzt mal das ganze größer zu dimensionieren, weil 25x25 Felder ist ein wenig zu klein.


    EDIT 2: 25. Juli 2011, 08:
    So, hab das ganze jetzt auf 150x150 vergrößert.
    Jetzt läufts nur deutlich langsamer als gewollt.
    Mal schauen, was ich da noch an Code/Rechenleistung einsparen kann.

    BTW: Danke an alle mal für die Hilfe. Hat mich sehr weitergebracht. :)
    So, hab es jetzt
    Dateien
    • Game of Life.exe

      (49,15 kB, 113 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Himalius“ ()