BPS #13: Drag & Drop - Auswertung

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

Xeres

Moderator

Betreff: BPS #13: Drag & Drop - Auswertung

BeitragSo, Okt 16, 2011 16:06
Antworten mit Zitat
Benutzer-Profile anzeigen
Eine Drag & Drop Funktion macht die Steuerung für viele Nutzer einfacher und/oder bequemer - wer konnte sie umsetzen?

Das war die Aufgabe

Postet hier eure Ergebnisse, Codes, Gedanken. Lernt von den anderen, seht euch deren Quelltext an und versucht euren eigenen zu verbessern.

Diskussion
Postet zu euren Codes stets eine kurze Erklärung mit euren Gedanken in denen ihr simpel gesagt die Frage "Wieso habe ich XY auf diese Art gelöst?" beantwortet. Beiträge, die nur den Code enthalten werden wir aus dem Thread entfernen.

Nächste Aufgabe
In zwei Wochen, wird die Musterlösung nach editiert und die nächste Aufgabe eingestellt.

Viel Spaß & viel Erfolg!

Musterlösung:
BlitzMax: [AUSKLAPPEN]
SuperStrict
' BPS: Holzchopf - Drag & Drop

Framework BRL.Max2D
Import BRL.Timer
Import BRL.Random
Import BRL.GLMax2D

' Fenster initialisieren
Graphics 800,600
Global timer:TTimer = CreateTimer(50)
SeedRnd MilliSecs()

' Deklarationen, hier alles vom Objekt
Local posX:Int = Rand(0,19) ' x-Position im Raster
Local posY:Int = Rand(0,14) ' y-Position im Raster
Local offX:Int, offY:Int ' relative Mausposition
Local drag:Byte = False ' ob das Objekt gezogen wird

' einfache Hauptschleife
While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
' Eingaben zwischenspeichern
Local mx:Int = MouseX()
Local my:Int = MouseY()
Local mhit:Byte = MouseHit(MOUSE_LEFT), mdown:Byte = MouseDown(MOUSE_LEFT)

' Raster zeichnen
For Local iy:Int = 0 To 14
For Local ix:Int = 0 To 19
Local gr:Int = 64 +32*((iy+ix)Mod 2)
SetColor gr,gr,gr
DrawRect ix*40,iy*40, 40,40
Next
Next

' festes Objekt
If Not drag
SetColor 240,240,240
DrawRect posX*40,posY*40, 40,40
' Objekt packen
If mhit
If mx=>posX*40 And mx<posX*40+40 And my=>posY*40 And my<posY*40+40
drag = True
' die Mausposition auf dem Objekt wird gespeichert (offset)
' das erlaubt, dass man das Objekt quasi irgendwo packen kann
' und es sich nicht "unter der Maus" bewegt
offX = mx -posX*40
offY = my -posY*40
EndIf
EndIf
' gepacktes Objekt
Else
SetColor 255,255,255
DrawRect mx-offX, my-offY, 40,40
' Objekt loslassen
If Not mdown
drag = False
' tileposition berechnen (wird gerundet)
posX = Int(Float(mx-offX)/40.0+0.5)
posY = Int(Float(my-offY)/40.0+0.5)
' ungünstige Rundungsfälle korrigieren
If posX<0 Then posX=0
If posX>19 Then posX=19
If posY<0 Then posY=0
If posY>14 Then posY=14
EndIf
EndIf

' Double-Buffering
Flip 0
Cls
' FPS-Begrenzung
WaitTimer(timer)
Wend

End
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
  • Zuletzt bearbeitet von Xeres am So, Okt 30, 2011 15:20, insgesamt 2-mal bearbeitet

BlitzMoritz

