Bildergalerie
Sie wollen mit Excel eine Übersicht der Bilder eines Verzeichnisses
haben?
Schön wäre auch noch eine kleine Vorschau!
Und ein Klick soll das Bild zum Bearbeiten öffnen?
Leider bringen Bilder, die in eine Tabelle eingebettet sind, viel Verdruss.
Jedes Formatieren der Tabelle kann die Position der Bilder ändern. Ein
Ausweg liefern Kommentare, dort kann man als Hintergrund eine Grafik verwenden.
Nun ist es aber mühselig, das von Hand zu machen.
Mein Code startet einen Dialog zur Verzeichnisauswahl. Es ist dabei zu beachten,
dass der Code für XL 97 geschrieben wurde, dort existiert der Operator
AddressOf noch nicht, und muss nachgebildet werden. Bei Versionen > XL97
wird dir ganze Sache etwas einfacher, man muss nur folgende Zeile
'Version = XL97
.lpfnCallback = GetFuncAdress("Startdirectory")
durch diese ersetzen
'Versionen > XL97
.lpfnCallback = AddressOf_ToLong(AddressOf Startdirectory
)
und kann die Funktion GetFuncAdress mitsamt der Deklarationen löschen.
Ist das Verzeichnis ausgewählt, werden alle Unterverzeichnisse nach JPGs
durchsucht. Dann wird die Größe der Bilder ermittelt, um die Seitenverhältnisse
richtig darzustellen. Der Pfad, der Dateiname und die Größe wird
ins Tabellenblatt eingetragen. Ein Hyperlink auf die Datei wird erzeugt, und
der Kommentar mit Bild eingefügt. Da der Pfad für die Grafiken auf
99 Zeichen begrenzt ist, zumindestens bei mir war danach Schluss, werden die
8+3 Datei- und Pfadnamen benutzt. Eine kleine API-Funktion macht das.
Beispieldatei (bilderschau.zip 21 KB)
'########################################################
'# Aufrufen mit
'########################################################
Private Sub cmbParsen_Click()
Bildervorschau
End Sub
'########################################################
'# In ein Modul
'########################################################
Option Explicit
Private Declare Function GetShortPathName Lib "kernel32"
_
Alias "GetShortPathNameA" (ByVal lpszLongPath
As String, _
ByVal lpszShortPath As String, ByVal lBuffer As Long)
As Long
Public Sub Bildervorschau()
Dim myPfad As String, myDatei As String, Zeile As Long
Dim Weite As Double, Höhe As Double, Verhältnis As Double
Dim a As Comment, MyXlliste As New Collection, z
Dim ShortPath As String
myPfad = VBGetFolder("Ordner wählen", "C:\")
If myPfad = "" Then Exit Sub
xlliste myPfad, MyXlliste, "jpg"
With Worksheets("Bilderschau")
.Range("A:D").ClearComments
.Range("A:D").ClearContents
.Range("A1") = "Pfad"
.Range("B1") = "Datei"
.Range("C1") = "Höhe"
.Range("D1") = "Breite"
Zeile = 1
For Each z In MyXlliste
JPEGSize z, Weite, Höhe
ShortPath = String(150, 0)
GetShortPathName z, ShortPath,
150
ShortPath = Left(ShortPath,
InStr(1, ShortPath, Chr(0)) - 1)
Zeile = Zeile + 1
.Cells(Zeile, 1) = z
.Cells(Zeile, 2) = Dir(z)
.Cells(Zeile, 3) = Höhe
.Cells(Zeile, 4) = Weite
Verhältnis = Weite / Höhe
ActiveSheet.Hyperlinks.Add Anchor:=.Cells(Zeile,
2), Address:=ShortPath
Set a = .Cells(Zeile, 1).AddComment
a.Shape.Fill.UserPicture ShortPath
a.Shape.Height = 100
a.Shape.Width = a.Shape.Height
* Verhältnis
Next
End With
End Sub
Private Sub xlliste(Startdir As String, _
ByRef Liste As Collection, Filter As String)
Dim V() As String, zähler As Long
Dim aktVerz As String, Dateiname As String
On Error Resume Next
If Left$(Filter, 1) <> "." Then Filter = "." &
Filter
ReDim V(1 To 100)
If Right$(Startdir, 1) <> "\" Then
'Nachschauen, ob übergebener
Pfad auch einen Backslash enthält.
'Wenn nicht, dann anhängen
Startdir = Startdir & "\"
End If
aktVerz = Startdir
Startdir = Startdir & "*"
Dateiname = Dir$(Startdir, vbDirectory Or vbNormal)
Do While Dateiname <> ""
If Right$(Dateiname, 1) <> "." Then
If GetAttr(aktVerz & Dateiname)
And vbDirectory Then
'wenn
Datei ein Verzeichnis ist
zähler
= zähler + 1
'dann
ein Array mit Verzeichnissen füllen.
If zähler
> UBound(V) Then
ReDim
Preserve V(1 To zähler + 1)
End
If
V(zähler)
= Dateiname
Else
'Handelt
es sich um eine Datei,
If LCase(Right$(Dateiname,
Len(Filter))) = LCase(Filter) Then
'und
entspricht sie noch den Filterbedingungen,
'dann
den Pfad an die Collection Liste hängen.
Liste.Add
aktVerz & Dateiname, aktVerz & Dateiname
End
If
End If
End If
Dateiname = Dir$()
Loop
'Jetzt erst werden die Unterverzeichnisse abgearbeitet,
'weil Dir$ mit Rekursionen nicht klarkommt.
If zähler = 0 Then Exit Sub
ReDim Preserve V(1 To zähler)
For zähler = 1 To UBound(V)
'Jetzt ruft sich diese Sub noch
mal auf.
xlliste aktVerz & V(zähler), Liste, Filter
Next
End Sub
Private Function JPEGSize(ByVal myDatei As String, _
Weite As Double, Höhe As Double) As Boolean
Dim ff As Long, Flag As Byte, c As Long
Dim x As Byte, y As Byte, Zeiger As Long
ff = FreeFile: Zeiger = 1
Open myDatei For Binary Access Read As ff
Get ff, 2, Flag: Get ff, 5, x: Get ff, 6, y
c = CDbl(x) * 256 + CDbl(y)
Zeiger = 6
Do
If (Flag = &HC2) Or (Flag
= &HC0) Then
Get
ff, Zeiger + 4, x: Get ff, , y
Weite
= CDbl(x) * 256 + CDbl(y)
Get
ff, Zeiger + 2, x: Get ff, , y
Höhe
= CDbl(x) * 256 + CDbl(y)
JPEGSize
= True
Exit
Do
End If
Zeiger = Zeiger + c - 2
Get ff, Zeiger + 1, x
If x <> 255 Then Exit
Do
Get ff, , Flag
Zeiger = Zeiger + 2
Get ff, Zeiger + 1, x: Get ff,
, y
c = CLng(x) * 256 + CLng(y)
Zeiger = Zeiger + 2
Loop While Flag <> &HD9
Close
End Function
'########################################################
'# In ein Modul zur Verzeichnisauswahl
'########################################################
Option Explicit
'*************************************
'* AddressOf
'* Ausgeknobelt von K. Getz und M. Kaplan
'*************************************
Private Declare Function GetVbaProjekt _
Lib "vba332.dll" Alias "EbGetExecutingProj" _
(hVBA As Long) As Long
Private Declare Function GetFunktionsnummerString _
Lib "vba332.dll" Alias "TipGetFunctionId" _
(ByVal hVBA As Long, ByVal strFuncNameUnicode _
As String, _
strFunktionsnummer As String) As Long
Private Declare Function GetFunktionsnummerLong _
Lib "vba332.dll" Alias "TipGetLpfnOfFunctionId" _
(ByVal hVBA As Long, ByVal strFunktionsnummer _
As String, hlngFunction As Long) As Long
'*************************************
Private Declare Function FindWindow Lib "user32"
Alias _
"FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function SHBrowseForFolder Lib "shell32"
_
(lpbi As BROWSEINFO) As Long
Private Declare Function SHGetPathFromIDList _
Lib "shell32" (ByVal pidList As Long, _
ByVal lpBuffer As String) As Long
Private Declare Function SetWindowText Lib "user32"
_
Alias "SetWindowTextA" (ByVal hwnd As Long, _
ByVal lpString As String) As Long
Private Type BROWSEINFO
hwndOwner As Long
pidlRoot As Long
pszDisplayName As Long
lpszTitle As Long
ulFlags As Long
lpfnCallback As Long
lParam As Long
iImage As Long
End Type
Private Const RETURNONLYFSDIRS = &H3
Private Const WM_SETTEXT = &HC
Private Const WM_USER = &H400
Private Const BFFM_INITIALIZED = 1
Private Const BFFM_SETSELECTION = (WM_USER + 102)
Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As String) As Long
Private strStartdirectory As String
Private strTitelDialog As String
Private Function Startdirectory(ByVal hwnd As Long,
ByVal uMsg As Long, _
ByVal lp As Long, ByVal pData As Long) As Long
'Diese Funktion wird vom Dialog aufgerufen
If uMsg = BFFM_INITIALIZED Then
'Wenn Dialog initialisiert wird
If Len(strStartdirectory) > 1 Then
'Jetzt wird das Startverzeichnis
gesetzt
SendMessage hwnd, BFFM_SETSELECTION, 1,
strStartdirectory
End If
'Da Titel setzen bei mir unter Win
XP nicht
'Funktioniert, machen wir es hier
SetWindowText hwnd, strTitelDialog
End If
End Function
Public Function VBGetFolder(Titel As String, Startdir
As String) As String
Dim lngListID As Long
Dim strBuffer As String
Dim udtBrowseInfo As BROWSEINFO
'Funktioniert auch ohne vbNullChar
strStartdirectory = Startdir & vbNullChar
'Funktioniert auch ohne vbNullChar
Titel = Titel & vbNullChar
strTitelDialog = Titel
With udtBrowseInfo
.hwndOwner = 0
'Funktioniert bei mir nicht (Win
XP)
'.lpszTitle = StrPtr(Titel)
.ulFlags = RETURNONLYFSDIRS
'Version = XL97
.lpfnCallback = GetFuncAdress("Startdirectory")
'Versionen > XL97
'.lpfnCallback = AddressOf_ToLong(AddressOf Startdirectory
)
End With
lngListID = SHBrowseForFolder(udtBrowseInfo)
If lngListID Then
strBuffer = String(512, 0)
SHGetPathFromIDList lngListID, strBuffer
strBuffer = Left(strBuffer, InStr(strBuffer, Chr(0))
- 1)
VBGetFolder = strBuffer
End If
End Function
Private Function AddressOf_ToLong(ByVal FPointer As
Long) As Long
'Wenn AddressOf in Versionen > XL97 benutzt
wird
'ist diese auf dem ersten Blick unnötige Funktion wichtig
AddressOf_ToLong = FPointer
End Function
'*************************************
'* AddressOf
'* Ausgeknobelt von K. Getz und M. Kaplan
'*************************************
Public Function GetFuncAdress&(strFunktion$)
Dim hVBA&, lngRück&, strFunktionsnummer$
Dim hlngFunction&, strFuncNameUnicode$
strFuncNameUnicode = StrConv(strFunktion, vbUnicode)
GetVbaProjekt hVBA
If hVBA <> 0 Then
lngRück = GetFunktionsnummerString(hVBA, _
strFuncNameUnicode, strFunktionsnummer)
If lngRück = 0 Then
lngRück = GetFunktionsnummerLong(hVBA,
_
strFunktionsnummer,
hlngFunction)
If lngRück
= 0 Then GetFuncAdress = _
hlngFunction
End If
End If
End Function