bitmap und PictureBox.image
-
Freitag, 22. Februar 2013 05:07
Hallo ,
hab das Thema nach hier verschoben .
danke für die Antwort . Habe rumprobiert , es geht einigermaßen . Jetzt stehe ich aber vor einem neuen Problem . Ich stelle mich einfach doof an . In VB6 sind die Pictureboxen mit z.B. : Bauteilboxen(1) , Bauteilboxen(2) als array bezeichnet . Ich kann also mit dem Index jede Box ansprechen . In VB.Net sind die Bezeichnungen aber Bauteilbox1,Bauteilbox2... Ich habe schon ein wenig rumgelesen , mit den Controls , weiss aber nicht , wie ich es anfangen soll . Ich habe eine Select case Routine vorläufig eingefügt , aber das ist nicht passabel , da ich ca 20 PictureBoxen habe . Ich will mit n als Index das Image in die jeweilige PicturBox laden .
Kannst Du mir eine einfache Routine schreiben ? Ich habe ein Buch und finde in dem ganzen Buch keine einzige Zeile , wo erklärt wird , wie es geht , komisch müsste doch ganz einfach sein ?
MyImage = NewBitmap(a2$) 'n= Datei.txt ab n=1 Bilder
'n=0 , 2$ = "���"
SelectCasen
Case1
BauteilBox1.Image = MyImage
BauteilBox1.Visible = True
Case2
BauteilBox2.Image = MyImage
BauteilBox2.Visible = True
BauteilBox2.Top = BauteilBox1.Top + 15 + BauteilBox1.Height
Case3
BauteilBox3.Image = MyImage
BauteilBox3.Visible = True
BauteilBox3.Top = BauteilBox2.Top + 15 + BauteilBox1.Height
EndSelect
n = n + 1
Alle Antworten
-
Freitag, 22. Februar 2013 06:40Beantworter
Hallo,
Steuelement Arrays gibt es bei Visual Basic .NET nicht mehr,
aber Du kannst Steuerelemente wie alles andere in Arrays oder Auflistungen speichern:
Private BauteilBoxen As List(Of PictureBox) Public Sub New() ' Erzeugt die Steuerelemente InitializeComponent() ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu. ' Auflistungen der PictureBoxen (wären 20...) BauteilBoxen = New List(Of PictureBox) From {Me.PictureBox1, Me.PictureBox2} ' Durchlaufen der Auflistungen und zuweisen For index As Integer = 0 To BauteilBoxen.Count - 1 BauteilBoxen(index).Image = New Bitmap(24, 24) If index > 0 Then BauteilBoxen(index).Top = BauteilBoxen(index - 1).Top + 15 + BauteilBoxen(index - 1).Height End If BauteilBoxen(index - 1).Visible = True Next End Sub
Im Abschnitt findet alles im Konstruktor statt, aber Du kannst es an beliebiger Stelle durchführen.
Selbst das Erzeugen der PictureBoxen könntest Du dynamisch machen. Du musst sie dann der Controls-Auflistung des Formulars hinzufügen. Ich habe deswegen im Beispiel eine generische Auflistung intialisiert, die lässt sich leichter erweitern als ein Array, das ebenfalls möglich wäre.
Auch kann man über die Steuerelemente über ihren Namen in der Controls-Auflistung ansprechen,
was aber letztendlich ineffektiver ist.
Gruß Elmar
P. S.: Verschieben können nur Moderatoren den Thread;
aber das ist eine neue Frage und die lässt man besser getrennt.- Als Antwort vorgeschlagen Giftzwockel Freitag, 8. März 2013 15:05
-
Samstag, 23. Februar 2013 15:00
Hallo danke ,
das geht gut . Leider stelle ich mich ganz doof an , mit VB6 habe ich jetzt schon seit 1998 programmiert , aber mit VB.Net klappt es einfach noch nicht . Ich will mein Malprogramm in VB.Net überführen , aber immer hakt etwas .
ImportsSystem.Drawing
PublicClassGrafikform
Privatebild(3) AsBitmap
PrivateBauteilBoxen AsList(OfPictureBox)
PublicSubNew()
bild(0) = NewBitmap("C:\baut1\infrtrans.STL")
bild(1) = NewBitmap("C:\baut1\infrarsend.STL")
bild(2) = NewBitmap("C:\baut1\steckAnschl.STL")
InitializeComponent()
BauteilBoxen = NewList(OfPictureBox) From{Me.BauteilBox1, Me.BauteilBox2, Me.BauteilBox3}
ForIndex AsInteger= 0 ToBauteilBoxen.Count - 1
BauteilBoxen(Index).SizeMode = PictureBoxSizeMode.AutoSize
BauteilBoxen(Index).Image = bild(Index)
BauteilBoxen(Index).Visible = True
' AddHandler BauteilBoxen.click, AddressOf Bauteilboxen_click
Next
EndSub
damit kann ich nun die Bauteile laden , aber wie komme ich jetzt an die Index Nr bei einem Click Event auf eine PictureBox ? Vielleicht kannst Du mir nochmals ein wenig helfen , auch wenn es nervt .
P.S. zum Start des Programms müssen Leerstellen eingefügt werden , der Server entfernt komischer Weise die Leerstellen z.B.Public Class Grafikform wandelt der Server in
PublicClassGrafikform
- Bearbeitet ERDFLIEGER Samstag, 23. Februar 2013 15:03
-
Samstag, 23. Februar 2013 18:28Beantworter
Hallo,
Visual Basic .NET ist eine (fast) neue Sprache. Nimm Dir die Zeit die (vielen) neuen Möglichkeiten kennenzulernen - und nimm nichts als gegeben an, was Du von Visual Basic 6/Classic gewohnt warst (es geht oft anders).
Zunächst eine Kleinigkeit:
Private bild(3) As Bitmap
definiert ein Array mit 4 (nicht 3) Elementen = eins zu viel; denn es wird der höchste Indexwert angeben und nicht etwa die Anzahl und da die Untergrenze 0 ist, kommt eins mehr dabei heraus - ein Kompromiss zu Visual Basic Classic, siehe Arraydimensionen in Visual Basic
Zur Ermittlung des Index:
Oft wirst Du das gar nicht brauchen, z. B. bei einem EventHandler geht es direkter:' in Schleife zu gewiesen AddHandler BauteilBoxen(index).Click, AddressOf BauteilBox_Click Private Sub BauteilBox_Click(sender As Object, e As EventArgs) ' Sender enthält das auslösende Steuerelemt Dim pbox = DirectCast(sender, PictureBox) End SubUnd für die Fälle wo man doch den Index braucht, kann man die Auflistung durchsuchen:
Private Sub BauteilBox_Click(sender As Object, e As EventArgs) Dim pbox = DirectCast(sender, PictureBox) ' Auflistung mit Hilfe von Lambda Funktion durchsuchen Dim pboxIndex = BauteilBoxen.FindIndex(Function(pb) pb Is pbox) ' oder manuell über eine Schleife Dim pboxIndex2 = -1 For index = 0 To BauteilBoxen.Count - 1 If BauteilBoxen(index) Is pbox Then pboxIndex2 = index Exit For End If Next Console.WriteLine("{0} = {1}", pbox.Name, pboxIndex) End SubDie erste (kürzere) Variante nutzt mit FindIndex eine eingebaute Methode einer List(Of T) und verwendet einen Lambda-Ausdruck - ein Weg direkt Methoden einzubetten anstatt mit AdressOf).
Die zweite Variante als konventionelle Schleife macht das Gleiche, nur braucht man mehr Code.
Zum P. S.:
Verwende die Schaltfläche "Codeblock einfügen" oben in der Leiste, dann gibt es (fast) richtig formatierten Code.Gruß Elmar
-
Sonntag, 24. Februar 2013 10:25
Hi Elmar , entschuldige , wenn ich Dich nerve , aber Ich habe zwar VB.Net als Code Sprache , aber es kommt einfach ein VB6 Programm heraus. Daher die komischen Fragen . Wenn ich nach Deinen Antworten ein wenig rum suche , muss ich auch feststellen , daß Listen nicht nötig sind . Ich hab das Programm ausgebessert , bin erstaund , mit wie wenig Code alles funktioniert . Mit den Arrays konnte ich mich nur wundern . Zuerst hatte ich ein Bilder Array Dim Bild() as Bitmap Dim n as integer = 0 unten in Private Sub Form1_Load(.... nach Do hatte ich redim Bild(n)='aus Datei geladener String Für n=0 gibt es keine Fehlermeldung . Man kann also immer Array(n) als Anzahl n -1 , wenn n >= 0 nehmen .
Imports System Imports System.IO Public Class Form1 ' Im Formular zu verwendende Klassenvariablen erstellen. Private Bild() As Bitmap Private kontrollbitmap As Bitmap Private links As Integer = 50 'left Private oben As Integer = 150 'top Private Sub myButtonHandler_Click(ByVal sender As Object, ByVal e As EventArgs) 'Click auf PicBox If TypeOf sender Is PictureBox Then 'Kontrolle kontrollbitmap = New Bitmap((CType(sender, PictureBox).Image)) KontrollPicBox1.Image = kontrollbitmap End If End Sub Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Dim ladefile As String = "C:\baut1\steckbrl1.txt" 'z.B.Hier stehen die Images Dim myimage As Bitmap Dim a2$ Dim n As Integer = 0 Dim lr As StreamReader = New StreamReader(ladefile) Me.Show() Me.WindowState = FormWindowState.Maximized 'holt die Bilder aus der Datei Do a2$ = lr.ReadLine() myimage = New Bitmap(a2$) If n > 2 Then 'max 3 PictureBoxen lr.Close() : Exit Sub Else Dim newpicturebox As New PictureBox newpicturebox.Name = "BauteilBox" & n.ToString() 'Name newpicturebox.Left = links newpicturebox.Top = oben oben += newpicturebox.Height newpicturebox.Image = myimage newpicturebox.Visible = True ' Ereignishandler click hinzufügen. AddHandler newpicturebox.Click, AddressOf myButtonHandler_Click ' Der Auflistung von Steuerelementen das Steuerelement hinzufügen. Controls.Add(newpicturebox) n += 1 'Zähler End If Loop Until a2$ Is Nothing End Sub Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click End End Sub End ClassIch bau jetzt erst mal alles in das Programm ein und darf mich dann wieder melden , wenn ich nicht weiter komme , solange bleibst Du von mir verschont . Beste Grüße Jürgen .
-
Montag, 25. Februar 2013 10:32Beantworter
Hallo Jürgen,
was Arrays und Auflistungen angeht:
Auch die Controls-Auflistung ist eine solche. Redim sollte man vermeiden; das ist ineffizienter als eine Auflistung zu verwenden.Kleine Grundregel: Arrays sollte man dort verwenden, wo die Größe von vornherein feststeht. Wo sich die Größe zur Laufzeit ändert, ist eine Auflistung der bessere Weg.
Zum Code in Form_Load:
Show solltest Du dort nicht aufrufen. Das passiert automatisch, wenn das Load-Ereignis abgewickelt wurde. Load soll der zusätzlichen Initialisierung dienen, bevor das Formular angezeigt wird. Rufst Du Show auf, kann die Anzeige "zappelig" werden, weil noch nicht alle Steuerelement fertig zur Anzeige sind.
Um einige Zeilen Text einzulesen, ist es einfacher die File-Methoden,
hier z. B. File.ReadAllLines zu verwenden. (Vermeidet den kleinen Fehler, dass Du ein offene Datei behältst, wenn dort nur eine Zeile drin ist).Zum MyButtonHandler_Click - der besser MyPictureBox_Click hiesse:
Visual Basic kennt TryCast - dort stehen die Unterschiede zu DirectCast und CType - womit Du den richtigen Typ erhältst. Grundsätzlich gilt: .NET ist strenger in der Typisierung als VB 6. Es empfiehlt sich neuen Code immer mit Option Strict On zu erstellen. Ohne das verhält sich VB zwar mehr wie VB 6, man riskiert dafür unnötige Laufzeitfehler.
Zusammengefasst würde ich das (ungetestet) in etwa so schreiben:
Private Bild() As Bitmap Private kontrollbitmap As Bitmap Const Ladefile As String = "C:\baut1\steckbrl1.txt" 'z.B.Hier stehen die Images Private Sub DateienLaden() Dim dateien = System.IO.File.ReadAllLines(Ladefile, System.Text.Encoding.Default) ' Windows ANSI ' Maximal 2 Dateien (-1 für 0-basierend) Dim anzahl = Math.Min(dateien.Length, 2) - 1 ' Array in passender Größe erstellen bild = New Bitmap(anzahl) {} ' Dateien laden und PictureBoxen erstellen For index = 0 To anzahl bild(index) = New System.Drawing.Bitmap(dateien(index)) Dim pbox = New PictureBox() pbox.Name = "BauteilBox" & index.ToString() pbox.Image = bild(index) ' Positionierung ausgelassen AddHandler pbox.Click, AddressOf MyPictureBox_Click Me.Controls.Add(pbox) Next End Sub ' Namen von Eventhandler angepasst um die Herkunft anzuzeigen Private Sub MyPictureBox_Click(ByVal sender As Object, ByVal e As EventArgs) ' DirectCast sollte zwar ausreichen... Dim pbox = TryCast(sender, PictureBox) If pbox IsNot Nothing Then KontrollPicBox1.Image = pbox.Image End If End SubGruß Elmar
-
Dienstag, 26. Februar 2013 11:52
Hallo Elmar ,
super Deine Vorschläge , ich streng mich an . Entschuldige „Show.. Ich bin noch in der Erprobungsfase und debugge im Einzelschritt . Show erzwingt die Form Anzeige , so kann ich die (das) Form und gleichzeitig den Code sehen . Schlampig , wie ich bin , habe ich dies stehen lassen . MyPictureBox , klar . File.ReadAllLines, habe ich ausgebessert . Ich probiere gerade mit Pictureboxen , Ich glaube ich lasse die PicBoxen einfach stehen und erst beim Speichern erzeuge ich eine Bitmap , oder ein Image .
Option Strict On : Man kann dann aber das Image nicht in eine Bitmap umwandeln , es kommt die Fehlermeldung :
Option Strict on lässt keine implizierte Konvertierung von System.Drawing image in System.Drawing Bitmap zu .
Meine alten Dateien sind aber alles Bitmaps , jetzt will ich mit Vectoren weiter machen .
Den Code unten habe ich getestet , das Modul und die Public Variablen nur zum Spielen , wird natürlich entfernt .
Jetzt weiss ich nicht , ob es eine Eigenschaft gibt , die Hintergrundfarbe durchsichtig zu machen . In VB 6 wurde das mit AND gemacht , das gibt es doch sicher fertig . Im Programm die 3 Labels MousKoord , Bildzaehlerlbl und Bildname zur Kontrolle .
Ich habe eine PictureBox Moveboxzum Verschieben der Bauteile . Die Bauteilboxen werden erst bei Ausführung geladen . Die Ruheboxerst nach Mousup . Das ganze auf das Form .
'Option Strict On Imports System Imports System.IO Imports System.Collections Imports System.Drawing Public Class Drawing2 ' Public Bld(2) As String Public oben As Integer = 100 Public unten As Integer = 750 Public links As Integer = 230 Public rechts As Integer = 1300 Public Picbreit As Integer Public Pichoch As Integer '##################################### UPGS Private Sub picture_laden(x As String, y As String) Dim name As String ' x = zeichneObjekt 'y = string vom Bild , oder bitmap If zeichneObjekt = "laden" Or zeichneObjekt = "ruhesanft" Then Select Case zeichneObjekt Case "laden" name = "BauteilBox" mybitmap = New Bitmap(y) Case "ruhesanft" name = "RuheBox" 'mybitmap schon belegt ! End Select Dim newpicturebox As New PictureBox newpicturebox.Name = name & Boxenzähler.ToString() 'Name newpicturebox.SizeMode = PictureBoxSizeMode.AutoSize newpicturebox.Image = mybitmap newpicturebox.Left = mauslocationx ' BauteilBox1.Left newpicturebox.Top = mauslocationy 'BauteilBox1.Top newpicturebox.Visible = True 'wird true , wenn mouse Move ' Ereignishandler click hinzufügen. 'wenn nötig für Laden u. ruhesanft verschiedene 'Handler einfügen . 'bei Handler gleich kann mit Click auf geparkten PicBoxen weiter gemacht werden . AddHandler newpicturebox.Click, AddressOf MyPictureBox_Click ' Der Auflistung von Steuerelementen das Steuerelement hinzufügen. Controls.Add(newpicturebox) Boxenzähler += 1 'Zähler mauslocationy += newpicturebox.Height + 15 Bildzaehlerlbl.Text = Str(Controls.Count) End If End Sub '############## Form Private Sub Drawing2_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove If zeichneObjekt <> "move" Then Exit Sub If e.X > links And e.Y > oben And e.X < rechts - Picbreit And e.Y < unten - Pichoch Then Movebox.Left = e.X + 5 Movebox.Top = e.Y + 5 MousKoord.Text = e.X & " ; " & e.Y Movebox.Visible = True End If End Sub Public Sub MyPictureBox_Click(ByVal sender As Object, ByVal e As EventArgs) 'Click auf PicBox If TypeOf sender Is PictureBox Then 'Kontrolle mybitmap = TryCast(sender, PictureBox).Image 'Bitmap zum Ziehen mauslocationx = TryCast(sender, PictureBox).Left mauslocationy = TryCast(sender, PictureBox).Top 'y von gewählter Box Picbreit = TryCast(sender, PictureBox).Width Pichoch = TryCast(sender, PictureBox).Height 'movebox bleibt unsichtbar eingeparkt Movebox.Image = mybitmap Movebox.Visible = False Bildname.Text = TryCast(sender, PictureBox).Name zeichneObjekt = "Rahmen rot" Me.Invalidate() End If End Sub Private Sub SchließenToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SchließenToolStripMenuItem.Click Close() End Sub Private Sub Drawing2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Dim n As Integer Me.WindowState = 2 'Rahmen zeichnen zeichneObjekt = "laden" ' mybitmap = New Bitmap("C:\baut1\infrtrans.STL") ' BauteilBox1.Image = mybitmap Bld(0) = "C:\baut1\infrtrans.STL" Bld(1) = "C:\baut1\infrarsend.STL" Bld(2) = "C:\baut1\steckAnschl.STL" For n = 0 To 2 Call picture_laden("laden", Bld(n)) Next zeichneObjekt = "Ur_Rahmen" Invalidate() End Sub Private Sub DrawImageTeilToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles DrawImageTeilToolStripMenuItem.Click Invalidate() End Sub Private Sub Drawing2_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp 'Click geht auf Movebox , nicht auf Form , wenn in FormMove e.x -5/e.y -5 'auf Form bei + 5 'Stop zeichneObjekt = "ruhesanft" 'movebox wird unsichtbar eingeparkt mauslocationx = e.X + 5 mauslocationy = e.Y + 5 Movebox.Left = 200 Movebox.Top = 80 Movebox.Visible = False picture_laden(zeichneObjekt, "mybitmap") 'Paint anweisen , roten Rahmen zu zeichnen zeichneObjekt = "Rahmen weiss" Me.Invalidate() End Sub Private Sub Movebox_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Movebox.MouseUp 'Erklärung zu Click 'bei ' Movebox.Left = e.X + 5 ' Movebox.Top = e.Y + 5 'Ist Picture rechts unten 'dann Click Ereignis auf Form 'bei ' Movebox.Left = e.X - 5 ' Movebox.Top = e.Y - 5 'ist Movebox unter dem Mouse Zeiger 'Click geht dann auf Movebox , nicht auf Form , wenn -5 'auf Form bei + 5 'Stop 'zeichneObjekt = "Rahmen weg" 'mauslocationx = e.X 'mauslocationy = e.Y 'Invalidate() '########## wenn nötig beim Bewegen ,wenn 'mauszeiger auf Movebox , Routine für mauslocx,..Y / + e.x, y erstellen , dann kann 'movebox über geparkte Box gezogen werden . 'soll aber hier vermieden werden ! End Sub Private Sub Drawing2_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint Dim rec As New Rectangle(mauslocationx - 5, mauslocationy - 5, Picbreit + 10, Pichoch + 10) 'Zeichenfläche Dim g As Graphics = e.Graphics Dim r = New Rectangle(links - 5, oben - 5, rechts - links + 10, unten - oben + 10) 'Markierungsrahmen g.FillRectangle(Brushes.AntiqueWhite, r) 'Ur Rahmen wird immer gezeichnet Select Case zeichneObjekt Case "Ur_Rahmen" 'wird immer gezeichnet Case "Rahmen rot" g.FillRectangle(Brushes.Red, rec) zeichneObjekt = "move" Case "Rahmenweiss" g.FillRectangle(Brushes.AntiqueWhite, rec) End Select End Sub End Class Module Bildzeichnenmdl Public mybitmap As Bitmap Public Boxenzähler As Integer Public zeichneObjekt As String = "" Public mauslocationx As Integer = 50 Public mauslocationy As Integer = 80 Public Bld(2) End Module
Beste Grüße Jürgen und vielen Dank.
-
Dienstag, 26. Februar 2013 14:40Beantworter
Hallo Jürgen,
Du brauchst Dich nicht für Show entschuldigen, dafür sind Foren da. Solche Dinge haben wir anfangs alle gemacht (und manche tuns immer noch ;).
Zum Konvertieren:
Wie schon geschrieben .NET (und Visual Basic) sind streng typisiert. und daraus ergibt sich die Notwendigkeit den richtigen Typ zu verwenden.
Ein PictureBox.Image ist vom Typ System.Drawing.Image. Eine Bitmap ist von Image abgeleitet, kann aber mehr. Aber ein Image könnte auch ein Metafile sein (wenn auch eher selten verwendet), was was anderes ist (und dann schief ginge).
Visual Basic erlaubt eine implizite Konvertierung, wenn der Typ "kleiner" ist, erfordert aber eine explizite Konvertierung wenn der Typ "größer" ist, mehr siehe Implizite und explizite Konvertierungen (Visual Basic)
Und hier ist deswegen einen Cast notwendig:
Bitmap myBitmap = DirectCast(PictureBox.Image, Bitmap)
Da Konvertieren auch kostet, sollte man das immer nur einmalig machen. In Deinem MyPictureBox_Click ist es deshalb sinnvoll eine Variable vom Typ PictureBox einzuführen und einen DirectCast durchzuführen, anstatt dies jedes Mal zu machen:
Public Sub MyPictureBox_Click(ByVal sender As Object, ByVal e As EventArgs) ' Einmal casten Dim myPictureBox = DirectCast(sender, PictureBox) Dim myBitmap = DirectCast(myPictureBox.Image, Bitmap) mauslocationx = myPictureBox.Left mauslocationy = myPictureBox.Top Picbreit = myPictureBox.Width Pichoch = myPictureBox.Height ' Alternativ für oben: Rectangle MyPictureBoxBounds = myPictureBox.Bounds Movebox.Image = mybitmap Movebox.Visible = False Bildname.Text = myPictureBox .Name zeichneObjekt = "Rahmen rot" End Sub(außerdem muss man weniger tippen und es wird deutlich lesbarer ;)
TryCast ist wäre zu viel des Guten (und ich hatte es nur wegen Deines TypeOf gezeigt), da es in dem Fall, wo die Typen nicht passen Nothing liefert; was man im allgemeinen überprüft. Da das aber gar nicht passieren kann ist DirectCast besser.
Zum Malen selbst ließe sich einiges sagen. Doch probiere erst mal selbst ein wenig. Wenn Fragen kommen, mache bitte eine neue Diskussion auf - hier wird es etwas unübersichtlich viel.
Kleiner Tipp zum Debuggen: Anstatt "Stop" kannst Du jederzeit über "F9" einen Breakpoint setzen.
Gruß Elmar

