所需依赖库下载:
#NoEnv #SingleInstance Force SetBatchLines, -1 #Include <Gdip_All> Gui, Add, ListView, Grid AltSubmit x10 y10 r20 w330 h400 vMyListView g列表被点击 hwndHLV, 文件名|拍摄日期| 💬 LV_ModifyCol(1, 150) LV_ModifyCol(2, 130) LV_ModifyCol(3, 30) SetHeaderItemCheckBox(hLV, 1) gui, font, s9, 微软雅黑 gui, Add, Text, x13 y+2 w150 v项目信息 gui, Add, Text, x280 y+-16 w200 v修改信息 gui, font, s12, 微软雅黑 gui, Add, text, x355 y10 w180 vname gui, Add, Pic, y+10 vPic g打开图片 gui, font, s9, 微软雅黑 gui, Add, text, x+0 y165 , 拍摄日期: gui, Add, text, y+5 , 创建日期: gui, Add, text, y+5 , 修改日期: gui, Add, text, c002b55 x420 y165 w130 v拍摄日期 gui, Add, text, c002b55 y+5 w130 v创建日期 gui, Add, text, c002b55 y+5 w130 v修改日期 gui, Add, Radio, Checked0 x355 y260 v指定时间单选 g单选按钮被点击, 指定日期: gui, Add, DateTime, y+5 w180 v指定时间 gui, Add, Radio, Checked0 y+5 v匹配文件名单选 g单选按钮被点击, 匹配文件名: gui, Add, Edit, y+5 w180 v匹配文件名编辑框 Gui, Add, Button, x355 y387 w50 g加载按钮被点击, 打 开 Gui, Add, Button, x+14 w50 +Disabled v移除按钮 g移除按钮被点击, 移 除 Gui, Add, Button, x+14 w50 +Disabled v修改按钮 g修改按钮被点击, 修 改 ImageListID1 := IL_Create(10) ; 创建图像列表, 这样 ListView 才可以显示图标: LV_SetImageList(ImageListID1) ; 关联图像列表到 ListView, 然而它就可以显示图标了: Gui, Show, , 相片拍摄时间修改 Folder := "D:\picture" Gosub, 加载文件 return 加载按钮被点击: Gui +OwnDialogs ; 强制用户解除此对话框后才可以操作主窗口. FileSelectFolder, Folder,, 4, 选择要加载的目录 if not Folder ; 用户取消了对话框. return Else { LV_Delete() Gosub, 加载文件 } Return 加载文件: global 加载文件 := 1 GDIPToken := Gdip_Startup() ; 检查文件夹名称的最后一个字符是否为反斜杠, 对于根目录则会如此, ; 例如 C:\. 如果是, 则移除这个反斜杠以避免之后出现两个反斜杠. LastChar := SubStr(Folder, 0) if (LastChar = "\") Folder := SubStr(Folder, 1, -1) ; 移除尾随的反斜杠. ; 计算 SHFILEINFO 结构需要的缓存大小. sfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340) VarSetCapacity(sfi, sfi_size) ; 获取所选择文件夹中的文件名列表并添加到 ListView: Loop Files, %Folder%\*.* { ; 建立唯一的扩展 ID 以避免变量名中的非法字符, ; 例如破折号. 这种使用唯一 ID 的方法也会执行地更好, ; 因为在数组中查找项目不需要进行搜索循环. SplitPath, A_LoopFileFullPath,, Dir, FileExt ; 获取文件扩展名. If A_LoopFileExt In bmp,jpg,png,tif { ExtID := 0 ; 进行初始化来处理比其他更短的扩展名. Loop 7 ; 限制扩展名为 7 个字符, 这样之后计算的结果才能存放到 64 位值. { ExtChar := SubStr(FileExt, A_Index, 1) if not ExtChar ; 没有更多字符了. break ; 把每个字符与不同的位置进行运算来得到唯一 ID: ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1))) } ; 检查此文件扩展名的图标是否已经在图像列表中. 如果是, ; 可以避免多次调用并极大提高性能, ; 尤其对于包含数以百计文件的文件夹而言: IconNumber := IconArray%ExtID% if not IconNumber ; 此扩展名还没有相应的图标, 所以进行加载. { ; 获取与此文件扩展名关联的高质量小图标: if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "Str", A_LoopFileFullPath , "UInt", 0, "Ptr", &sfi, "UInt", sfi_size, "UInt", 0x101) ; 0x101 为 SHGFI_ICON+SHGFI_SMALLICON IconNumber := 9999999 ; 把它设置到范围外来显示空图标. else ; 成功加载图标. { ; 从结构中提取 hIcon 成员: hIcon := NumGet(sfi, 0) ; 直接添加 HICON 到小图标和大图标列表. ; 下面加上 1 来把返回的索引从基于零转换到基于一: IconNumber := DllCall("ImageList_ReplaceIcon", "Ptr", ImageListID1, "Int", -1, "Ptr", hIcon) + 1 DllCall("DestroyIcon", "Ptr", hIcon) ; 缓存图标来节省内存并提升加载性能: IconArray%ExtID% := IconNumber } } GDIPImage := Gdip_LoadImageFromFile(A_LoopFileLongPath) PropItem := Gdip_GetPropertyItem(GDIPImage, 0x9003) ; ExifDTOrig - Date & time of original Gdip_DisposeImage(GDIPImage) Datetime := PropItem.Value ; 在 ListView 中创建新行并把它和上面的图标编号进行关联: LV_Add("Icon" . IconNumber, A_LoopFileName, Datetime) if (A_Index = 1) 显示图像(A_LoopFileName, A_LoopFileLongPath, datetime) GuiControl,Text, 项目信息, % LV_GetCount() . " 个图像" } } Gdip_Shutdown(GDIPToken) 加载文件 := 0 return 移除按钮被点击: GuiControl, -Redraw, MyListView 起始行 := 0 RowNumber := 0 ; 这会使得首次循环从顶部开始搜索. Loop { RowNumber := LV_GetNext(RowNumber - 1) if !起始行 起始行 := RowNumber if not RowNumber ; 上面返回零, 所以没有更多选择的行了. break LV_Delete(RowNumber) ; 从 ListView 中删除行. } 起始行 := (起始行 > 1) ? 起始行-1 : 起始行 LV_GetText(FileName, 起始行, 1) ; 从首个字段中获取文本. LV_GetText(Datetime, 起始行, 2) Filepath := Dir "\" FileName 显示图像(FileName, FilePath, datetime) GuiControl, +Redraw, MyListView Return 单选按钮被点击: if (A_GuiControl = "匹配文件名单选") { GuiControl,, 指定时间单选 , 0 GuiControl,, 匹配文件名单选 , 1 global 拍摄时间来源 := "匹配文件" GuiControl, Enable, 修改按钮 tooltip % 拍摄时间 } Else { GuiControl,, 指定时间单选 , 1 GuiControl,, 匹配文件名单选 , 0 global 拍摄时间来源 := "指定时间" GuiControl, Enable, 修改按钮 } Gui, Submit, NoHide Return 修改按钮被点击: GuiControl, -Redraw, MyListView Loop % LV_GetCount() LV_Modify(A_Index,,,, "") GuiControl, +Redraw, MyListView Gui, Submit, NoHide GDIPToken := Gdip_Startup() 拍摄时间 := "" global 修改数组 := {} RowNumber := 0 ; 这样使得首次循环从列表的顶部开始搜索. Loop { RowNumber := LV_GetNext(RowNumber) ; 在前一次找到的位置后继续搜索. if not RowNumber ; 上面返回零, 所以选择的行已经都找到了. break LV_GetText(FileName, RowNumber, 1) ; 从首个字段中获取文本. LV_GetText(Datetime, RowNumber, 2) if (拍摄时间来源 = "指定时间") FormatTime, 拍摄时间, %指定时间%, yyyy/MM/dd HH:mm:ss ;yyyy/MM/dd HH:mm:ss Else 拍摄时间 := 匹配文件名(FileName)[1] 修改数组.insert(RowNumber "|" Dir . "\" . FileName "|" Datetime "|" 拍摄时间) } 修改项 := [] for index, element in 修改数组 ; 在大多数情况下建议使用枚举的方式. { 修改项 := StrSplit(element, "|") sCmd := "D:\3m_script\exiftool.exe" . " -P" . " -ModifyDate=" """" 修改项[4] """" . " -DateTimeOriginal=" """" 修改项[4] """" . " -overwrite_original " . 修改项[2] ret:=CmdRet(sCmd) LV_Modify(修改项[1], "Vis") LV_Modify(修改项[1], "-Select") GDIPImage := Gdip_LoadImageFromFile(修改项[2]) PropItem := Gdip_GetPropertyItem(GDIPImage, 0x9003) Gdip_DisposeImage(GDIPImage) Datetime := StrReplace(PropItem.Value, ":") Datetime := StrReplace(Datetime, " ") FormatTime, Datetime, %Datetime%, yyyy/MM/dd HH:mm:ss if (Datetime = 修改项[4]) LV_Modify(修改项[1], , , Datetime, " ✔") } Gdip_Shutdown(GDIPToken) Return 列表被点击: Critical if (A_GuiEvent = "i") ;修改动作会触发 i { 选择 := 0 RowNumber := 0 ; 这样使得首次循环从列表的顶部开始搜索. Loop { RowNumber := LV_GetNext(RowNumber) ; 在前一次找到的位置后继续搜索. if not RowNumber ; 上面返回零, 所以选择的行已经都找到了. break 选择++ } GuiControl,Text, 项目信息, % LV_GetCount() . " 个图像 选择 " 选择 " 个" if (选择 > 0) GuiControl, Enable, 移除按钮 Else GuiControl, Disable, 移除按钮 if (选择 > 0 and 拍摄时间来源 != "") GuiControl, Enable, 修改按钮 Else GuiControl, Disable, 修改按钮 if (LV_GetCount() = 0 and 选择 = 0) { GuiControl,Text, 拍摄日期 GuiControl,Text, 创建日期 GuiControl,Text, 修改日期 GuiControl,, 匹配文件名编辑框 GuiControl,Text, name, 文件名 } } if (A_GuiEvent = "Normal") ; 脚本还可以检查许多其他的可能值. { 选择 := 0 RowNumber := 0 ; 这样使得首次循环从列表的顶部开始搜索. Loop { RowNumber := LV_GetNext(RowNumber) ; 在前一次找到的位置后继续搜索. if not RowNumber ; 上面返回零, 所以选择的行已经都找到了. break 选择++ } if A_EventInfo { LV_GetText(FileName, A_EventInfo, 1) ; 从首个字段中获取文本. LV_GetText(Datetime, A_EventInfo, 2) Filepath := Dir "\" FileName 显示图像(FileName, FilePath, datetime) } } Return 显示图像(Filename, FilePath, datetime) { if !GDIPToken GDIPToken := Gdip_Startup() global picpath := FilePath ; 用于点击图片时 执行Run GuiControl,Text, name, %Filename% pBitmap := Gdip_CreateBitmapFromFile(FilePath) Gdip_GetImageDimensions(pBitmap, Width, Height) Gdip_DisposeImage(pBitmap) if (Width > Height) GuiControl,, Pic, % "*w200 *h-1 " FilePath Else GuiControl,, Pic, % "*w-1 *h150 " FilePath if !datetime 拍摄时间 := "" Else { Datetime := StrReplace(datetime, ":") Datetime := StrReplace(Datetime, " ") FormatTime, 拍摄时间, %Datetime%, yyyy/MM/dd HH:mm } GuiControl,Text, 拍摄日期, %拍摄时间% if (拍摄时间来源 = "匹配文件") { 匹配时间 := 匹配文件名(FileName) if (匹配时间[2] = 0) { Gui, Font, cRed GuiControl, Font, 匹配文件名编辑框 } Else { Gui, Font, c000000 GuiControl, Font, 匹配文件名编辑框 } GuiControl,, 匹配文件名编辑框, % 匹配时间[1] } FileGetTime, 创建时间, %FilePath%, C FileGetTime, 修改时间, %FilePath%, M FormatTime, 创建时间, %创建时间%, yyyy/MM/dd HH:mm FormatTime, 修改时间, %修改时间%, yyyy/MM/dd HH:mm GuiControl,Text, 创建日期, %创建时间% GuiControl,Text, 修改日期, %修改时间% if GDIPToken and (加载文件 = 0) Gdip_Shutdown(GDIPToken) } 匹配文件名(FileName) { 匹配时间 := [] y := SubStr(FileName, 1, 4) m := SubStr(FileName, 6, 2) d := SubStr(FileName, 8, 2) 时间 := y "/" m "/" d " " A_Hour ":" A_Min ":" A_Sec 匹配时间.Insert(时间) if !RegExMatch(时间, "(?:(?:(?:(?:1[8-9]|20)(?:04|08|[2468][048]|[13579][26]))|2000)([-/])02(?:\1)29|(?:(?:1[8-9]|20)\d\d)([-/])(?:(?:0[1-9]|1[0-2])(?:\2)(?:0[1-9]|1[0-9]|2[0-8])|(?:0(?:1|[3-9])|(?:1[0-2]))(?:\2)(?:29|30)|(?:0[13578]|1[02])(?:\2)31))") 匹配时间.Insert(0) Else 匹配时间.Insert(1) Return 匹配时间 } CmdRet(sCmd, callBackFuncObj := "", encoding := "CP0") { static HANDLE_FLAG_INHERIT := 0x00000001, flags := HANDLE_FLAG_INHERIT , STARTF_USESTDHANDLES := 0x100, CREATE_NO_WINDOW := 0x08000000 DllCall("CreatePipe", "PtrP", hPipeRead, "PtrP", hPipeWrite, "Ptr", 0, "UInt", 0) DllCall("SetHandleInformation", "Ptr", hPipeWrite, "UInt", flags, "UInt", HANDLE_FLAG_INHERIT) VarSetCapacity(STARTUPINFO , siSize := A_PtrSize*4 + 4*8 + A_PtrSize*5, 0) NumPut(siSize , STARTUPINFO) NumPut(STARTF_USESTDHANDLES, STARTUPINFO, A_PtrSize*4 + 4*7) NumPut(hPipeWrite , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*3) NumPut(hPipeWrite , STARTUPINFO, A_PtrSize*4 + 4*8 + A_PtrSize*4) VarSetCapacity(PROCESS_INFORMATION, A_PtrSize*2 + 4*2, 0) if !DllCall("CreateProcess", "Ptr", 0, "Str", sCmd, "Ptr", 0, "Ptr", 0, "UInt", true, "UInt", CREATE_NO_WINDOW , "Ptr", 0, "Ptr", 0, "Ptr", &STARTUPINFO, "Ptr", &PROCESS_INFORMATION) { DllCall("CloseHandle", "Ptr", hPipeRead) DllCall("CloseHandle", "Ptr", hPipeWrite) throw Exception("CreateProcess is failed") } DllCall("CloseHandle", "Ptr", hPipeWrite) VarSetCapacity(sTemp, 4096), nSize := 0 while DllCall("ReadFile", "Ptr", hPipeRead, "Ptr", &sTemp, "UInt", 4096, "UIntP", nSize, "UInt", 0) { stdOut := StrGet(&sTemp, nSize, encoding) ;返回当前信息 ; sOutput .= stdOut := StrGet(&sTemp, nSize, encoding) ;返回累积信息 ( callBackFuncObj && callBackFuncObj.Call(stdOut) ) } DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION)) DllCall("CloseHandle", "Ptr", NumGet(PROCESS_INFORMATION, A_PtrSize)) DllCall("CloseHandle", "Ptr", hPipeRead) Return sOutput } 打开图片: run, %picpath% Return GuiClose: ; 当窗口关闭时, 自动退出脚本: ExitApp ;--------test-----------------改变LV样式,被选条目颜色改变 SetExplorerTheme(HCTL) { ; HCTL : handle of a ListView or TreeView control If (DllCall("GetVersion", "UChar") > 5) { VarSetCapacity(ClassName, 1024, 0) If DllCall("GetClassName", "Ptr", HCTL, "Str", ClassName, "Int", 512, "Int") If (ClassName = "SysListView32") || (ClassName = "SysTreeView32") Return !DllCall("UxTheme.dll\SetWindowTheme", "Ptr", HCTL, "WStr", "Explorer", "Ptr", 0) } Return False } ;--------------------------------------------------------- SetHeaderItemCheckBox(hListView, item) { static LVM_GETHEADER := 0x101F, HDS_CHECKBOXES := 0x400, HDI_FORMAT := 0x4 , HDM_FIRST := 0x1200, HDM_GETITEM := HDM_FIRST + (A_IsUnicode ? 3 : 11) , HDM_SETITEM := HDM_GETITEM + 1, HDF_CHECKBOX := 0x40 , HDITEM_SIZE := 4*6 + A_PtrSize*6, fmt_offset := 4*3 + A_PtrSize*2 SendMessage, LVM_GETHEADER,,,, ahk_id %hListView% WinExist("ahk_id" header := ErrorLevel) WinSet, Style, +%HDS_CHECKBOXES% VarSetCapacity(HDITEM, HDITEM_SIZE, 0) NumPut(HDI_FORMAT, HDITEM) SendMessage, HDM_GETITEM, --item, &HDITEM fmt := NumGet(HDITEM, fmt_offset, "Int") NumPut(fmt|HDF_CHECKBOX, HDITEM, fmt_offset) SendMessage, HDM_SETITEM, item, &HDITEM }
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)