Live-Forum - Die aktuellen Beiträge
Anzeige
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender

Forumthread: Zeichnen in UserForm

Zeichnen in UserForm
19.02.2020 22:16:54
KlausF
Hallo an Alle!
Zunächst möchte ich mich erstmal für die zahllosen guten Tipps und Lösungen bedanken, die von so vielen Mitgliedern gegeben werden! Deshalb ist dieses Forum auch immer wieder der erste Anlaufpunkt, wenn ich nicht weiter komme.
Ich habe über die Forensuche schon viel über das Zeichnen in einer Userform gelesen. Ich bin positiv überrascht, dass ich einfache Figuren (Kreise, Rechtecke usw.) über diverse API-Funktionen in eine Form zeichnen kann.
Aber ein Problem konnte ich bisher absolut nicht lösen: Ich lasse nach dem öffnen der UserForm vor dem Zeichnen eine MsgBox "blabla" anzeigen und zeichne dann diverse Elemente. Alles gut!
Lasse ich aber den Aufruf für die MsgBox weg, bleibt die UserForm leer und keine der Figuren wird angezeigt. ich habe ein hWnd = GetForegroundWindow() ausprobiert, weil meine Vermutung dahin ging, dass ich nicht in das richtige Handle zeichne. Mit den diversen "Application.ScreenUpdating"-Sachen habe ich auch etliches ausprobiert, half alles nichts.
Hat jemand dazu eine Idee? Notfalls muss ich eine zeitlich begrenzte MsgBox (von einer Sekunde oder so) verwenden, möchte das aber nicht wirklich...
Ich würde mich über einen Tipp sehr freuen ;-)
Grüße an Alle!
Anzeige

12
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Zeichnen in UserForm
19.02.2020 22:32:01
onur
Hast du auch
UserformXY.Repaint

getestet?
AW: Zeichnen in UserForm
19.02.2020 22:42:59
KlausF
Hallo onur,
ja, habe ich auch probiert: Keine Veränderung (also keine Anzeige). Bei C-Code würde ich mir ansehen, welche Funktionen MsgBox() intern aufruft. Mit einem Disassembler bekomme ich sowas hin, aber in VBA?
Gruß Klaus
Anzeige
AW: Zeichnen in UserForm
19.02.2020 22:44:16
onur
Poste doch mal die (Beispiels-) Datei.
AW: Zeichnen in UserForm
19.02.2020 22:52:16
KlausF
Private Sub UserForm_Activate()
Dim lngHwndUserForm As LongPtr
hMapFormWnd = GetForegroundWindow()
hMapDC = GetDC(hMapFormWnd)
'currently the map ONLY will displayed if you do the call!!!
MsgBox "blabla"
' CoW_Form.Repaint
'draw all elements of map
Call drawMap(hMapDC, g_s_CurrentArea, g_i_CurrentMapNumber)
Anzeige
AW: Zeichnen in UserForm
19.02.2020 22:53:42
onur
Die DATEI - nicht das Makro.
AW: Zeichnen in UserForm
19.02.2020 23:07:45
KlausF
Sorry, aber da ist jede Menge Code von anderen Leuten drin.
Vielleicht kann man den Ablauf auch so nachvollziehen:
Die besagte UserForm wird von einer anderen UserForm gestartet. Ich bin bewusst nicht in die Funktion UserForm_Initialize() gegangen, weil diese UserForm nach dem Schließen evt. nochmals geöffnet werden kann.
Das ganze Ding funktioniert ja auch perfekt, wenn ich diese MsgBox steigen lasse. Wird eigentlich das Handle vom DeviceContext neu erstellt, wenn die UserForm.Hide und UserForm.Show erneut aufgerufen wird?
Anzeige
AW: Zeichnen in UserForm
19.02.2020 23:10:12
onur

CoW_Form.Repaint

