Abstand in Bildergalerie mit Listview

  • VB.NET
  • .NET (FX) 4.0

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von drschef.

    Abstand in Bildergalerie mit Listview

    Ich arbeite unter VB10/W 8.1 und benutze folgenden Code zur Erzeugung einer schachbrettartigen Bildübersicht:

    VB.NET-Quellcode

    1. IL.ImageSize = New Size(180, 135)
    2. IL.ColorDepth = ColorDepth.Depth32Bit
    3. IL.Images.Clear()
    4. For i as integer = 0 To 4
    5. IL.Images.Add(Image.FromFile("c:\!\00 tmp\#D1\pictures\B" & Format(i + 1, "000") & ".jpg"))
    6. Next
    7. LV.View = View.LargeIcon
    8. LV.LargeImageList = IL
    9. LV.LabelWrap = False
    10. LV.ShowGroups = False
    11. For i as integer = 0 To 4
    12. Dim item As ListViewItem = New ListViewItem
    13. item.ImageIndex = i
    14. item.Text = "B" & Format(i + 1, "000")
    15. LV.Items.Add(item)
    16. Next


    Die Bilder werden in einer dynamischen Schachbrettanordnung richtig angezeigt. Zwischen den einzelnen Bildern wird aber sehr viel Platz verschenkt. Recherchen zu dem Problem brachten eine etwas unaktuelle Empfehlung mit API und PostMessage. Eine andere Empfehlung ging in die Richtung mit OwnerDraw. Gibt es auch eine direktere Möglichkeit, um die Bilder bei gleicher Größe mit reduziertem Abstand anzuzeigen. Im Forum habe ich keinen entsprechenden Hinweis gefunden.
    Bilder
    • ExListView.jpg

      71,77 kB, 616×583, 229 mal angesehen
    Wie wäre es mit FlowLayoutPanel oder TableLayoutPanel mit PictureBoxen statt ListView?
    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!
    Warum kein WinAPI (PostMessage und was auch immer sonst)? Das ist eigentlich die klassische und einfachste Methode. Außerdem würde ich dir beim ListView-Control empfehlen, das aus der Library WindowsFormsAero zu nehmen, das sieht besser aus (an den ExplorerStyle angepasst: windowsformsaero.codeplex.com ).
    Danke für die schnellen Stellungnahmen.

    Die Empfehlungen von RodFromGermany betreffend FlowLayoutPanel usw. klingen vielversprechend. Komme aber leider erst heute Nachmittag dazu, mich damit zu befassen.

    Kein WinAPI, weil ich glaubte und hoffte, dass da inzwischen wie in den meisten anderen Fällen entsprechende Eigenschaften des Controls dafür einstehen sollten. Aber auch, weil an mehreren Referenzen, die auf die Methode Bezug nahmen, ein Misserfolg gemeldet wurde, wie berechtigt, habe ich da nicht überprüft. Schließlich wird ein Handle auf den ListView benötigt, wo ich auf Anhieb nicht parat habe, wie man dazu kommt. Danke auch für den Hinweis auf die Library.

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

    Probiert es trotzten mal mit der WinAPI-Methode. Such einfach nach LVM_SETICONSPACING, da solltest du genug finden. Und den Handle kriegst du über DeinListView.Handle .
    1. Nach Empfehlung von RodFromGermany habe ich mit dem FlowLayoutPanel begonnen. Das sieht nicht schlecht aus. Aber was vielleicht etwas umständlich grafisch ergänzt werden muss, ist die Selektion. Oder gibt es da einen simplen Trick?

    2. Nach Empfehlung von nafets3646 habe ich mit der WinAPI und PostMessage mit folgendem Code experimentiert:

    VB.NET-Quellcode

    1. Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
    2. ByVal hwnd As Long, _
    3. ByVal wMsg As Long, _
    4. ByVal wParam As Long, _
    5. ByVal lParam As Long) As Long
    6. Public Function ListViewSetIconSpace(ByVal hwnd As Long, ByVal wSpace As Integer, ByVal hSpace As Integer) As Long
    7. Dim isp As Long = (wSpace And &HFFFF&) Or (hSpace * &H10000) ' MakeLong
    8. ListViewSetIconSpace = PostMessage(hwnd, &H1035&, 0, isp)
    9. End Function
    10. ... ListViewSetIconSpace(CLng(LV.Handle), 200, 155)


    Bei PostMessage kommt ein sehr abstrakter Fehlerkommentar:
    Ein Aufruf an die PInvoke-Funktion "KonturTest!KonturTest.MyListView::PostMessage" hat das Gleichgewicht des Stapels gestört. Wahrscheinlich stimmt die verwaltete PInvoke-Signatur nicht mit der nicht verwalteten Zielsignatur überein. Überprüfen Sie, ob die Aufrufkonvention und die Parameter der PInvoke-Signatur mit der nicht verwalteten Zielsignatur übereinstimmen.

    Da weiß ich nicht mehr weiter.

    Was ist denn daran so schwer?!

    C#-Quellcode

    1. ​const int LVM_SETICONSPACING = 0x1035;
    2. [DllImport("user32.dll")]
    3. public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
    4. public void SetListViewItemPadding(ListView listView, short leftPadding, short topPadding)
    5. {
    6. SendMessage(listView.Handle, LVM_SETICONSPACING, IntPtr.Zero, (IntPtr)(((ushort)leftPadding) | (uint)(topPadding << 16)));
    7. listView.Refresh();
    8. }
    9. private void button1_Click(object sender, EventArgs e)
    10. {
    11. SetListViewItemPadding(listView1, 100, 100);
    12. }
    Danke für den Code. Ich habe den Code nach bestem Wissen überarbeitet und nach VB umgesetzt. Jetzt lautet er:

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Const LVM_SETICONSPACING As Integer = &H1035&
    3. Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
    4. ByVal hwnd As Long, _
    5. ByVal wMsg As Long, _
    6. ByVal wParam As Long, _
    7. ByVal lParam As Long) As Long
    8. Public Sub SetListViewItemPadding(ByVal hwnd As Long, _
    9. ByVal wSpace As Integer, ByVal hSpace As Integer)
    10. Dim isp As Long = (wSpace And &HFFFF&) Or (hSpace * &H10000)
    11. PostMessage(hwnd, LVM_SETICONSPACING, 0, isp)
    12. End Sub
    13. ...
    14. SetListViewItemPadding(CLng(LV.Handle), CShort(100), CShort(100))
    15. ...


    Der Fehlerkommentar ist der gleiche wie gehabt. Scheint doch etwas schwerer zu sein.
    Mal eine Frage: Wie kommt man denn von DllImport()(IntPtr, uint, IntPtr, IntPtr) auf Declare Function (Long, Long, Long, Long) ? Das ist doch Quatsch. Handles sind niemals Long oder so, es sind Zeiger also nimm auch Zeiger bzw. dessen Ersatztyp den IntPtr.

    Gonger96 schrieb:

    Das ist doch Quatsch.
    Nö, das ist VB6-Ranz.
    @drschef VB ist so:

    VB.NET-Quellcode

    1. <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    2. Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    3. End Function
    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!
    Danke für alle Beteiligten und den letzten deutlichen Tip von Gonger96.

    Ja, wie kommt man zu dieser Parameterliste? nafets3646 hatte es ja richtig vorgegeben. Abgeschrieben von
    vbarchiv.net/tipps/tipp_2032-l…aren-icon-abstaenden.html

    Nach dem Hinweis von Gonger96 habe ich im Objektkatalog nachgeschaut, der diesen Hinweis bestätigt. Und siehe da - es funktioniert!

    Damit hat sich der alternative Weg von RodFromGermany unter Verwendung von FlowLayoutPanel erledigt, den ich inzwischen so weit hatte, dass eine Markierung der Zellen möglich war, in denen jeweils ein Panel mit je einer PictureBox und einem Label enthalten war. Wenn es nun auch nicht zur Anwendung kommt, so habe ich doch einiges dazugelernt. Und irgendwann nützt es.

    Um nun noch dem oben erwähnten Link eine funktionstüchtige Variante entgegenzusetzen hier der endgültige Code:

    VB.NET-Quellcode

    1. Imports System.Runtime.InteropServices
    2. Public Class MyListView
    3. Const LVM_SETICONSPACING As Integer = &H1035&
    4. Public Declare Function PostMessage Lib "user32" Alias "PostMessageA" ( _
    5. ByVal hwnd As IntPtr, _
    6. ByVal wMsg As Integer, _
    7. ByVal wParam As IntPtr, _
    8. ByVal lParam As IntPtr) As Long
    9. Public Sub SetListViewItemPadding(ByVal hwnd As Long, _
    10. ByVal wSpace As Integer, ByVal hSpace As Integer)
    11. Dim isp As Long = (wSpace And &HFFFF&) Or (hSpace * &H10000)
    12. PostMessage(LV.Handle, LVM_SETICONSPACING, CType(0, IntPtr), CType(isp, IntPtr))
    13. End Sub
    14. Private Sub Me_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    15. IL.ImageSize = New Size(180, 135)
    16. IL.ColorDepth = ColorDepth.Depth32Bit
    17. IL.Images.Clear()
    18. For i As Integer = 0 To 4
    19. IL.Images.Add(Image.FromFile("c:\!\00 tmp\#D3\pictures\B" & Format(i + 1, "000") & ".jpg"))
    20. Next
    21. LV.View = View.LargeIcon
    22. LV.LargeImageList = IL
    23. LV.LabelWrap = False
    24. LV.ShowGroups = False
    25. SetListViewItemPadding(CLng(LV.Handle), CShort(190), CShort(150))
    26. For i As Integer = 0 To 4
    27. Dim item As ListViewItem = New ListViewItem
    28. item.ImageIndex = i
    29. item.Text = "B" & Format(i + 1, "000")
    30. LV.Items.Add(item)
    31. Next