ImagePreview-Explorer mit ScrollArea und Canvas

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Ghosty1967
Beiträge: 203
Registriert: 29.08.2005 13:56
Computerausstattung: Intel i7, 128GB Ram, Win10 Ultimate, PB6.00 Alpha 3
Wohnort: Köln

ImagePreview-Explorer mit ScrollArea und Canvas

Beitrag von Ghosty1967 »

Hallo zusammen... ich habe mich einmal hingesetzt und nach einer Lösung für eine Bildvorschau-Liste wie sie z.B.
bei diversen Bildbearbeitungsprogrammen, Viewern verwendet wird gesucht. Hintergrund ist ein kleines Programm,
welches ich mir (aus reinem Programmierinteresse :mrgreen: ) selber basteln möchte um Metadaten zu diversen
Bildern zu verwalten.
Jetzt habe ich eine erste Lösung in weitestgehender Eigenregie erarbeitet, mit der ich rein optisch wirklich ganz
zufrieden bin. Ich würde mich aber sehr gerne eurer Kritik, eurem Fachwissen stellen um Verbesserungen in z.B.
der Geschwindigkeit zu erzielen.
Im Grunde handelt es sich bei der Bildvorschau um ein ScrollAreaGadget mit jeder Menge CanvasGadgets...geht
das eventuell auch eleganter?
Ach ja, bitte entschuldigt, dass ich den Code nicht auskommentiert habe, aber ich glaube, so kompliziert ist er nicht :)
Ich freue mich auf eure Kommentare und Vorschläge.

..p.s. Im Moment funktioniert erst die Bildvorschau...also links Verzeichnis wählen und rechts Bildvorschauen anzeigen

Hier einmal der Sourcecode...

Code: Alles auswählen

UseGIFImageDecoder()
UseJPEG2000ImageDecoder()
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTGAImageDecoder()
UseTIFFImageDecoder()

Enumeration
  #WIN_INTERFACE
  #TRE_FILELIST
  #LST_FILELIST
  #CON_USERINFO
  #TXT_USERINFO
  #BAR_USERINFO
  #WIN_PREVIEW
  #SCR_PREVIEW
  #TMP_IMAGE
  #FNT_SMALL
  #FNT_ARIAL
EndEnumeration

Structure FILESTRUCTURE
  FILE_IDX.l
  FILENAME.s
  FILEDATE.s
  FILESIZE.l
  IMGWIDTH.l
  IMGHEIGHT.l
  IMGDEPTH.l
EndStructure  
  
Global NewList CONTENT.FILESTRUCTURE()
Global memScrGadgets.l
Global cSelStart.l, cSelEnd.l

