Hallo zusammen ich hoffe mal das ist das richtige Unterforum für dieses Thema, wenn nicht, bitte verschieben...
ich habe ein Bitmap (einer WaveForm), das in einem Image-Control (entsprechend WinForms-PictureBox), welches auf einem Canvas liegt, angezeigt wird. Dort möchte ich einige verschiedene Linien zeichnen, einmal die Aufnahmeposition, die Playbackposition und eine Position, die man per Klick auf das Image setzen kann. Dabei kann man auch per Button das Image auf dem Canvas nach links oder rechts verschieben.
Hier mein Code:
Allgemein:
Spoiler anzeigen
Die Properties:
Spoiler anzeigen
Das tatsächliche Zeichnen der Linien und erstellen des Bitmaps:
Spoiler anzeigen
Wenn die Aufnahme gestoppt wird, wird Folgendes ausgeführt:
Spoiler anzeigen
Nun zu den Problemen:
(1) Im untersten Spoiler in Zeile 6 scheint das
(2) Wenn ich, nachdem
ich habe ein Bitmap (einer WaveForm), das in einem Image-Control (entsprechend WinForms-PictureBox), welches auf einem Canvas liegt, angezeigt wird. Dort möchte ich einige verschiedene Linien zeichnen, einmal die Aufnahmeposition, die Playbackposition und eine Position, die man per Klick auf das Image setzen kann. Dabei kann man auch per Button das Image auf dem Canvas nach links oder rechts verschieben.
Hier mein Code:
Allgemein:
VB.NET-Quellcode
- Public Function TransformToPixels(Units As Double) As Integer 'diese Funktion wandelt die in WPF gängigen Units in "bitmapfähige" Pixel um
- Using g As Graphics = Graphics.FromHwnd(IntPtr.Zero)
- Dim retValue As Integer = CInt(((g.DpiX / 96) * Units))
- Return CInt(retValue - (retValue * (MainModule.HoleSkalierung - 1)))
- End Using
- End Function
- Public Sub UpdateWaveForm(sender As Object, e As EventArgs) 'Aufruf über Dispatcher des MainWindows
- Try
- Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().Invoke(Sub() WellenFormZeichnen())
- Catch
- End Try
- End Sub
Die Properties:
VB.NET-Quellcode
- Private _RecordingXPosWF As Double 'Aufnahmeposition (rote Linie)
- Public Property RecordingXPosWF As Double
- Get
- Return _RecordingXPosWF
- End Get
- Set(value As Double)
- _RecordingXPosWF = value
- RaisePropertyChanged()
- End Set
- End Property
- Private _PlayXPosWF As Double 'die Playbackposition (grüne Linie)
- Public Property PlayXPosWF As Double
- Get
- Return _PlayXPosWF
- End Get
- Set(value As Double)
- If value <= RecordingXPosWF Then
- _PlayXPosWF = value
- PlayBackPosition = TimeSpan.FromSeconds(GetPositionInSeconds(_PlayXPosWF))
- RaisePropertyChanged()
- Else
- If IsPlaying Then
- Bass.BASS_ChannelStop(PlayBackChannel)
- Else
- Dim OKVM = New OKDialogViewModel
- OKVM.Meldung = "Du versuchst die Abspielposition auf einen ungültigen Wert festzulegen. Bitte stelle sicher, dass du die Abspielposition links von oder direkt auf dem Aufnahmefortschritt platzierst."
- Services.ServiceContainer.GetService(Of IMainWindowService)?.HoleDispatcher().Invoke(Sub() dialogService.ShowModalDialog("", OKVM, Me, True, False, Services.WindowStyle.None, Services.ResizeMode.NoResize, 500, Services.SizeToContent.Height, Services.WindowStartupLocation.CenterOwner, ""))
- End If
- End If
- End Set
- End Property
- Private _ClickedXPosWF As Double 'klickbare Position (gelbe Linie)
- Public Property ClickedXPosWF As Double
- Get
- Return _ClickedXPosWF
- End Get
- Set(value As Double)
- If value <= RecordingXPosWF Then
- _ClickedXPosWF = value
- MarkerPosition = TimeSpan.FromSeconds(GetPositionInSeconds(value))
- RaisePropertyChanged()
- Else
- Dim OKVM = New OKDialogViewModel
- OKVM.Meldung = "Du versuchst den Marker auf einen ungültigen Wert festzulegen. Bitte stelle sicher, dass du die Markerposition links von oder direkt auf dem Aufnahmefortschritt platzierst."
- dialogService.ShowModalDialog("", OKVM, Me, True, False, Services.WindowStyle.None, Services.ResizeMode.NoResize, 500, Services.SizeToContent.Height, Services.WindowStartupLocation.CenterOwner, "")
- End If
- End Set
- End Property
- Private _Zoom As Integer
- Public Property Zoom As Integer 'hier kann man zoomen, so dass die Bitmap eine höhere Auflösung hat dadurch, dass sie einfach breiter gezeichnet wird
- Get
- Return _Zoom
- End Get
- Set(value As Integer)
- _Zoom = value
- RaisePropertyChanged()
- UpdateWaveForm(Nothing, Nothing)
- End Set
- End Property
- Private _WFBreite As Double
- Public Property WFBreite As Double 'Die Breite des Image-Controls, gebunden an ActualWidth
- Get
- Return _WFBreite
- End Get
- Set(value As Double)
- _WFBreite = value
- RaisePropertyChanged()
- End Set
- End Property
- Private _WFXPosOnCanvas As Double
- Public Property WFXPosOnCanvas As Double 'Die X-Position des Image-Controls auf dem Canvas
- Get
- Return _WFXPosOnCanvas
- End Get
- Set(value As Double)
- _WFXPosOnCanvas = value
- RaisePropertyChanged()
- End Set
- End Property
Das tatsächliche Zeichnen der Linien und erstellen des Bitmaps:
VB.NET-Quellcode
- Public Sub WellenFormZeichnen()
- If WF IsNot Nothing Then
- If RecordingXPosWF <> 0 Then
- Dim WellenForm As Bitmap = WF.CreateBitmap(CInt(TransformToPixels(WFBreite)) * Zoom, CInt(TransformToPixels(WFHoehe) * MainModule.HoleSkalierung), -1, -1, False) 'Bitmap erzeugen
- Dim Grafik As Graphics = Graphics.FromImage(WellenForm)
- Dim Stift As System.Drawing.Pen
- If (RecordingXPosWF <> Nothing) OrElse (RecordingXPosWF <> 0) Then
- Stift = New System.Drawing.Pen(System.Drawing.Color.Red)
- Grafik.DrawLine(Stift, CSng(TransformToPixels(RecordingXPosWF) * Zoom), 0, CSng(TransformToPixels(RecordingXPosWF) * Zoom), TransformToPixels(WFHoehe)) 'Aufnahmeposition einzeichnen (rot)
- End If
- If (ClickedXPosWF <> Nothing) OrElse (ClickedXPosWF <> 0) Then
- Stift = New System.Drawing.Pen(System.Drawing.Color.Yellow)
- Grafik.DrawLine(Stift, CSng(ClickedXPosWF * Zoom - WFXPosOnCanvas), 0, CSng(ClickedXPosWF * Zoom - WFXPosOnCanvas), TransformToPixels(WFHoehe)) 'klickbare Position enizeichnen (gelb)
- End If
- If (PlayXPosWF <> Nothing) OrElse (PlayXPosWF <> 0) Then
- Stift = New System.Drawing.Pen(System.Drawing.Color.Green)
- Grafik.DrawLine(Stift, CSng(PlayXPosWF * Zoom - WFXPosOnCanvas), 0, CSng(PlayXPosWF * Zoom - WFXPosOnCanvas), TransformToPixels(WFHoehe)) 'Playbackposition einzeichnen (grün)
- End If
- WaveForm = BitmapToImageSource(WellenForm)
- Else
- WaveForm = BitmapToImageSource(WF.CreateBitmap(CInt(TransformToPixels(WFBreite)) * Zoom, CInt(TransformToPixels(WFHoehe) * MainModule.HoleSkalierung), -1, -1, False))
- End If
- Else
- WaveForm = Nothing
- End If
- End Sub
Wenn die Aufnahme gestoppt wird, wird Folgendes ausgeführt:
VB.NET-Quellcode
- Private Sub RecordingStopped()
- Bass.BASS_ChannelStop(RecordingChannel)
- Dim Prozent As Double = BytesWritten / MaxTrackLaengeInBytes * 100 'ermitteln der Aufnahmeposition
- RecordingXPosWF = TransformToPixels(WFBreite) / 100 * Prozent 'wenn ich hier WFBreite nicht zu Pixel transformiere, bekomme ich augenscheinlich das gleiche Ergebnis, was eigentlich nicht sein kann??
- WF.RenderRecording(RenderBuffer, RenderLength)
- UpdateWaveForm(Nothing, Nothing)
- If Not IsPlaying Then PeakTimer.Stop()
- PeakL = 0
- PeakR = 0
- RecordingOrStoppedIcon = RecordingIcon
- HasRecorded = True
- IsRecording = False
- End Sub
Nun zu den Problemen:
(1) Im untersten Spoiler in Zeile 6 scheint das
TransformToPixels
keinen Effekt zu haben. Denn egal wie ich es mache, die Position scheint immer korrekt gezeichnet zu werden. Eigentlich ja gut, aber in irgendeiner sehr speziellen Situation könnte mir das um die Ohren fliegen... Der Code geht definitv auch an dieser Stelle vorbei, hab es mit Haltepunkt getestet...(2) Wenn ich, nachdem
RecordingStopped
ausgeführt wurde, den Zoom erhöhe und das Image auf dem Canvas verschoben habe, und dann wieder den Zoom verändere, dann werden häufig die gelbe und grüne Linie falsch gezeichnet, was ich nicht verstehe. Siehe angehängte Screenshots. Bei dem fehlerbehafteten Screenshot sind die gelbe und rote Linie auf einmal rechts von der roten Linie, was nicht sein darf, und dich verstehe nicht, wie das zu Stande kommen kann...