BeitragSo, Okt 16, 2011 19:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Steuer' hier auch 'mal wieder 'was bei ... und zwar schön knapp und kurz in 17 Zeilen ohne viel Service.
"Action" speichert die Aktivität der linken Maustaste, "Position" die Stelle des "Anfassens" und "R" die Rechteckkoordinaten.
Die simple Operation ( ... + 20) / 40 * 40 sorgt wegen Integer für das Einrasten.
Der Rest erklärt sich direkt aus dem Code - wüsste nich', was sonst noch viel zu sagen wäre ...
BlitzMax: [AUSKLAPPEN]
Graphics 800,600
Local Action@, Position%[2], R%[] = [Rand(0,680) / 40 * 40, Rand(0,510) / 40 * 40]
While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
Cls
If Action = False Then
DrawRect R[0], R[1], 120, 90
If MouseHit(1) Then
Position = [MouseX(), MouseY()]
If Abs(R[0] + 60 - Position[0]) <= 60 And Abs(R[1] + 45 - Position[1]) <= 45 Then Action = True
End If
Else
DrawRect R[0] + MouseX()-Position[0], R[1] + MouseY()-Position[1], 120, 90
Action = MouseDown(1)
If Action = False Then R = [(R[0] + MouseX()-Position[0] + 20) / 40 * 40, (R[1] + MouseY()-Position[1] + 20) / 40 * 40]
End If
Flip
Wend

Thunder

BeitragSo, Okt 16, 2011 21:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Meine Lösung erinnert vielleicht etwas an einen Desktop. Ich habe etwas mehr integriert, als es die eigentliche Aufgabenstellung verlangt hätte (Namensgebung für Elemente, Löschen/Hinzufügen von Elementen).

BlitzMax: [AUSKLAPPEN]
SuperStrict
Framework brl.basic
Import brl.timer
Import brl.Graphics
Import brl.d3d9max2d

'Const GW:Int=640, GH:Int=480
Const GW:Int=800, GH:Int=600

Graphics GW,GH


Local timer:TTimer=CreateTimer(50)

TIcon.Create "/bin"
TIcon.Create "/root"
TIcon.Create "/usr"

Repeat
Cls

TIcon.updateall

Flip 0
WaitTimer timer
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End


Type TIcon
Const ACTION_MOVE:Int=1
Const ACTION_RENAME:Int=2
Const BOX_X:Int = 100
Const BOX_Y:Int = 80


' asource speichert das Icon, das gerade bearbeitet (verschoben, Name geändert) wird.
' action speichert die Aktion die darauf ausgeführt wird (ACTION_MOVE oder ACTION_RENAME).
' die sind notwendig um zu bestimmen, ob eine Operation auf einem Icon ausgeführt werden
' darf.
' Wenn ich mit einem Icon, das ich gerade verschiebe, über ein anderes fahre, darf nicht
' auf diesem auch die Verschiebeoperation gestartet werden etc.
Global asource:TIcon, action:Int
Global list:TList=New TList, creation:Int

Field name:String
Field x:Int, y:Int

'Neues Icon wird in die Liste integriert.
Function Create(name:String, setx:Int=-1, sety:Int=-1)
Local i:TIcon, ok:Int=0
i=New TIcon
i.name=name
i.checkname
If setx=-1 And sety=-1 Then
i.distribute
Else
i.x=setx;i.y=sety
i.grid
EndIf
list.addlast i
EndFunction

'Schaut, ob der Name schon vorhanden ist und verändert ihn, wenn nötig.
Method checkname()
Local tmpname:String=name, i:TIcon, j:Int=2
Repeat
For i=EachIn list
If i<>Self And i.name=tmpname Then Exit
Next
If i And i<>Self And i.name=tmpname Then
tmpname=name+" ("+j+")"
j:+1
Continue
EndIf
Exit
Forever
name=tmpname
EndMethod


Function updateall()
For Local i:TIcon=EachIn list
i.update
Next

' Wenn keine Operation durchgeführt wird (d.h. asource=Null) und
' die linke Maustaste gehalten wird wird creation erhöht, ansonsten
' auf 0 gesetzt
If asource=Null And MouseDown(MOUSE_LEFT) Then
creation:+1
Else
creation=0
EndIf

' Wenn creation 60 erreicht (nach 60 Schleifendurchläufen/Frames),
' hier etwas mehr als eine Sekunde (siehe Timer)
If creation=60 Then
Create "Neuer Ordner",MouseX(),MouseY()
creation=0

'gehe in Benennungsmodus für Ordner
asource=TIcon(list.last())
action=ACTION_RENAME
EndIf
EndFunction