;------ PROCEDURES -----
Procedure GetUseableHeight()
  ;Calculate the visible desktop-height without the taskbar-height
  SystemParametersInfo_(#SPI_GETWORKAREA, 0, @DesktopWorkArea.RECT, 0)
  TbH = GetSystemMetrics_(#SM_CYSCREEN) - DesktopWorkArea\Bottom
  ProcedureReturn GetSystemMetrics_(#SM_CYSCREEN) - TbH
EndProcedure  

Procedure.s CutText(text.s, length)
  If StartDrawing(WindowOutput(#WIN_INTERFACE))
    For p = 1 To Len(text)
      If TextWidth(Left(text, p)) > length
        text = Left(text, p - 1): Break
      EndIf
    Next p
    StopDrawing()
  EndIf
  ProcedureReturn text
EndProcedure

Procedure usrTextGadget(gID, x, y, width, height, text.s, textcolor = #PB_Default, backcolor = #PB_Default)
  If gID = #PB_Any
    gID = TextGadget(#PB_Any, x, y, width, height, text)
  Else  
    TextGadget(gID, x, y, width, height, text)
  EndIf
  If textcolor <> #PB_Default: SetGadgetColor(gID, #PB_Gadget_FrontColor, textcolor): EndIf
  If backcolor <> #PB_Default: SetGadgetColor(gID, #PB_Gadget_BackColor , backcolor): EndIf
EndProcedure

Procedure ReadDirectoryContent(path.s)
  PathAddBackslash_(@pfad)
  Protected dir = ExamineDirectory(#PB_Any, path, "*.*")
  If ListSize(CONTENT()) > 0
    ForEach CONTENT()
      If IsGadget(100 + ListIndex(CONTENT())): FreeGadget(100 + ListIndex(CONTENT())): EndIf
    Next
  EndIf  
  ClearList(CONTENT())
  If dir
    While NextDirectoryEntry(dir)
      If DirectoryEntryType(dir) = #PB_DirectoryEntry_File
        If FindString("bmp,jpg,jpeg,tga,tif,tiff,gif,png,ico", LCase(GetExtensionPart(DirectoryEntryName(dir)))) > 0
          fn.s = path + DirectoryEntryName(dir)
          AddElement(CONTENT())
          ;picture-data
          CONTENT()\FILE_IDX = ListIndex(CONTENT())
          CONTENT()\FILENAME = fn
          CONTENT()\FILEDATE = FormatDate("%dd.%mm.%yyyy - %hh:%ii:%ss", GetFileDate(fn, #PB_Date_Modified))
          CONTENT()\FILESIZE = FileSize(fn)
          ;insert specified userdata here
        EndIf
      EndIf
    Wend
    FinishDirectory(dir)
    SortStructuredList(CONTENT(), #PB_Sort_Ascending, OffsetOf(FILESTRUCTURE\FILENAME), TypeOf(FILESTRUCTURE\FILENAME))
  EndIf
EndProcedure

Procedure FillPreviewList()
  If ListSize(CONTENT()) = 0: ProcedureReturn: EndIf
  DisableGadget     (#TRE_FILELIST, #True)
  While WindowEvent(): Wend
  SetGadgetAttribute(#SCR_PREVIEW , #PB_ScrollArea_InnerHeight, 1000)
  SetGadgetAttribute(#BAR_USERINFO, #PB_ProgressBar_Maximum, ListSize(CONTENT()))
  OpenGadgetList(#SCR_PREVIEW)
  xPos = 10: yPos = 10: count.l = 0
  ForEach CONTENT()
    SetGadgetText (#TXT_USERINFO, "Lese Datei " + Str(ListIndex(CONTENT()) + 1) + " von " + Str(ListSize(CONTENT())) + "  " + GetFilePart(CONTENT()\FILENAME) + " (" + Str(CONTENT()\FILESIZE) + " Byte)")
    SetGadgetState(#BAR_USERINFO, ListIndex(CONTENT()) + 1)
    If LoadImage(#TMP_IMAGE, CONTENT()\FILENAME)
      imgW.l = ImageWidth (#TMP_IMAGE)
      imgH.l = ImageHeight(#TMP_IMAGE)
      imgN.s = CutText(GetFilePart(CONTENT()\FILENAME), 150)
      imgD.s = Str(imgW) + "x" + Str(imgH) + " - " + Str(CONTENT()\FILESIZE/1024) + "kB"
      imgT.s = FormatDate("%dd.%mm.%yyyy  %hh:%ii:%ss", GetFileDate(CONTENT()\FILEDATE, #PB_Date_Modified))
      CONTENT()\IMGWIDTH  = ImageWidth (#TMP_IMAGE)
      CONTENT()\IMGHEIGHT = ImageHeight(#TMP_IMAGE)
      CONTENT()\IMGDEPTH  = ImageDepth (#TMP_IMAGE)
      If imgW > imgH
        relWH.f = imgH / imgW: newW  = 120: newH = 120 * relWH
      ElseIf imgH > imgW
        relWH.f = imgW / imgH: newH  = 96: newW = 96 * relWH
      ElseIf imgW = imgH
        newH = 96: newW = 96
      EndIf
      CanvasGadget(100 + ListIndex(CONTENT()), xPos, yPos, 156, 156, #PB_Canvas_DrawFocus)
      If StartDrawing(CanvasOutput(100 + ListIndex(CONTENT())))
        count + 1
        Box(   0,   0, 156, 156, $EAEAEA)
        Box(  14,   4, 128, 104, $FFFFFF)
        Box(   0, 111, 156,  54, $CAEDED)
        Box(   0,   0,  20,  10, $B7B7B7)
        DrawingMode(#PB_2DDrawing_Outlined)
        Box(   0,   0, 156, 156, $ACACAC)
        Box(  14,   4, 128, 104, $B7B7B7)
        DrawImage(ImageID(#TMP_IMAGE),  15 + ((126 - newW) / 2),  8 + ((96 - newH) / 2), newW, newH)
        DrawingFont(FontID(#FNT_SMALL))
        DrawText(   2,   0, RSet(Str(count), 3, "0"), $0, $B7B7B7)
        DrawingFont(FontID(#FNT_ARIAL))
        DrawText((156 - TextWidth(imgN)) / 2, 112, imgN, $0, $CAEDED)
        DrawText((156 - TextWidth(imgD)) / 2, 126, imgD, $0, $CAEDED)
        DrawText((156 - TextWidth(imgT)) / 2, 140, imgT, $0, $CAEDED)
        StopDrawing()
        While WindowEvent(): Wend
      EndIf
    EndIf
    If IsImage(#TMP_IMAGE): FreeImage(#TMP_IMAGE): EndIf
    xPos + 155: If xPos > 478: yPos + 155: xPos = 10: EndIf
  Next
  CloseGadgetList()
  SetGadgetAttribute(#SCR_PREVIEW, #PB_ScrollArea_InnerHeight, 176 + (Int(ListSize(CONTENT()) / 4) * 155))
  DisableGadget     (#TRE_FILELIST, #False)
  SetActiveGadget   (#TRE_FILELIST)
EndProcedure

Procedure DrawImageSelect()
  If cSelEnd = -1: cSelEnd = cSelStart: EndIf
  For canvas = 100 To 100 + ListSize(CONTENT()) - 1  
    If StartDrawing(CanvasOutput(canvas))
      DrawingMode(#PB_2DDrawing_Outlined)
      Box(   0,   0, 156, 156, $B7B7B7)
      Box(   1,   1, 154, 154, $EAEAEA)
      StopDrawing()
    EndIf
  Next
  For canvas = cSelStart To cSelEnd  
    If StartDrawing(CanvasOutput(canvas))
      DrawingMode(#PB_2DDrawing_Outlined)
      Box(   0,   0, 156, 156, $FF0000)
      Box(   1,   1, 154, 154, $FF0000)
      StopDrawing()
    EndIf
  Next
EndProcedure

Procedure DrawPreviewWindow(index)
  SelectElement(CONTENT(), index)
  If LoadImage(#TMP_IMAGE, CONTENT()\FILENAME) = 0
    ProcedureReturn
  EndIf  
  scrW.l = GetSystemMetrics_(#SM_CXSCREEN)
  scrH.l = GetSystemMetrics_(#SM_CYSCREEN)
  imgW.l = ImageWidth (#TMP_IMAGE)
  imgH.l = ImageHeight(#TMP_IMAGE)
  If imgW > imgH
    relWH.f = imgH / imgW: newW  = scrW: newH = newW * relWH
    If newH > scrH: newH = scrH: newW = scrH / relWH: EndIf
  ElseIf imgH > imgW
    relWH.f = imgW / imgH: newH  = scrH: newW = newH * relWH
    If newW > scrW: newW = scrW: newH = scrW / relWH: EndIf
  ElseIf imgW = imgH
    newH = scrH: newW = scrW
  EndIf
  If OpenWindow(#WIN_PREVIEW, 0, 0, scrW, scrH, "", #PB_Window_BorderLess)
    SetWindowColor(#WIN_PREVIEW, $0)
    StickyWindow  (#WIN_PREVIEW, #True)
    If StartDrawing(WindowOutput(#WIN_PREVIEW))
      DrawImage(ImageID(#TMP_IMAGE), (scrW-newW)/ 2, (scrH-newH) / 2, newW, newH)
      DrawingFont(FontID(#FNT_SMALL))
      DrawText(   0,   0, " ESACPE to exit ", $0000FF, $00FFFF)
      StopDrawing()
    EndIf
  EndIf
  DisableWindow(#WIN_INTERFACE, #True)
  SetActiveWindow(#WIN_PREVIEW)
  While WindowEvent(): Wend
  Repeat: Until GetAsyncKeyState_(#VK_ESCAPE)
  CloseWindow(#WIN_PREVIEW)
  DisableWindow(#WIN_INTERFACE, #False)
  SetActiveWindow(#WIN_INTERFACE)
EndProcedure

LoadFont(#FNT_ARIAL, "Arial", 8)
LoadFont(#FNT_SMALL, "Small Fonts", 6)
If OpenWindow(#WIN_INTERFACE, (GetSystemMetrics_(#SM_CXSCREEN) - 988) / 2 , (GetUseableHeight() - 700) / 2, 988, 700, "PhotoMeta", #PB_Window_SystemMenu)
  usrTextgadget       (#PB_Any      ,  10,  10, 100,  14, "Ordner auswählen", $DD0000)
  ExplorerTreeGadget  (#TRE_FILELIST,  10,  25, 300, 665, "", #PB_Explorer_AlwaysShowSelection|#PB_Explorer_AutoSort|#PB_Explorer_NoFiles)
  ;this is a test for a selfmade "listicongadget"
  usrTextgadget       (#PB_Any      , 315,  10, 100,  14, "Dateivorschau", $DD0000)
  ScrollAreaGadget    (#SCR_PREVIEW , 315,  25, 663, 450, 635, 1000, 100, #PB_ScrollArea_Flat)
    SetGadgetColor    (#SCR_PREVIEW , #PB_Gadget_BackColor, $FFFFFF)
  CloseGadgetList()
  ContainerGadget     (#CON_USERINFO, 315, 474, 663,  24, #PB_Container_Flat)
    ;SetGadgetColor    (#CON_USERINFO, #PB_Gadget_BackColor, $FFFFFF)
    ProgressBarGadget (#BAR_USERINFO,   2,   2, 657,   4,   1, 100)
    usrTextGadget     (#TXT_USERINFO,   2,   8, 657,  14, "Information:", $0);, $FFFFFF)
    SetGadgetFont     (#TXT_USERINFO, FontID(#FNT_ARIAL))
  CloseGadgetList()
  usrTextGadget       (#PB_Any      , 315, 503, 100,  14, "Metadaten", $DD0000)
  ContainerGadget     (#PB_Any      , 315, 520, 530, 170, #PB_Container_Flat)
    TextGadget        (#PB_Any      ,  10,  10,  80,  14, "Aufnahmedatum:" , #PB_Text_Right)
    DateGadget        (#PB_Any      ,  95,   7, 115,  20, "%dd.%mm.%yyyy - %hh:%ii", Date(),  #PB_Date_UpDown)
    ButtonImageGadget (#PB_Any      , 500,   6,  22,  22, 0)
    TextGadget        (#PB_Any      ,  10,  33,  80,  14, "Aufnahmeort:" , #PB_Text_Right)
    StringGadget      (#PB_Any      ,  95,  30, 400,  20, "")
    ButtonImageGadget (#PB_Any      , 500,  29,  22,  22, 0)
    TextGadget        (#PB_Any      ,  10,  56,  80,  14, "Personen:"    , #PB_Text_Right)
    StringGadget      (#PB_Any      ,  95,  53, 400,  20, "")
    ButtonImageGadget (#PB_Any      , 500,  52,  22,  22, 0)
    TextGadget        (#PB_Any      ,  10,  79,  80,  14, "Beschreibung:", #PB_Text_Right)
    StringGadget      (#PB_Any      ,  95,  76, 400,  20, "")
    ButtonImageGadget (#PB_Any      , 500,  75,  22,  22, 0)
    TextGadget        (#PB_Any      ,  10, 102,  80,  14, "Bemerkungen:" , #PB_Text_Right)
    EditorGadget      (#PB_Any      ,  95,  99, 400,  35, #PB_Editor_WordWrap)
    ButtonImageGadget (#PB_Any      , 500,  98,  22,  22, 0)
    CheckBoxGadget    (#PB_Any      ,  10, 140, 200,  20, "Metadaten automatisch speichern")
    ButtonGadget      (#PB_Any      , 422, 140, 100,  22, " Speichern", #PB_Button_Left)
  CloseGadgetList()
  usrTextGadget       (#PB_Any      , 850, 503, 100,  14, "Dateimenü", $DD0000)
  ContainerGadget     (#PB_Any      , 850, 520, 128, 170, #PB_Container_Flat)
    ButtonGadget      (#PB_Any      ,  10,  10, 108,  22, " Verschieben", #PB_Button_Left)
  CloseGadgetList()
EndIf

Repeat
  winEvent.l = WaitWindowEvent()
  Select winEvent
    Case #PB_Event_Gadget
      Select EventGadget()
          
        ;click on ExplorerGadget to select a path to read  
        Case #TRE_FILELIST
          If EventType() = #PB_EventType_LeftClick
            If userPath.s <> GetGadgetText(#TRE_FILELIST)
              secs.l = GetTickCount_()
              userPath.s = GetGadgetText(#TRE_FILELIST)
              SetGadgetText(#TXT_USERINFO, "Durchsuche " + Chr(34) + userPath + Chr(34))
              ReadDirectoryContent(userPath)
              FillPreviewList()
              cSelStart.l = -1
              cSelEnd.l   = -1
              seconds.s = StrF((GetTickCount_() - secs)/1000, 2)
              SetGadgetState    (#BAR_USERINFO, 0)
              SetGadgetText     (#TXT_USERINFO, "Verzeichnis mit " + Str(ListSize(CONTENT())) + " Dateien in " + seconds + " Sekunden eingelesen.")
            EndIf  
          EndIf
          
        ;click on an image in the ScrollAreaGadget to select it  
        Case 100 To 100 + ListSize(CONTENT())
          If EventType() = #PB_EventType_LeftDoubleClick
            DrawPreviewWindow(EventGadget() - 100)
          ElseIf EventType() = #PB_EventType_LeftClick
            cSelStart = EventGadget(): cSelEnd = cSelStart: DrawImageSelect()
            SelectElement(CONTENT(), cSelStart - 100)
            SetGadgetText(#TXT_USERINFO, GetFilePart(CONTENT()\FILENAME) + "  -  " + Str(CONTENT()\FILESIZE) + " Byte, " + Str(CONTENT()\IMGWIDTH) + " x " + Str(CONTENT()\IMGHEIGHT) + " Pixel, " + Str(CONTENT()\IMGDEPTH) + "Bit")
          ElseIf EventType() = #PB_EventType_RightClick
            cSelEnd = EventGadget()  : DrawImageSelect()
          EndIf  
          
      EndSelect
  EndSelect    
Until winEvent = #PB_Event_CloseWindow
gnaps
Beiträge: 151
Registriert: 02.09.2008 13:02

Re: ImagePreview-Explorer mit ScrollArea und Canvas

Beitrag von gnaps »

Hi,

ich arbeite seit ca. drei Wochen an einem ähnlichen Projekt.
Bin schon fast fertig.
Das Programm benötigt mein Schwager in seinem Architekturbüro
um die Flut von Bildern zu verwalten.

Ich habe dies auch über eine ähnliche Vorgehensweise probiert, jedoch wegen der Geschwindigkeit dann doch gelassen.
Ich zeige immer nur die nächsten 6 Bilder über 6 "ButtonGadget()" von dem Bild aus das in der Bilderliste angelickt ist da es ja eine vorschau sein soll und nicht eine Bildervorschau vom gesammten.
Geht man davon aus dass 1000 Bilder und mehr in einem Verzeichnis verwaltet werden ist diese Vorschau nicht nutzbar.

Schöne Arbeit aber für manche Vorhaben nicht nutzbar.

Wie speicherst du deine Metadaten ??

ich haue das in eine SQLite Datenbank.
bei diesem Projekt gibt es eine Gewerkeleiste die unendlich lang sein kann. Diese definiert der Nutzer in einer externen Textdatei selber.
Für jedes Gewerk gibt es eine Kategorieenliste die der Nutzer auch in einer externen Textdatei definiert.
Das ganze mache ich damit hier nur geklickt werden muss und nicht immer wiederkehrende Metadaten getippt werden müssen.

Ist das ganze gespeichert kann über die Adresse mit einem bestimmten Projekt über die ganzen Gewerk und Kategorieen suchen.

Hier hatte ich eine Anfrage hier im Forum da ich bei der SQL-Suche ein Problem hatte.

http://forums.purebasic.com/german/view ... 16&t=31166

Also gutes gelingen für dein Vorhaben.

gruß
gnaps
PureBasic Vollversion V 5.71 für Windows - Windows 10 (64)
Antworten