muss NACH dem Zeichnen kommen, sonst bringt es ja auch nix.
AW: Zeichnen in UserForm
20.02.2020 00:43:30
KlausF
Das habe ich probeweise gemacht, es ändert sich nichts (keine Anzeige)...
AW: Zeichnen in UserForm
20.02.2020 08:38:43
volti
Hallo Klaus,
hier einige Gedanken, die mir so kommen:
Ich würde das handle der UF nicht über GetForegroundwindow holen sondern über FindWindow(vbNullString, Userform1.Caption) o.ä.
Dann hast Du auf jeden Fall das richtige handle.
Hieraus dann den DeviceConext holen und zeichnen.....
Damit das gut klappt, setze noch ein DoEvents rein. s.code (Beispiel)
Übrigens, Repaint sendet eine Neuzeichnungsanforderung via Excel an Windows und zeichnet die UF ohne deine extern durchgeführten Malaktivitäten neu. (s.Beispiel)
Das müsstest Du dann selber machen.
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" ( _
        ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
Declare PtrSafe Function Rectangle Lib "gdi32" (ByVal hdc As LongPtr, ByVal X1 As Long, _
     ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Sub test()
 UserForm1.Show vbModeless
 Dim hwnd As LongPtr, hMapDC As LongPtr
 hwnd = FindWindow(vbNullString, UserForm1.Caption)
 hMapDC = GetDC(hwnd)
 DoEvents
 Rectangle hMapDC, 10, 10, 200, 200
 Sleep 2000
 UserForm1.Repaint
End Sub
viele Grüße
Karl-Heinz

Anzeige
AW: Zeichnen in UserForm
20.02.2020 10:13:57
KlausF
Hallo Karl-Heinz!
Danke für deinen Lösungsansatz! Leider zeichnet dieser Code bei mir kein Rechteck. Vielleicht ist die Kombination von meiner Konfiguration das Problem: Ich fahre noch Windows 7 (x64) und Office 2013. Wenn diese Prozedur bei dir funktioniert, habe ich das Problem neben meinem Schreibtisch stehen. Allerdings nutzen wir im Job Windows 10 und Office 365, da ist es aber genauso
Gruß Klaus
Anzeige
AW: Zeichnen in UserForm
20.02.2020 10:30:27
volti
Hi Klaus,
ja das funktioniert bei mir (Win 10 64 Bit, Off 365).
Step doch mal per F8 durch und setze bei Deinem Code statt Msgbox Doevents ein. Sleep wäre auch noch 'ne Möglichkeit.
Aber es ist ja so: Man kann auf einem DeviceContext prima malen (auch auf einer Fensterfläche oder Desktop). Sobald die UF/das Fenster einen Repaint-Befehl durch Windows erhält (z.B. durch Fensteränderung, Überlappen anderer Fenster usw.) sind Deine Malaktionen erst mal weg. Denn die gehören nicht zum Repaint-Ablauf des Fensters sondern wurden von Dir obendrauf gesetzt.
viele Grüße
Karl-Heinz
Anzeige
AW: Zeichnen in UserForm
20.02.2020 11:15:10
KlausF
Hallo nochmal!
Karl-Heinz, vielen lieben Dank, du hast den Knoten bei mir durchschlagen! Ich habe nun verstanden, dass die von Excel gezeichneten Objekte (Button, DropDown u.ä.) auch von Excel neu gezeichnet werden. Meine über die API gezeichneten Objekte fallen bei ersten Auffrischung des Fensters (oder der Userform) in den Jordan.
Das bringt mich wirklich weiter! Danke auch für deine Zeit und Hilfsbereitschaft!
Gruß Klaus
Anzeige
;
Anzeige
Anzeige

Infobox / Tutorial

Zeichnen in einer UserForm mit Excel VBA


Schritt-für-Schritt-Anleitung

  1. UserForm erstellen: Öffne den VBA-Editor (Alt + F11), klicke mit der rechten Maustaste auf „VBAProject“, wähle „Einfügen“ und dann „UserForm“.

  2. Zeichnen vorbereiten: Füge den folgenden Code in das Modul der UserForm ein:

    Private Sub UserForm_Activate()
       Dim lngHwndUserForm As LongPtr
       Dim hMapFormWnd As LongPtr
       Dim hMapDC As LongPtr
    
       hMapFormWnd = FindWindow(vbNullString, Me.Caption)
       hMapDC = GetDC(hMapFormWnd)
    
       DoEvents ' Wartet auf die Beendigung anderer Ereignisse
       Rectangle hMapDC, 10, 10, 200, 200 ' Zeichne ein Rechteck
    
       Sleep 2000 ' Kurze Pause, um das Zeichnen zu sehen
       Me.Repaint ' Aktualisiere die UserForm
    End Sub
  3. API-Deklarationen hinzufügen: Füge folgende Deklarationen zu deinem Modul hinzu:

    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
    Private Declare PtrSafe Function Rectangle Lib "gdi32" (ByVal hdc As LongPtr, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
  4. UserForm testen: Führe die UserForm aus (F5) und beobachte das gezeichnete Rechteck.


Häufige Fehler und Lösungen

  • Fehler: Keine Anzeige der gezeichneten Elemente: Stelle sicher, dass du hMapFormWnd korrekt über FindWindow erhältst. Wenn der GetDC-Aufruf fehlschlägt, könnte es an einem falschen Handle liegen.

  • Fehler: UserForm bleibt leer: Überprüfe, ob DoEvents und Sleep korrekt eingesetzt sind. Diese Funktionen helfen, die Anzeigen zu aktualisieren.


Alternative Methoden

  • Statt GetForegroundWindow zu verwenden, nutze FindWindow, um das Handle der UserForm zu erhalten. Dadurch kannst du sicherstellen, dass du im richtigen Kontext zeichnest.

  • Du kannst auch UserForm.Repaint nach deinen Zeichenvorgängen aufrufen, um sicherzustellen, dass die UserForm die gezeichneten Objekte anzeigt.


Praktische Beispiele

Hier ist ein Beispiel, das ein Rechteck in einer UserForm zeichnet:

Private Sub UserForm_Activate()
    Dim hwnd As LongPtr
    Dim hdc As LongPtr

    hwnd = FindWindow(vbNullString, Me.Caption)
    hdc = GetDC(hwnd)

    Rectangle hdc, 50, 50, 250, 150 ' Zeichne ein Rechteck
    Me.Repaint
End Sub

Du kannst die Werte für die Koordinaten anpassen, um verschiedene Größen und Positionen zu testen.


Tipps für Profis

  • Verwende DoEvents strategisch, um sicherzustellen, dass das Zeichnen nicht durch andere Prozesse unterbrochen wird.

  • Betrachte die Verwendung von Sleep, um dem System Zeit zu geben, die Zeichnung zu verarbeiten. Dies kann besonders nützlich sein, wenn du komplexe Zeichnungen mit mehreren Elementen machst.

  • Teste deine UserForm in verschiedenen Excel-Versionen, um sicherzustellen, dass der Code plattformunabhängig funktioniert.


FAQ: Häufige Fragen

1. Warum wird mein gezeichnetes Rechteck nicht angezeigt? Das könnte an einem falschen Handle liegen. Stelle sicher, dass du FindWindow korrekt verwendest, um das Handle der UserForm zu erhalten.

2. Kann ich andere Formen als Rechtecke zeichnen? Ja, du kannst auch andere GDI-Funktionen verwenden, um Kreise oder Linien zu zeichnen. Dazu musst du die entsprechenden API-Funktionen deklarieren und aufrufen.

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Entdecke mehr
Finde genau, was du suchst

Die erweiterte Suchfunktion hilft dir, gezielt die besten Antworten zu finden

Suche nach den besten Antworten
Unsere beliebtesten Threads

Entdecke unsere meistgeklickten Beiträge in der Google Suche

Top 100 Threads jetzt ansehen
Anzeige