Nicht auf einer Form sondern außerhalb einer Form zeichnen (Multiple Screen)

  • VB.NET
  • .NET (FX) 4.0

Es gibt 31 Antworten in diesem Thema. Der letzte Beitrag () ist von Drahuverar.

    Nicht auf einer Form sondern außerhalb einer Form zeichnen (Multiple Screen)

    Hallo Leute,

    für ein kleines Projekt suche ich zur Zeit die Möglichkeit außerhalb der Form zu zeichnen (Im Grunde immer auf dem Bildschirm / Die aktive Ansicht).
    Bin schon auf div. WinAPIs gestoßen, komme aber nicht klar. Mit dem Beispiel hier komme ich nicht wirklich zum Ziel (es passiert gar nichts).

    Beispiel
    (Habe es auch schon mit der GetDCEx Funktion versucht, leider ohne Erfolg)

    Hat jemand Tipps und oder Hinweise?
    Danke.
    Option Strict On!
    Das waere eine moeglichkeit, allerding muss regelmaessig neu gezeichnet werden.

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. <DllImport("user32.dll")>
    4. Private Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr
    5. End Function
    6. <DllImport("user32.dll")>
    7. Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean
    8. End Function
    9. Private Sub DrawOnScreen()
    10. Dim hDC As IntPtr = GetDC(IntPtr.Zero)
    11. If hDC <> IntPtr.Zero Then
    12. Using graphics As Graphics = graphics.FromHdc(hDC)
    13. Dim bounds As Rectangle = Screen.PrimaryScreen.Bounds
    14. Using pencil As New Pen(Brushes.Black, 3)
    15. graphics.DrawLine(pencil, 0, 0, bounds.Width, bounds.Height)
    16. End Using
    17. End Using
    18. ReleaseDC(hDC, IntPtr.Zero)
    19. End If
    20. End Sub
    21. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    22. DrawOnScreen()
    23. End Sub
    24. End Class
    And i think to myself... what a wonderfuL World!
    Hey @Eddy,
    funktioniert leider nicht... oder doch? 8|
    Das Beispiel, welches ich gepostet habe, funktioniert auch.

    Jetzt kommt das komische an der Sache:
    Es funktioniert nur, wenn ich kein Monitor bzw. 1 Monitor (Laptop-Bildschirm) angeschlossen habe... ?(
    Vielleicht weiß jemand, was man hier machen muss.. ich werde jedenfalls den Tag wohl mit Google verbringen. :/
    Option Strict On!
    @Drahuverar @Eddy Beide Codes funktionieren einwandfrei. W10, VS2013.
    @Drahuverar ist Strict Off und muss präzisieert werden.
    ReleaseDC(0, dc) ==> ReleaseDC(dc, IntPtr.Zero)
    Hier sind beide Zeichnungen drauf:

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Drahuverar schrieb:

    mit mehreren Anzeige-Geräten
    Ich habe 2 Bildschirme.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany
    @Eddy
    Ich bekomme es nicht hin. Weder mit dem Beispiel von Dir Eddy, noch mit dem Beispiel von VB-Fun.
    Ich habe ein Monitor über VGA angeschlossen- Hast du deinen Monitor über HDMI oder Displayport angeschlossen @RodFromGermany?

    kleines Beispiel auf 'ner Form. Funktioniert wie gesagt nur ohne weiteres Anzeigegerät. (siehe Anhang)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. <DllImport("user32.dll")>
    4. Private Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr
    5. End Function
    6. <DllImport("user32.dll")>
    7. Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean
    8. End Function
    9. Private Sub Eddy()
    10. Dim hDC As IntPtr = GetDC(IntPtr.Zero)
    11. If hDC <> IntPtr.Zero Then
    12. Using graphics As Graphics = Graphics.FromHdc(hDC)
    13. Dim bounds As Rectangle = Screen.PrimaryScreen.Bounds
    14. Using pencil As New Pen(Brushes.Black, 3)
    15. graphics.DrawLine(pencil, 0, 0, bounds.Width, bounds.Height)
    16. End Using
    17. End Using
    18. ReleaseDC(hDC, IntPtr.Zero)
    19. End If
    20. End Sub
    21. Private Sub vbFun()
    22. Dim RedPen As New Pen(Color.Red, 50)
    23. Dim GreenPen As New Pen(Color.GreenYellow, 50)
    24. Dim dc As IntPtr
    25. Dim g As Graphics
    26. Dim i As Integer
    27. Dim waW, waH As Long
    28. waW = Screen.PrimaryScreen.WorkingArea.Width
    29. waH = Screen.PrimaryScreen.WorkingArea.Height
    30. dc = GetDC(IntPtr.Zero)
    31. g = Graphics.FromHdc(dc)
    32. g.DrawLine(RedPen, 10, 10, waW - 10, waH - 10)
    33. g.DrawLine(GreenPen, waW - 10, 10, 10, waH - 10)
    34. g.DrawString("VB-fun", New Font("Comic Sans Ms", 70),
    35. New SolidBrush(Color.DarkBlue), 300, 300)
    36. g.Dispose()
    37. ReleaseDC(dc, IntPtr.Zero)
    38. End Sub
    39. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    40. Eddy()
    41. vbFun()
    42. End Sub
    43. End Class


    ...ich habe keine Ahnung, woran es liegen könnte. :(
    Bilder
    • Anhang.png

      68,59 kB, 1.335×911, 115 mal angesehen
    Option Strict On!

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

    @Drahuverar Das sieht mir nach der Standard-System-Schriftgröße aus, ansonsten ist mein Bild identisch.
    Ich geh über HDMI.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Bluespide schrieb:

    Graphics.FromHwnd(IntPtr.Zero)
    Jou, geht genau so. :D
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Bluespide schrieb:

    Warum überhaupt mit DllImport?

    Wie soll 'ich' (das Programm) denn mit dieser Funktion wissen auf welchem Handle ich zeichnen möchte? In meiner eigenen Anwendung und auch anderen Form-Objekten in meiner Anwendung macht das sicherlich Sinn, anders aber nicht (..wenn ich auf Windows Ebenen zeichnen möchte, brauche ich ja die WinAPI). Korrigiert mich bitte, wenn ich das falsch sehe- kann ja durchaus sein, dass ich das Falsch verstanden habe.

    Ich möchte gerne folgendes erreichen:
    An der Stelle, an der sich die Maus befindet (GetCursorPos()) möchte ich (rechts) von der Maus Symbole einblenden lassen.
    Das funktioniert, leider auch nur, wenn nur ein Anzeigegerät angeschlossen ist.
    Option Strict On!

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

    Bluespide hat schon recht, das Funktionert auch.

    VB.NET-Quellcode

    1. Private Sub DrawOnDesktop()
    2. Using graphics As Graphics = graphics.FromHwnd(IntPtr.Zero)
    3. Dim bounds As Rectangle = Screen.PrimaryScreen.Bounds
    4. Using pencil As New Pen(Brushes.Black, 3)
    5. graphics.DrawLine(pencil, 0, 0, bounds.Width, bounds.Height)
    6. End Using
    7. End Using
    8. End Sub


    Die GetCursorPos-Api-Function kannste einsparen.
    Dim p As Point = Cursor.Position

    Wenn du dort ein Symbol anzeigen moechtest, waere es vieleicht besser eine Form mit Borderstyle.None zu nehmen und darauf zu malen, dann flickert das nicht so.
    And i think to myself... what a wonderfuL World!

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

    Eddy schrieb:

    Die GetCursorPos-Api-Function kannste einsparen

    Jou, da haste Recht. :D
    Bin schon so sehr davon ausgegangen, das die Cursor.Position sich auf die Form beschränkt. :saint:

    Jedenfalls haben alle Recht- Es passt aber nicht, für das was ich machen wollte.
    Momentan wird immer auf dem von dem Benutzer definierten Hauptbildschirm gezeichnet. Das ist wie gesagt schon Mal etwas, und auch mit insgesamt 2 Monitoren funktioniert es nun auch- danke Jungs @RodFromGermany, @Eddy und @Bluespide - wechsel ich nun aber die Position der Maus auf einen anderen Bildschirm, kann ich ja nicht mehr auf diesem die Zeichnung erstellen bzw. zeichnen. Aus diesem Grund war ich auch der Meinung, dass ich die GetDC - Funktion bräuchte, um später einen anderen Monitor auswählen zu können.

    Die Startposition der Anwendung verändern bringt leider nichts.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim scr As Screen
    2. scr = Screen.AllScreens(1)'zum testen einfach mal die werte ändern (je nach anzahl der monitore)
    3. Me.StartPosition = FormStartPosition.Manual
    4. Me.Location = scr.Bounds.Location

    Daher stellt sich mir die Frage, wie ich vorgehen muss um das richtige Handle zu finden.
    Vielleicht wisst ihr ja, wie ich das am besten realisieren kann- für's erste lass ich es Mal sein, da ich gerade zu sehr an der GetDC-Geschichte hänge.
    Option Strict On!

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

    Edit:
    @Drahuverar
    Mit EnumDeviceDisplay kann man sich sparen, haette nur dazu gedient an den Devicenamen zu kommen, daran kommen wir aber auch ueber die Screen-Klasse. Probier mal dies:

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class Form1
    3. <DllImport("gdi32.dll")>
    4. Private Shared Function CreateDC(ByVal lpszDriver As String, ByVal lpszDevice As String, ByVal lpszOutput As String, ByVal DEVMODE As IntPtr) As IntPtr
    5. End Function
    6. <DllImport("gdi32.dll")> _
    7. Private Shared Function DeleteDC(ByVal hdc As IntPtr) As Boolean
    8. End Function
    9. Private Sub DrawOnScreens()
    10. For i = 0 To Screen.AllScreens.Length - 1
    11. Dim scr As String = Screen.AllScreens(i).DeviceName
    12. Dim hdc As IntPtr = CreateDC(Nothing, scr, Nothing, Nothing)
    13. Using g As Graphics = Graphics.FromHdc(hdc)
    14. Dim bounds As Rectangle = Screen.AllScreens(i).Bounds
    15. Using pencil As New Pen(Brushes.Black, 3)
    16. g.DrawLine(pencil, 0, 0, bounds.Width, bounds.Height)
    17. End Using
    18. End Using
    19. DeleteDC(hdc)
    20. Next
    21. End Sub
    22. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    23. DrawOnScreens()
    24. End Sub
    25. End Class




    Ups, sorry wollte editieren nicht doppelt posten.
    And i think to myself... what a wonderfuL World!

    Eddy schrieb:

    Wenn du dort ein Symbol anzeigen moechtest, waere es vieleicht besser eine Form mit Borderstyle.None zu nehmen und darauf zu malen, dann flickert das nicht so.
    Ich würde darauf nochmal genauer eingehen. Wenn du das in eine Timer packst geht das nicht? Für dein Vorhaben scheint mir das auch gut zu passen.

    VB.NET-Quellcode

    1. ​Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. Me.Timer1.Interval = 1
    3. Me.Timer1.Start()
    4. End Sub
    5. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    6. Me.Location = Point.Add(Cursor.Position, New Size(20, 0))
    7. End Sub
    Vielen Dank, @Eddy!

    Bluespide hat da einen guten Einwand mit der Positionierung bzw. mit der Positionsbestimmung der Form.

    @Bluespide
    Weißte.. Das sind so die Dinger, bei denen ich nur noch denken kann "Wieso denke ich so kompliziert". 8|
    Im Grunde ist das die wohl einfachste Möglichkeit. Form einblenden -> Anzeigen -> Form schließen -> Timer wieder stoppen -> fertig.
    Option Strict On!
    Ja, hat es. (Deswegen ein 'Hilfreich') :)
    Auf dem anderen Monitor auf jeden Fall. Auf dem Hauptbildschirm nicht- das liegt aber wohl daran, das die Form erscheint und die vorherige Zeichnung wieder von Windows überzeichnet wird.
    Option Strict On!

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