Function drawgrid()
Local x:Int
SetColor 90,90,90
For x=0 Until GH Step BOX_Y
DrawRect 0,x,GW,1
Next
For x=0 Until GW Step BOX_X
DrawRect x,0,1,GH
Next
SetColor 255,0,0
DrawRect 0,GH-10,GW,10
SetColor 255,255,255
EndFunction

' Ausrichter-Funktion
Method grid()
x=x/BOX_X*BOX_X
y=y/BOX_Y*BOX_Y
EndMethod

Method checkpos:Int(x:Int, y:Int)
For Local i:TIcon=EachIn list
If i<>Self And i.x=x And i.y=y Then Return False
Next
Return True
EndMethod

' Setze Icon an eine Position, die noch nicht vergeben ist
Method distribute()
Local sx:Int, sy:Int
For sy=0 Until GH Step BOX_Y
For sx=0 Until GW Step BOX_X
If checkpos(sx,sy) Then x=sx ; y=sy ; Return
Next
Next
EndMethod

Method update()
Local key:Byte, oldx:Int, oldy:Int, mhl:Int
SetColor 230,230,0
DrawRect x+BOX_X/4,y+BOX_Y/4-8,BOX_X/2,BOX_Y/2
SetColor 160,160,0
DrawRect x+BOX_X/4+2,y+BOX_Y/4-6,BOX_X/2-2,BOX_Y/2-3
SetColor 255,255,0
DrawRect x+BOX_X/4+4,y+BOX_Y/4-1,BOX_X/2-4,BOX_Y/2-7
SetColor 255,255,255
DrawText name,x+BOX_X/2-TextWidth(name)/2,y+BOX_Y-25

If asource=Null And mousein(x,y,BOX_X,BOX_Y) Then
'wenn creation=0 wurde die linke Maustaste noch nicht vorher festgehalten
If MouseDown(MOUSE_LEFT) And creation=0 Then asource=Self;action=ACTION_MOVE
If MouseHit(MOUSE_RIGHT) Then asource=Self;action=ACTION_RENAME
EndIf

If asource=Self Then
Select action
Case ACTION_MOVE
SetColor 130,130,130
DrawRect MouseX()-BOX_X/2,MouseY()-BOX_Y/2,BOX_X,2
DrawRect MouseX()-BOX_X/2,MouseY()-BOX_Y/2,2,BOX_Y
DrawRect MouseX()+BOX_X/2,MouseY()-BOX_Y/2,2,BOX_Y
DrawRect MouseX()-BOX_X/2,MouseY()+BOX_Y/2,BOX_X,2

drawgrid

SetColor 255,255,2555
If Not MouseDown(MOUSE_LEFT) Then
asource=Null
oldx=x ; oldy=y
x=MouseX();y=MouseY()
If y>=GH-10 Then list.remove Self;Return
grid
If Not checkpos(x,y) Then x=oldx ; y=oldy
EndIf
Case ACTION_RENAME
SetColor 0,0,200
DrawRect x+(BOX_X-TextWidth(name))/2-4,y+BOX_Y-25,TextWidth(name)+8,TextHeight(name)
SetColor 255,255,255
DrawText name,x+BOX_X/2-TextWidth(name)/2,y+BOX_Y-25


' blinkender Cursor: Millisecs Mod 500 = Ein Wert aus [0;499] (natürliche Zahlen)
' <250 ist die Hälfte der Werte, daher sollte der Cursor, im Idealfall,
' pro Sekunde zwei Mal an und aus gehen.
' Die Werte sind willkürlich gewählt und können für anderes "Blinkverhalten"
' angepasst werden.

If MilliSecs() Mod 500 <250 Then
DrawRect x+(BOX_X+TextWidth(name))/2+2,y+BOX_Y-24,1,TextHeight(name)-2
EndIf

key=GetChar()

