Mehrere PictureBoxen mit MouseDown Event verändern

ibktp

Grünschnabel
Hallo,

folgendes Problem, welches ich trotz Suchen nicht gelöst kriege.

Ich möchte um meine VB.NET Kenntnisse zu festigen ein kleines Spielchen entwickeln (Wörter in einem "Buchstabensalat" suchen)
Buchstaben sollen in Quadraten untergebracht sein.
Ich habe eine Klasse die von einer PictureBox erbt und ein paar zusatzfunktionen hat (Das Quadrat). Wenn man jetzt ein Wort gefunden hat soll man es natürlich Markieren können. Mein Wunsch ist es mit gedrückter Maustaste über die betrefenden Felder zu steuern. Diese sollen dann natürlich die Farbe ändern.
Das Problem: Die erste PictureBox macht das auch noch, aber die Nachfolgenden reagieren auf nichts mehr. Auch auf keinen Enter Event.
Ich habe dann Versucht das ganze in einen anderen Thread auszulagen (vorher noch nie gemacht) aber auch das bringt kein Ergebnis. Kann mich jemand in die Spur bringen?


Der BackgroundWorker (in meiner Klasse Deklariert):
Code:
 Private th As BackgroundWorker
 
Public Sub New( )
th = New BackgroundWorker
        AddHandler th.DoWork, AddressOf th_DoWork
        th.WorkerReportsProgress = True
        th.WorkerSupportsCancellation = True
end sub

und Hier meine Mouse Events und der BackgroundWorker der Klasse:
Code:
Public Sub myEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyClass.MouseEnter
        Me.BackColor = Color.DarkViolet
    End Sub

    Public Sub mousepushed(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        th.RunWorkerAsync()
    End Sub

    Public Sub th_dowork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
        Me.BackColor = Color.Red
        gewählt = True
        ' Debug.Print(e.)
    End Sub
 
Einen Backgroundworker zu verwenden halte ich für eine äußerst seltsame Idee (was soll das bringen?). Außerdem solltest du Eigenschaften von Controls nur aus dem Thread heraus verändern, von welchem das Control erstellt wurde.
Das MouseEnter-Event der zweiten PictureBox kann erst abgearbeitet werden, wenn für die erste PictureBox das MouseUp-Event eingetreten ist (weiß nicht warum).
Ich würde nur eine einzige PictureBox verwenden, in der du alle deine Rechtecke zeichnest. Oder du verwendest einen programmglobalen Hook um auf Mausbewegungen zu reagieren (Hooks sind aber nicht unbedingt trivial)
 
Den Versuch mit dem BackgroundHandler habe ich gestartet, weil ich dachte, dass eben das erste Quadrat "beschäftigt" ist mit dem Mouse Down. Bei Ladebalken wird das doch auch in der Richtung gemacht?
Wenn ich eine PictureBox Verwende müsste ich die Quadrate mit GDI zeichnen nehme ich an. Den gedanken hatte ich auch schon. Habe mich dann aber für die Picturebox entschieden weil ich später statt einen Farbwechsel Grafiken wechseln will, deswegen die Box.
Hooks kenne ich noch gar nicht, was mich aber nicht abschreckt mich mal schlau zu machen. Danke.
So ganz will ich mich noch nicht von meiner Idee mit mehreren Boxen trennen.
Ich teste mal ob es mich weiter bringt das MouseUp Event manuell auszulösen. Evtl in kombination mit einem Timer.
 
Hi,

Ich kanns grad nicht testen aber versuche doch mal alle Events auf einen Eventhandler zu legen und dann dort über sender die richtige PictureBox raussuchen. Vielleicht kommt dann dein Enter - Event durch.

Gruß
Erik
 
Alternativ könntest du das MouseEnter-event benutzen und in diesem fragen, ob die linke Maustaste gedrückt ist.

Gruß
col.blake
 
@Erik : das ist ne gute idee. Ich werds mal probieren. Mal schauen ob das klappt.
Code:
Handles Pbox1.MouseDown, Pbox2.MouseDown usw...
nach diesem Prinzip.

@col.blake: das ist ja genau das Problem :) es werden keine Events ausgelöst, weil wie ich hier gelernt habe das Steuerelement, das MouseDown ausgelöst hat "blockt" bis es das zugehörige MouseUp empfängt.
 
Erik hat mich auf die richtige Idee gebracht. Habe zum Testen Panels statt PictureBoxen verwendet, aber das dürfte ja egal sein. Hier der Code (ich gehe davon aus, dass auf der "Form1" zur Entwicklungszeit bereits mehrere Panels platziert wurden:
Code:
Public Class Form1
    Private Sub Panel_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Dim PositionRelativeToForm As Point = e.Location
            PositionRelativeToForm.Offset(CType(sender, Control).Location)
            Dim ControlAtMousePoint As Control = Me.GetChildAtPoint(PositionRelativeToForm, GetChildAtPointSkip.Invisible)
            If TypeOf ControlAtMousePoint Is Panel Then
                Dim PanelAtMousePoint As Panel = CType(ControlAtMousePoint, Panel)
                PanelAtMousePoint.BackColor = Color.Blue
            End If
        End If
    End Sub

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        For Each c As Control In Me.Controls
            If TypeOf c Is Panel Then
                Dim p As Panel = CType(c, Panel)
                p.BackColor = Color.Red
                AddHandler p.MouseMove, AddressOf Panel_MouseMove
            End If
        Next
    End Sub
End Class
Ich habe dabei folgendes gemacht:
Im Konstruktor der Form abonniere ich das MouseMove-Event von jedem Panel (damit ich es nicht manuell im Designer machen muss). Zusätzlich setze ich die Hintergrundfarbe auf "Rot".
Sobald sich die Maus über ein Panel bewegt und die linke Maustaste gedrückt ist, berechne ich die Mausposition relativ zur linken oberen Ecke des Client-Bereichs der Form und kann anhand dieser Koordinate überprüfen, ob sich unter der Maus ein Panel befindet. Wenn ja, dann wird die Farbe auf "Blau" geändert.
 
Zuletzt bearbeitet:
Zurück