Autor Beitrag
hRb
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 169
Erhaltene Danke: 10



BeitragVerfasst: Fr 15.06.18 22:06 
Hallo zusammen,
Unter der Frage "ImageList - schnelle Anzeige" habe ich zum Abschluss ein lauffähiges Beispiel beigefügt. Hier können Dateien durch Ziehen in der Listview-Ansicht verschoben werden. Dies funktioniert, allerdings nur mit Items im sichtbaren Bereich. Bei größerer Distanz muss ich von Hand den Scrollbalken betätigen und in Etappen verschieben.
Ich hätte gerne, dass die Listview-Ansicht automatisch weiter scrollt, wenn das Item an die Grenze gezogen wird. Gibt es hierfür eine "einfache" Lösung?
Danke und Gruß hRb
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 18.06.18 07:43 
- Nachträglich durch die Entwickler-Ecke gelöscht -
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 169
Erhaltene Danke: 10



BeitragVerfasst: Mo 18.06.18 22:43 
Hallo Frühlingsrrolle,
Dein Ansatz ist gut. Ich hatte das DragOver Ereignis ohnehin schon im Programm und nun erweitert (siehe unten). SB_TOP bzw SB_BOTTOM scheiden natürlich aus (Anfang/Ende), aber LINEUP/LINEDOWN erschien mir nach Microsoft-Library geeignet.
Meine Überlegung: DragOver liefert als Y-Parameter die Mausposition. Ich habe mein Listview auf ein Panel gelegt und frage nun die Y-Position ab. Kommt der Wert 50 Pixel an die Grenze wird geschoben. Das funktioniert auch im Prinzig.
Das Problem: das DragOver-Ereignis löst permanent aus und so scrollen die Bilder in Windeseile zum Anfang oder Ende. Ein schön gleichmäßiger ruhiges Scrollen kommt damit nicht zustande. Man müsste also einen Timer einschalten, der das Ereignis (oder die Applikation) 1-2 Sekunden anhält, damit der User die Maus aus der 50 Pixelzone herausbewegen kann - oder etwas ähnliches. Weiterhin wird bei MS erwähnt, dass gleichzeitig der SetScrollPos-Aufruf abgesetzt werden muss, um den Scrollbalken anzupassen! Ein neues Problem, da dies ein 16- oder 32-Bit-Wert ist und nicht mit der Pixelgröße meiner Icons synchrongeht. Ich werde das weiter verfolgen. Vielleicht auch ergänzender Tipp?
Gruß hRb
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.ListView1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := (Sender = Source) ;
  if y<=50
    then SendMessage(ListView1.Handle, WM_VSCROLL, SB_LINEUP{SB_TOP}0else
  if y>=Panel4.Height -50
    then SendMessage(ListView1.Handle, WM_VSCROLL, SB_LINEDOWN, 0);
end;
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 19.06.18 01:57 
- Nachträglich durch die Entwickler-Ecke gelöscht -
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 169
Erhaltene Danke: 10



BeitragVerfasst: Mi 20.06.18 18:00 
Hallo Frühlingsrolle
Zitat:
Da ich aus dem Ganzen nicht herauslesen kann, was genau wohin genau verschoben werden soll, kann ich dir auch keine ausreichende Hilfestellung anbieten.

Ich will es noch mal versuchen. Habe einen Bekannten, der seine Bilder mit Picasa vorführt. Dieses Programm zeigt die Dateien eines Ordners mit wechselnder Überblendtechnik in alphabetischer Reihenfolge. Nicht immer stimmt Aufnahmereihenfolge mit gewünschter Reihenfolge beim Vorführen überein, d.h. die Bilder sollen mit meinem Programm manuel sortiert und anschließend neu numeriert (umbenannt) werden.
Man gehe hier im Forum zur Frage "ImageList - schnelle Anzeige" und lade das von mir zuletzt eingestellte Programm (zip-Datei). Nach Start und Anwahl eines Ordners mit Bildern können diese in die gewünschte Reihenfolge gebracht werden.
1. in der Stringgridtabelle mit Bild auf/ab oder
2. in der Listview-Ansicht mit der Maus verschieben
Dort nun das Problem, dass das Verschieben nur unter den unmittelbar angezeigten Icons möglich ist. Will man über den angezeigten Bereich (nach oben oder nach unten) verschieben, dann geht dies in dieser Version nur, in dem man das verschobene Bildin z.B. in der untersten Zeile ablegt und dann mit der Maus den Schrollbalken so bewegt, dass das Bild oben erscheint. Nun kann es erneut nach unten verschoben werden. Prinzip klar?
Ich möchte jedoch, dass wenn Bild über den unteren Rand hinaus gezogen wird, dass dass der Anzeigebereich zu scrollen beginnt, bis man es an der gewünschten Stelle ablegt (Ziehen mit der Maus sollte ja bekannt sein).
Mit der von mir ausgedachten Methode rollt allerdings alles viel zu schnell. Zwischenzeitlich habe ich bemerkt, dass der im Beispiel genannte Wert von 50 Pixel zu hoch ist. Ein Wert von 1 oder 2 bringt den Scorllvorgang früher "zum Stillstand". Aber sicherlich kennt jeder von Profiprogrammen das sanfte scrollen einer Vorlage.
Ich denke, spätestens wenn man mein Beispiel einmal ausprobiert (bei mehr als 20-30 Dateien in einem Ordner), wird die Schwäche beim Verschieben in der Listview-Ansicht sichtbar.
Gruß hRb
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1192
Erhaltene Danke: 100

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: Do 21.06.18 08:16 
Hey,

dein Ansatz ist schon ganz richtig. In den Mouse und Drag Events hohlst Du dir die Daten zusammen. In einen Timer der einmal die Sekunde oder alle halbe Sekunde feuert kommt dann die eigentliche Verarbeitung.

_________________
Solange keine Zeile Code geschrieben ist, läuft ein Programm immer fehlerfrei.
Ich teste nicht, weil ich Angst habe Fehler zu finden.
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 169
Erhaltene Danke: 10



BeitragVerfasst: Mo 23.07.18 21:44 
Urlaub vorbei,
Zitat:
In einen Timer der einmal die Sekunde oder alle halbe Sekunde feuert kommt dann die eigentliche Verarbeitung.

Die Ermunterung von Sinspin hörte sich gut an. Lösung hat aber einige Zeit gedauert. Meine Probleme waren:
1. zu erkennen, wann ein Item aus der Ansicht herausgezogen wird und
2. wenn Timer einmal gestartet, diesen wieder beenden und zwar nicht nur beim Loslassen der Maus, sondern auch wenn Scrollanfang/ende erreicht wird. Da hatte ich beim Timer längere Zeit "Dauerfeuer". Hier meine Lösung. Alle 50ms wird um 5 Picel gescrollt.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
private
var ScrollWert:longint;
    ScrollEnd :boolean;
 
procedure TForm1.ListView1DragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
const vTime=50// Intervall  50 ms
var ScrollMinPos, ScrollMaxPos, Pos :LongInt;
begin
  Accept := (Sender = Source) ;

  Pos:=GetScrollPos(ListView1.Handle,SB_VERT);
  GetScrollRange(ListView1.Handle,SB_VERT,ScrollMinPos, ScrollMaxPos);
  if ((y<=50and (Pos > ScrollMinPos)) then
    begin
      ScrollWert:=-5;
      Timer2.Interval:=vTime; // 50 ms
      Timer2.Enabled:=true;   // Scrollvorgang starten
      ScrollEnd:=false;
     end
  else
  if ((y>=Listview1.Height-50and (Pos+5 <ScrollMaxPos)) then
    begin
     ScrollWert:=5;
     Timer2.Interval:=vTime; // 50 ms
     Timer2.Enabled:=true;   // Scrollvorgang starten
     ScrollEnd:=false;
    end
   else begin
     ScrollEnd:=true;        // Scrollvorgang abbrechen
     Timer2.Enabled:=false;
   end;
end;

procedure TForm1.ListView1EndDrag(Sender, Target: TObject; X, Y: Integer);
begin
  ScrollEnd:=true; //Scrollvorgang abbrechen
end;

procedure TForm1.Timer2Timer(Sender: TObject);
//Listview1 Scroll nach oben/unten bis Anfang/Ende oder ScrollEnd=true (DragEnd)
var ScrollMinPos, ScrollMaxPos, Pos :LongInt;
begin
  Pos:=GetScrollPos(ListView1.Handle,SB_VERT);  //aktuelle Pos von Scrollbar
  GetScrollRange(ListView1.Handle,SB_VERT,ScrollMinPos, ScrollMaxPos);  //liest ScrollMin-/MaxPos
  if (((Scrollwert>=0and (Pos+5 <= ScrollMaxPos)) or
      ((Scrollwert<=0and (Pos-5 >= ScrollMinPos))) and
       (ScrollEnd=false) then
    begin
 //     Listview1.ScrollBy(0,ScrollWert);   //funktioniert nicht
      ListView1.Scroll(0,ScrollWert);       //funktioniert
      Pos:=GetScrollPos(ListView1.Handle,SB_VERT);
      Listview1.Repaint;
      if  ((pos+5 <=ScrollMinPos) or (pos-5 >=ScrollMaxPos) or (ScrollEnd=true)) 
        then Timer2.Enabled:=false;  //Timer beenden bei Scrollende
    end
    else Timer2.Enabled:=false;
end;

Hinweis1: Die beiden Proceduren muss man eingebettet sehen in meine Anwendung, die ich früher bereit gestellt habe.
Hinweis2 zu den Funktionen GetScrollPos und GetScrollRange: Aus mir nicht nachvollziehbaren Gründen liefert der Wert Pos -wenn der Scrollbalken am Ende steht- nicht den Wert ScrollMaxPos. Hierdurch kann es zu unnötigen Repaint-Aufrufen kommen.