' key=8 : heißt, Backspace gedrückt. Wir löschen das hinterste Zeichen.
' key=13 oder key=10 (je nach OS): Enter wurde gedrückt. Wir beenden die Operation.
' key[<>0] And name.length<12 : wir beschränken die Maximallänge auf 12
If key=8 Then
name=name[..name.length-1]
ElseIf key=13 Or key=10 Or (MouseHit(MOUSE_LEFT) And Not mousein(x,y,BOX_X,BOX_Y)) Then
asource=Null
checkname
ElseIf key And name.length<12 Then
name:+Chr key
EndIf
EndSelect
EndIf
grid
EndMethod
EndType

Function mousein:Int(x:Int, y:Int, w:Int, h:Int)
Local mx:Int=MouseX(), my:Int=MouseY()
Return mx>=x And my>=y And mx<=x+w And my<=y+h
EndFunction


Ich habe einen TIcon-Type, der ein Icon speichert (Name, Position), globale Informationen (das Icon auf dem gerade eine Aktion ausgeführt wird [asource], Die Nummer der Aktion [action], die Liste, [creation] für das Hinzufügen von Icons) und Konstanten (BOX_X und BOX_Y - Größe eines Elements).
Wie die Bewegung/Umbenennung von Icons gehandhabt wird, kann man in der Methode "update()" ablesen.

Schnell noch zur Benützung:
Position ändern - Linke Maustaste + Drag & Drop
Umbenennen - Rechte Maustaste + Klick
Element hinzufügen - Linke Maustaste auf einer nicht belegten Position gedrückt halten
Element entfernen - Linke Maustaste + Drag & Drop + in/unterhalb der roten Markierung loslassen

Edit: Nach Holzchopfs Vorschlägen bearbeitet und ergänzt.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit
  • Zuletzt bearbeitet von Thunder am Mo, Okt 17, 2011 21:34, insgesamt einmal bearbeitet

Holzchopf

Meisterpacker

BeitragMo, Okt 17, 2011 8:53
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMoritz: Sehr gut! Ich denke, bei so wenig und überschaubarem Code kommt man auch mal ohne Kommentare und mit der zusätzlichen Beschreibung zurecht. Mag für den einen oder anderen vielleicht sogar lehrreich sein, alle 17 Zeilen des Codes mal zu analysieren und wäre eine gute Übung.

Thunder: Oha, sehr sehr ausführlich :O Das ist natürlich schön, wen eine Aufgabe so eifrig gelöst wird! Wird den einen oder anderen bestimmt zu etwas inspirieren Wink wenn demnächst lauter Worklogs eröffnet werden, in denen es darum geht, in BlitzMax ein (Fake-)Betriebssystem zu schreiben, weiss ich ja dann wer der schuldige ist Rolling Eyes
Allerdings kann man ein Objekt bei dir packen, wenn man vor dem drüberfahren schon die Maustaste drückt und dann erst den Cursor aufs Objekt bewegt.
Die Vorgehensweise ist zwar (Dank der zusätzlichen Beschreibung) ersichtlich, aber gerade für den Wert der Variable action würde ich für bessere Überschaubarkeit mit Konstanten Arbeiten Wink Und schön wären übrigens ein paar weitere Kommentare, gerade weil du zusätzliche Funktionalität einbringst; wie funktioniert die Namensänderung? wie kommt das Blinken des Cursors zustande? wo wird definiert, wie lange man die Maustaste gedrückt halten muss, um einen neuen Ordner zu erstellen? etc. Das kannst du gerne auch als Tipp direkt an dich auffassen, denn kurze Kommentare stechen auch optisch hervor und erhöhen die Leserlichkeit und Wiederzurechtfindbarkeit eines Codes enorm Rolling Eyes

mfG
Holzchopf
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

Thunder

BeitragMo, Okt 17, 2011 21:38
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für die Vorschläge, habe mich gleich daran gemacht Kommentare zu verfassen Very Happy jetzt gerade habe ich eigentlich gar nicht die Zeit dafür, aber dein Beitrag hat mich motiviert. Ich bin fürs erste hauptsächlich darauf eingegangen, was du angesprochen hast und werde später nochmal über den Code drüberlesen, was vielleicht noch erklärt werden sollte.
Die Sache mit dem Drüberfahren, wenn die Maustaste bereits gedrückt war, habe ich übrigens gelöst Smile
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group