-- 物件類別模組 # (模組) RegularExpression 正規化 > 使用內建函示庫 CreateObject("vbscript.regexp") 為基礎建立 ## 搜尋符合字串,回傳第一筆結果 ### [版次一] 2024/05/02 > (依序輸入: 原始字串; 正規化語法; 是否忽略大小寫,默認忽略) #### 程式碼 ``` Option Explicit '搜尋符合的字串,回傳結果 Public Function SelectValue(ByVal str_RawString As String, str_Condition As String, Optional bool_IgnoreCase As Boolean = True) As String Dim regEx As Object, matches As Object Dim str_return As String Set regEx = CreateObject("vbscript.regexp") '匹配文字 regEx.Pattern = str_Condition '一次取代 regEx.Global = True '不分大小寫 regEx.IgnoreCase = bool_IgnoreCase '執行匹配 Set matches = regEx.Execute(str_RawString) '返回匹配到的值 If matches.Count > 0 Then str_return = matches(0) Else str_return = "" End If '釋放內存 Set regEx = Nothing Set matches = Nothing '回傳 SelectValue = str_return End Function ``` ### [版次二] 2025/05/15 > 新增進階提取子字串功能,默認不提取,可指定回傳第幾個 > (依序輸入: 原始字串; 正規化語法; 是否忽略大小寫,默認忽略; 提取子字串) #### 程式碼 ``` Option Explicit '搜尋符合的字串,回傳結果 (依序輸入: 原始字串;正規化語法;忽略大小寫) Public Function SelectValue(ByVal str_RawString As String, str_Condition As String, Optional bool_IgnoreCase As Boolean = True, Optional int_subMatch As Integer = -1) As String Dim regEx As Object, matches As Object Dim str_return As String Set regEx = CreateObject("vbscript.regexp") '匹配文字 regEx.Pattern = str_Condition '一次取代 regEx.Global = True '不分大小寫 regEx.IgnoreCase = bool_IgnoreCase '執行匹配 Set matches = regEx.Execute(str_RawString) '返回匹配到的值 If matches.Count > 0 Then '2025/05/15 新增進階撈提取字串 If int_subMatch < 0 Then str_return = matches(0) Else str_return = matches(0).SubMatches(0) End If Else str_return = "" End If '釋放內存 Set regEx = Nothing Set matches = Nothing '回傳 SelectValue = str_return End Function ``` ### 實際範例: 子字串 #### RegularExpression 資料比對 ![image](https://hackmd.io/_uploads/Sy-ItHkOel.png) #### 對應 VBA 呼叫 ``` str_ProcessTime = SelectValue(str_txtFileContext, "Date.Time\s*:\s*(\d{2}.\d{2}.\d{4}\s+\d{2}:\d{2}:\d{2})", True, 0) ----------------------------------------------------------------------------- Lot Number : 30UYGE Operator : NA Magazine : OK W/B-M/C : Customer Number: NA BD DWG NO. : MT6991Z_TCZBHJD-P-H-D Date/Time : 08/05/2025 02:07:51 ----------------------------------------------------------------------------- ``` ## 取代符合字串為空值,回傳剩餘結果 ### [版次一] 2024/05/02 > (依序輸入: 原始字串; 正規化語法; 是否忽略大小寫,默認忽略) #### 程式碼 ``` Option Explicit '取代符合的字串為空字串,回傳剩下值 Public Function ReplaceValue(ByVal str_RawString As String, str_Condition As String, Optional bool_IgnoreCase As Boolean = True) As String Dim regEx As Object, matches As Object Dim str_return As String Set regEx = CreateObject("vbscript.regexp") '匹配文字 regEx.Pattern = str_Condition '一次取代 regEx.Global = True '不分大小寫 regEx.IgnoreCase = bool_IgnoreCase '執行匹配 str_return = regEx.Replace(str_RawString, "") '釋放內存 Set regEx = Nothing Set matches = Nothing '回傳 ReplaceValue = str_return End Function ``` ## 搜尋符合的字串,回傳所有結果 > (依序輸入: 原始字串; 正規化語法; 是否忽略大小寫,默認忽略) #### 程式碼 ``` Option Explicit 'SelectValue的變形,保留所有符合的字串,串再一起回傳 Public Function KeepValue(ByVal str_RawString As String, str_Condition As String, Optional bool_IgnoreCase As Boolean = True) As String Dim regEx As Object, matches As Object Dim str_return As String Dim int_i As Integer Set regEx = CreateObject("vbscript.regexp") str_return = "" '匹配文字 regEx.Pattern = str_Condition '一次取代 regEx.Global = True '不分大小寫 regEx.IgnoreCase = bool_IgnoreCase '執行匹配 Set matches = regEx.Execute(str_RawString) '返回匹配到的值 For int_i = 0 To matches.Count - 1 str_return = str_return & matches(int_i) Next '釋放內存 Set regEx = Nothing Set matches = Nothing '回傳 KeepValue = str_return End Function ``` # (模組) Excel 環境設定 ## 程式執行前,關閉 Excel Function > 並非適用於所有情境,然多數時關閉如螢幕更新,會加快整體運算速度,降低程式出錯率 > 特別在Excel需大量處理幾十萬筆資料時,開啟可大幅降低Excel公式參照異常 #### 程式碼 ``` Sub Close_Excel_fuction_for_efficiency() Application.ScreenUpdating = False '(不)顯示螢幕更新 Application.DisplayStatusBar = False '(不)顯示狀態列 Application.EnableEvents = False '(不)物件觸發事件 Application.DisplayAlerts = False '(不)顯示對話視窗 Application.AskToUpdateLinks = False '(不)顯示更新 Application.Calculation = xlCalculationManual '(不)顯示Excel公式更新 End Sub ``` ## 程式執行完,開啟 Excel Function > 執行前若關閉對應項目,須確保程式結束重新打開功能,避免人工操作Excel畫面無回應 #### 程式碼 ``` Sub Open_Excel_fuction_for_EndVBA() Application.ScreenUpdating = True Application.DisplayStatusBar = True Application.EnableEvents = True Application.DisplayAlerts = True Application.AskToUpdateLinks = True Application.Calculation = xlCalculationAutomatic End Sub ``` # (模組) 動態陣列 ## 一維陣列 ``` '動態一維陣列更新 Sub Reload_DynamicArray(ByRef strList_input() As String, ByVal str_input As String) Dim long_ListSize As Long '初始執行 If strList_input(0) = "" Then strList_input(0) = str_input Exit Sub End If '非第一筆資料執行 long_ListSize = UBound(strList_input) '擴充陣列 ReDim Preserve strList_input(long_ListSize + 1) '將輸入值帶入最後 strList_input(long_ListSize + 1) = str_input End Sub ``` ## 二維/多維陣列 ``` '動態二/多維陣列更新 Sub Reload_DynamicArray2(strArray_input() As String, strList_input() As String) Dim long_ArraySize As Long '初始執行 If strArray_input(0) = "" Then strArray_input(0) = strList_input Exit Sub End If '非第一筆資料執行 long_ArraySize = UBound(strArray_input) '擴充陣列 ReDim Preserve strArray_input(long_ArraySize + 1) '將輸入值帶入最後 strArray_input(long_ArraySize + 1) = strList_input() End Sub ``` # Graphical User Interface 圖形化介面 ## 資料夾選取 ``` Option Explicit 'Create Global Variables Public workbook_Marco As Workbook Public worksheet_Tool As Worksheet Public range_SourceFolderPath As Range Public range_DestinationFolderPath As Range Public str_SourceFolderPath As String Public str_DestinationFolderPath As String Public str_FileNameExtension As String Public int_DeleteTxtLine As Integer '初值建立 Sub Set_Global_Variables() Set workbook_Marco = Workbooks("WaferMapping小工具ver1.0_(Security C).xlsm") Set worksheet_Tool = workbook_Marco.Worksheets("參數設定與檔案執行") With worksheet_Tool .Activate Set range_SourceFolderPath = .Range("D3") Set range_DestinationFolderPath = .Range("D4") str_SourceFolderPath = range_SourceFolderPath str_DestinationFolderPath = range_DestinationFolderPath ' float_CmdDelaySecond = CDbl(.Range("D7")) '單位秒,執行每筆CMD需Delay時間。 根據執行電腦端進行調整 str_FileNameExtension = UCase(.Range("D7")) '防呆,英文強制轉大寫 -> 按MTK去寫程式 int_DeleteTxtLine = CInt(.Range("D8")) End With End Sub Sub Button_SourceFolderSelect() Call Close_Excel_fuction_for_efficiency Call Set_Global_Variables Call FillSheetData_FromSelecFolder(range_SourceFolderPath) Call Open_Excel_fuction_for_EndVBA End Sub Sub Button_DestinationFolderSelect() Call Close_Excel_fuction_for_efficiency Call Set_Global_Variables Call FillSheetData_FromSelecFolder(range_DestinationFolderPath) Call Open_Excel_fuction_for_EndVBA End Sub Private Function SelectFolder() As String On Error GoTo ExceptionHandle Dim bool_RunAction As Boolean bool_RunAction = True Dim object_FolderSelect As FileDialog Dim str_FolderPath As String Set object_FolderSelect = Application.FileDialog(msoFileDialogFolderPicker) '選擇資料夾,則返回 -1,反之回傳 0 str_FolderPath = IIF(object_FolderSelect.Show = -1, object_FolderSelect.SelectedItems(1), "") Set object_FolderSelect = Nothing bool_RunAction = False ExceptionHandle: If bool_RunAction = True Then str_FolderPath = "" SelectFolder = str_FolderPath End Function Private Sub FillSheetData_FromSelecFolder(inputRange As Range) Dim var_temp As Variant Dim str_Data As String str_Data = SelectFolder() If str_Data = "" Then var_temp = MsgBox("未成功選取資料夾! 請重新進行選取!!", vbExclamation, "選取異常") Exit Sub End If inputRange = str_Data End Sub ``` # 建立新資料夾/檔案 ## 說明 > 因為VBA呼叫CMD,會涉及到非同步議題 (CMD還沒複製完檔案,就開始執行下筆VBA) 所以這邊可以改成使用VBA 內建功能 CreateObject("Scripting.FileSystemObject") ## 程式 ``` '同步複製檔案 Private Sub CopyFile(ByVal strFilePath_Source As String, ByVal strFolderPath_Destination As String) Dim object_FSO As Object Dim var_temp As Variant Dim strFilePath_Destination As String Set object_FSO = CreateObject("Scripting.FileSystemObject") strFilePath_Destination = strFolderPath_Destination _ & Right(strFilePath_Source, Len(strFilePath_Source) - InStrRev(strFilePath_Source, "\")) '<防呆> 若原本檔案存在,先刪除 If object_FSO.FileExists(strFilePath_Destination) Then object_FSO.DeleteFile strFilePath_Destination, True '複製檔案 If object_FSO.FolderExists(strFolderPath_Destination) Then object_FSO.CopyFile strFilePath_Source, strFilePath_Destination, True Else '<防呆> ' var_temp = MsgBox("發生異常! " & strFilePath_Destination & " 檔案未建立成功!!", vbExclamation, "執行異常") Err.Raise vbObjectError + 5487, "CopyFile", "未發現檔案路徑" & vbCrLf & strFolderPath_Destination End If Set object_FSO = Nothing End Sub ``` ``` Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) '比較帶入檔案位置,另存新檔案至對應位置 'PS:原本CMD其實可執行,但GPT4建議因CMD為非同步作業,會增加VBA等待不穩定性 (一筆0.5sec,太久)。 故改成VBA內建處理資料夾新增/檔案複製,會比較優選 Private Function SaveCopyNewFile_AndGetPath(ByVal strInput_FilePath As String) As String Dim object_FSO As Object Dim var_temp As Variant Dim str_NewFilePath As String, str_NewFolderPath As String Set object_FSO = CreateObject("Scripting.FileSystemObject") str_NewFilePath = str_DestinationFolderPath & Replace(strInput_FilePath, str_SourceFolderPath, "") str_NewFolderPath = Left(str_NewFilePath, InStrRev(str_NewFilePath, "\") - 1) ' '<測試> ' Debug.Print "cmd.exe /c mkdir """ & str_NewFolderPath & """ && copy /Y """ & strInput_FilePath & """ """ & str_NewFilePath & """" '檢查資料夾是否存在,否則建立 If Not object_FSO.FolderExists(str_NewFolderPath) Then Call CreateFolder(object_FSO, str_NewFolderPath) ' Shell ("cmd.exe /c mkdir """ & str_NewFolderPath & """") ' ' If float_CmdDelaySecond > 0 Then Sleep float_CmdDelaySecond * 1000 '複製檔案 If object_FSO.FolderExists(str_NewFolderPath) Then object_FSO.CopyFile strInput_FilePath, str_NewFilePath, True Else '<防呆> var_temp = MsgBox("發生異常! " & str_NewFilePath & " 檔案未建立成功!!", vbExclamation, "執行異常") End If ' Shell ("cmd.exe /c copy /Y """ & strInput_FilePath & """ """ & str_NewFilePath & """") ' ' If float_CmdDelaySecond > 0 Then Sleep float_CmdDelaySecond * 1000 Set object_FSO = Nothing SaveCopyNewFile_AndGetPath = str_NewFilePath End Function Private Sub CreateFolder(ByRef object_FSO As Object, ByVal str_NewFolderPath As String, Optional ByVal str_OriginFolderPath As String = "") Dim strArray_SplitFolderPath() As String Dim str_tempFolderPath As String Dim int_i As Integer If str_OriginFolderPath = "" Then str_OriginFolderPath = range_DestinationFolderPath str_tempFolderPath = str_OriginFolderPath & "\" strArray_SplitFolderPath = Split(Replace(str_NewFolderPath, str_tempFolderPath, ""), "\") For int_i = LBound(strArray_SplitFolderPath) To UBound(strArray_SplitFolderPath) str_tempFolderPath = str_tempFolderPath & strArray_SplitFolderPath(int_i) & "\" If Not object_FSO.FolderExists(str_tempFolderPath) Then object_FSO.CreateFolder str_tempFolderPath End If Next End Sub ``` # 檔案讀寫 ## 說明 > 使用 VBA 內建功能 CreateObject("ADODB.Stream"),以txt開啟檔案進行編寫 ## 程式 ``` '處理帶入的.MTK檔 (Wafer) ,留著Raw分頁待後續作業 (尚未點選OS圖片生成) Private Sub RunData_ByWaferFile(ByVal str_MtkFilePath As String) ' '<測試> 尋找是否正確找到所有.MTK檔 ' Debug.Print str_MtkFilePath Dim object_ADO As Object Dim str_NewFilePath As String, str_txtFileContext As String '讀檔 Set object_ADO = CreateObject("ADODB.Stream") With object_ADO .Charset = "utf-8" .Open .LoadFromFile (str_MtkFilePath) str_txtFileContext = .ReadText() .Close End With '根據現有格式偵測處理,未符合條件檔案 If Split(str_txtFileContext, vbCrLf)(0) = str_FileNameExtension _ And Right(Split(str_txtFileContext, vbCrLf)(3), 3) = str_FileNameExtension Then '同步另存新檔案 str_NewFilePath = SaveCopyNewFile_AndGetPath(str_MtkFilePath) '<方案1> 基本有四行,第一行、第四行結尾為副檔名 Call OverWriteTxt(object_ADO, str_txtFileContext, str_NewFilePath) Else '<方案3> 每份都包含一個Mapping跟Bin的資訊 If Split(str_txtFileContext, vbCrLf)(0) = "Customer:" & str_FileNameExtension _ And Left(Split(str_txtFileContext, vbCrLf)(1), 8) = "Schedule" Then '同步另存新檔案 str_NewFilePath = SaveCopyNewFile_AndGetPath(str_MtkFilePath) '<方案2> 以上的其他狀況,嘉緯說就不複製了 Else End If End If Set object_ADO = Nothing End Sub '以TXT方式,覆蓋編寫檔案 (From RunData_ByWaferFile) Private Sub OverWriteTxt(ByRef object_ADO As Object, ByVal str_TxtContent As String, ByVal str_NewFilePath As String) Dim str_TxtLines() As String Dim str_newConText As String Dim int_i As Integer ' 處理內容 str_newConText = "" str_TxtLines = Split(str_TxtContent, vbCrLf) For int_i = int_DeleteTxtLine To UBound(str_TxtLines) str_newConText = str_newConText & str_TxtLines(int_i) & vbCrLf Next If Right(str_newConText, 2) = vbCrLf Then str_newConText = Left(str_newConText, Len(str_newConText) - 2) ' 覆寫檔案 With object_ADO .Charset = "utf-8" .Type = 2 .Open .WriteText str_newConText .SaveToFile str_NewFilePath, 2 .Close End With End Sub ``` # 多層資料夾搜尋 ## 說明 > 因為VBA使用Dir(),僅能搜尋單層資料夾 故使用 VBA 內建功能 CreateObject("Scripting.FileSystemObject"),搭配進行遞迴搜尋 ## 程式 ``` '取得工作頁來源資料夾,帶入遞迴遍尋 (Call Search_SubFolder) Private Sub Search_rootFolder(str_SourcePath As String) Dim object_FileSystem As Object, object_rootFolder As Object Set object_FileSystem = CreateObject("Scripting.FileSystemObject") '匯入工作頁來源資料夾 Set object_rootFolder = object_FileSystem.GetFolder(str_SourcePath) '遍尋來源資料夾底下,所有.MTK檔 Call Search_SubFolder(object_rootFolder) Set object_rootFolder = Nothing Set object_FileSystem = Nothing End Sub '遞迴,遍尋每個資料夾,將符合.MTK檔帶入搜尋 (Call Search_MtkFile) Private Sub Search_SubFolder(object_nodeFolder As Object) Dim object_subFolder As Object For Each object_subFolder In object_nodeFolder.subfolders '如果子資料夾底下還有資料夾,繼續遞迴遍尋 If object_subFolder.subfolders.Count > 0 Then Call Search_SubFolder(object_subFolder) '反之,將該子資料夾,拋去偵測 Else Call Search_MtkFile(object_subFolder) End If Next object_subFolder '另外自己當下這層資料夾,也可能存在相應檔案,也須帶入偵測處理 Call Search_MtkFile(object_nodeFolder) End Sub '搜尋資料夾底下的.MTK檔,將檔案帶入正規化處理 (Call RunData_ByWaferFile) Private Sub Search_MtkFile(object_nodeFolder As Object) Dim var_temp As Variant Dim strList_MtkFilePath() As String Dim str_nodeFolder As String, str_temp As String, str_FileNameExtension_ForReg As String ReDim strList_MtkFilePath(0) str_nodeFolder = object_nodeFolder.Path & "\" str_FileNameExtension_ForReg = "." & UCase(str_FileNameExtension) & "|." & LCase(str_FileNameExtension) ' ".MTK|.mtk" '遍尋是否存在.MTK檔,符合檔案拋到一維陣列儲存 (strList_MtkFilePath) str_temp = Dir(str_nodeFolder) Do While str_temp <> "" If RegularExpression.SelectValue(str_temp, str_FileNameExtension_ForReg) <> "" Then Call Reload_DynamicArray(strList_MtkFilePath, str_nodeFolder & str_temp) str_temp = Dir() Loop '如果找到.MTK檔,就抓去處理 (Call RunData_ByWaferFile) For Each var_temp In strList_MtkFilePath If var_temp <> "" Then Call RunData_ByWaferFile(var_temp) Next End Sub ``` # Notes 寄信 ## Main ``` Private Sub function_Note() Dim Note As New class_Note Note.Setting_To = Array("WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE") Note.Setting_CC = Array("WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE") ' Note.Setting_BCC = Array("WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE") Note.Setting_Subject = "測試 Test" ' Note.Setting_SecurityLevel = "C" Note.Setting ' Note.Show_NoteSet Note.Add_Entity "Content", "</h2><p><font face=""微軟正黑體"", size=""3"">Image</font></p><img src=""cid:TestImage.jpg"" alt=""<圖片遺失!!>""><p>this is Test from VBA Send Notes</p><p><br>Thanks.</p><br>" Note.Add_Entity "Image", "", "D:\ASEKH\K17805\VBA\(Test)自主練習\DownloadData\TestImage.jpg" Note.Add_Entity "File", "", "D:\ASEKH\K17805\VBA\(Test)自主練習\DownloadData\Rowdata_(Security C).xlsx" Note.Run Note.Clear End Sub ``` ## clase_Note ``` '<備註> ' 1. 範例: ' Dim Note As New class_Note ' Note.Setting_To = Array("WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE") ' Note.Setting_CC = Array("WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE") '' Note.Setting_BCC = Array("WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE", "WeiCheng Lee/ASEK/ASE@ASE") ' Note.Setting_Subject = "測試 Test" '' Note.Setting_SecurityLevel = "C" ' Note.Setting '' Note.Show_NoteSet ' Note.Add_Entity "Content", "</h2><p><font face=""微軟正黑體"", size=""3"">Image</font></p><img src=""cid:TestImage.jpg"" alt=""<圖片遺失!!>""><p>this is Test from VBA Send Notes</p><p><br>Thanks.</p><br>" ' Note.Add_Entity "Image", "", "D:\ASEKH\K17805\VBA\(Test)自主練習\DownloadData\TestImage.jpg" ' Note.Add_Entity "File", "", "D:\ASEKH\K17805\VBA\(Test)自主練習\DownloadData\Rowdata_(Security C).xlsx" ' Note.Run ' Note.Clear ' ' 2. 需搭配 class_Note2 類別模組使用 ' ' 3. 三種用法:(1) "Content" -> 輸入Html語法 (指定Image資訊) ' (2) "Image" -> 給檔案名稱即可 ' (3) "File" -> 給檔案名稱即可,若跳出後綴名需擴充,再額外寫 (目前僅實裝常用檔案格式) Option Explicit Dim array_To As Variant, array_CC As Variant, array_BCC As Variant Dim str_Subject As String, str_SecurityLevel As String Dim object_Notes As Object, object_Stream As Object, object_document As Object, object_NotesSession As Object Dim object_MimeEntity As Object, object_Prefix As Object, object_Suffix As Object, object_Entity As Object Dim class_listFile As New class_Note2 '檔案格式對應MIME表 '輸入/更改參值 (檔案來源, SQL指令) Public Property Let Setting_To(inputArray_To As Variant) array_To = inputArray_To End Property Public Property Let Setting_CC(inputArray_CC As Variant) array_CC = inputArray_CC End Property Public Property Let Setting_BCC(inputArray_BCC As Variant) array_BCC = inputArray_BCC End Property Public Property Let Setting_Subject(inputStr_Subject As String) str_Subject = inputStr_Subject End Property Public Property Let Setting_SecurityLevel(inputStr_SecurityLevel As String) str_SecurityLevel = inputStr_SecurityLevel End Property Public Sub Setting() '先設定格式對應表 ' class_listFile.Setting_suffix = Array(".csv", ".doc", ".docx", ".htm", ".html", ".jpeg", ".jpg", ".js", ".json", ".jsonld", ".png", ".ppt", ".pptx", ".rar", ".svg", ".txt", ".xls", ".xlsx", ".zip", ".7z") class_listFile.Setting_suffix = Array("csv", "doc", "docx", "htm", "html", "jpeg", "jpg", "js", "json", "jsonld", "png", "ppt", "pptx", "rar", "svg", "txt", "xls", "xlsx", "zip", "7z") class_listFile.Setting_MIME = Array("text/csv", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "text/html", "text/html", "image/jpeg", "image/jpeg", "text/javascript", "application/json", "application/ld+json", "image/png", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.rar", "image/svg+xml", "text/plain", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/zip", "application/x-7z-compressed") Set object_Notes = CreateObject("Notes.NotesSession") '指定資料庫 Set object_Stream = object_Notes.CREATESTREAM '新增文件 Set object_document = object_Notes.CURRENTDATABASE.createDocument '不將內文轉成 RichText形式 object_Notes.CONVERTMIME = False Set object_NotesSession = CreateObject("Notes.NotesSession") With object_document '收件人(to) If IsEmpty(array_To) Then array_To = Array("") MsgBox "請先填入收件人!!" Exit Sub End If .SendTo = array_To '收件人(CC) If IsEmpty(array_CC) Then array_CC = Array("") End If .CopyTo = array_CC '收件人(BCC) If IsEmpty(array_BCC) Then array_BCC = Array("") End If .BlindCopyTo = array_BCC '信件標題 If str_Subject = "" Then MsgBox "請先填入信件標題!!" Exit Sub End If .Subject = str_Subject '機密等級(Security A/B/C/D) If str_SecurityLevel = "" Then str_SecurityLevel = "C" End If .SecurityLevel = str_SecurityLevel '格式指定 .form = "Memo" End With Set object_MimeEntity = object_document.CREATEMIMEENTITY 'ASE Notes前綴 Set object_Prefix = object_MimeEntity.CREATECHILDENTITY With object_Prefix object_Stream.WRITETEXT _ "<html><head><p><font size=""3"">** Security C ** <br></p><br></head>" .SETCONTENTFROMTEXT object_Stream, "text/HTML;charset=UTF-8", 1725 object_Stream.Close object_Stream.TRUNCATE End With End Sub Public Sub Show_NoteSet() MsgBox "To : " & Join(array_To, ", ") & vbCrLf & vbCrLf _ & "CC : " & Join(array_CC, ", ") & vbCrLf & vbCrLf _ & "BCC : " & Join(array_BCC, ", ") & vbCrLf & vbCrLf _ & "Subject : " & str_Subject & vbCrLf _ & "SecurityLevel : " & str_SecurityLevel _ , vbInformation, "寄信資訊設定清單" ' MsgBox "To : " & Join(array_To, vbCrLf & " ") & vbCrLf & vbCrLf _ ' & "CC : " & Join(array_CC, vbCrLf & " ") & vbCrLf & vbCrLf _ ' & "BCC : " & Join(array_BCC, vbCrLf & " ") & vbCrLf & vbCrLf _ ' & "Subject : " & str_Subject & vbCrLf _ ' & "SecurityLevel : " & str_SecurityLevel _ ' , vbInformation, "寄信資訊設定清單" End Sub Public Sub Add_Entity(str_EntityType As String, Optional str_content As String = "", Optional str_Source As String = "") 'str_EntityType,像bool的選項輸入可能? Dim str_fileName As String, str_MIME As String Set object_Entity = object_MimeEntity.CREATECHILDENTITY With object_Entity Select Case str_EntityType Case "Content" object_Stream.WRITETEXT _ "<body>" & str_content & "</body>" .SETCONTENTFROMTEXT object_Stream, "text/HTML;charset=UTF-8", 1725 object_Stream.Close object_Stream.TRUNCATE Case "Image" '<防呆>偵錯,未輸入變數則提醒 (終止程式運行) If str_Source = "" Then MsgBox "!!請確認Add_Entity呼叫變數是否有誤!!" End End If str_fileName = Mid(str_Source, InStrRev(str_Source, "\") + 1) .CREATEHEADER("Content-ID").SETHEADERVAL str_fileName object_Stream.Open str_Source, "binary" .SETCONTENTFROMBYTES object_Stream, "image/jpeg;name=" & str_fileName, 1730 object_Stream.Close object_Stream.TRUNCATE Case "File" '<防呆>偵錯,未輸入變數則提醒 (終止程式運行) If str_Source = "" Then MsgBox "!!請確認 Add_Entity 呼叫變數是否有誤!!" End End If str_fileName = Mid(str_Source, InStrRev(str_Source, "\") + 1) ' str_MIME = class_listFile.Getting_MIME_Value("B") If InStr(str_fileName, ".") > 0 Then str_MIME = class_listFile.Getting_MIME_Value(Mid(str_Source, InStrRev(str_Source, ".") + 1)) Else '<防呆>偵錯,使用者檔案輸入錯誤 (終止程式運行) MsgBox "!!請確認輸入 str_fileName 檔案名稱是否有誤!!" End End If '<防呆>需再擴充檔案格式(後綴名) (終止程式運行) If str_MIME = "" Then MsgBox "!!請聯絡開發人員,擴充檔案格式 " & Mid(str_Source, InStrRev(str_Source, ".") + 1) & "!!" End End If ' Dim int_i As Integer ' For int_i = 0 To class_listFile.Getting_suffix_ArrayNumber ' If LCase(Split(str_fileName, ".")(-1)) = class_listFile.Getting_suffix_Value( Setting_suffix(int_i) Then ' str_MIME = Setting_MIME(int_i) ' Exit For ' End If ' Next .CREATEHEADER("Content-ID").SETHEADERVAL str_fileName object_Stream.Open str_Source, "binary" .SETCONTENTFROMBYTES object_Stream, str_MIME & ";name=" & str_fileName, 1730 object_Stream.Close object_Stream.TRUNCATE Case Else Set object_Entity = Nothing Exit Sub End Select End With Set object_Entity = Nothing End Sub Public Sub Run() 'ASE Notes後綴 Set object_Suffix = object_MimeEntity.CREATECHILDENTITY With object_Suffix object_Stream.WRITETEXT _ "<foot><p><font face=""Default Monospace"", size=""2""><br><br>----- ASE Confidentiality Notice -----<br>The preceding message (including any attachments) contains proprietary information that may be confidential, privileged, or constitute non-public information. It is to be read and used solely by the intended recipient(s) or <br>conveyed only to the designated recipient(s). If you are not an intended recipient of this message, please notify the author or sender immediately either by replying to this message or by telephone at 886-7-3617131 and delete <br>this message (including any attachments hereto) immediately from your system. You should not read ,retain, disseminate, distribute, copy or use this message in whole or in part for any purpose, not disclose all or any part of <br>its content to any other person.<br>----- ASE Confidentiality Notice -----</p></foot></html>" .SETCONTENTFROMTEXT object_Stream, "text/HTML;charset=UTF-8", 1725 object_Stream.Close object_Stream.TRUNCATE End With '存取郵件 object_document.SAVEMESSAGEONSEND = True '忽略錯誤 On Error Resume Next '寄出Mail object_document.send False End Sub '結束時釋放記憶體 Public Sub Clear() Set object_Notes = Nothing Set object_Stream = Nothing Set object_document = Nothing Set object_NotesSession = Nothing Set object_MimeEntity = Nothing Set object_Prefix = Nothing Set object_Suffix = Nothing Set object_Entity = Nothing End Sub '更新紀錄 '初版:2024/05/02 By WeiCheng_Lee ``` ## class_Note2 ``` '<備註> ' 搭配 class_Note 使用 Option Explicit Dim str_suffix As Variant, str_MIME As Variant '輸入/更改參值 (檔案來源, SQL指令) <註1> Public Property Let Setting_suffix(input_suffix As Variant) str_suffix = input_suffix End Property Public Property Let Setting_MIME(input_MIME As Variant) str_MIME = input_MIME End Property ''取得陣列大小 (目前有多少值) 'Public Function Getting_suffix_ArrayNumber() As Integer ' Getting_ArrayNumber = UBound(str_suffix) 'End Function ' ''輸入數字(陣列第幾個值),取得對應Array值 'Public Function Getting_suffix_Value(int_input As Integer) As String ' Getting_suffix_Value = str_suffix(int_input) 'End Function 'Public Function Getting_MIME_Value(int_input As Integer) As String ' Getting_MIME_Value = str_MIME(int_input) 'End Function '輸入suffix對應值,參照MIME Array對應值 Public Function Getting_MIME_Value(inputStr_suffix As String) As String Dim int_i As Integer For int_i = 0 To UBound(str_suffix) If str_suffix(int_i) = inputStr_suffix Then Getting_MIME_Value = str_MIME(int_i) Exit Function End If Next '若找不到,回傳空值 Getting_MIME_Value = "" End Function '更新紀錄 '初版:2024/05/02 By WeiCheng_Lee ``` ## Other 類型研究 ``` Option Explicit Dim source_workbook As Workbook Dim source_worksheet As Worksheet Sub Main_Notes() '(無關)資料來源 Set source_workbook = Workbooks.Open(ThisWorkbook.Path & "\DownloadData\Rowdata_(Security C).csv") Set source_worksheet = source_workbook.Sheets("Rowdata_(Security C)") '1. 文字 + 附圖 ,會卡UI控制 ' Call WorkspaceUI '2. 文字 + 附檔(圖片or文件檔都可) ,可繞過UI卡控 <- 這個好像沒有公司信件的格式,不知道為啥 ' Call RichText '3. 利用MIME傳送,功能齊全但較為複雜,可繞過UI卡控 Call Html source_workbook.Close End Sub Private Sub WorkspaceUI() Dim object_Notes As Object Set object_Notes = CreateObject("Notes.NotesUIWorkspace") '寄件人 Dim object_document As Object Set object_document = object_Notes.COMPOSEDOCUMENT("TWKHM13/ASE", "mail7\WeiCheng_Lee.nsf", "Memo") '收件人(To) Call object_document.FIELDSETTEXT("EnterSendTo", "WeiCheng Lee/ASEK/ASE@ASE") '收件人(CC) Call object_document.FIELDSETTEXT("EnterCopyTo", "WeiCheng Lee/ASEK/ASE@ASE") '信件標題 Call object_document.FIELDSETTEXT("Subject", "VBA Test (Security C)") '機密等級(Security A/B/C/D) Call object_document.FIELDSETTEXT("SecurityLevel", "C") '內文 Call object_document.GOTOFIELD("Body") '輸入文字 Call object_document.InsertText(vbCrLf & vbCrLf & vbCrLf & "<WorkspaceUI>" & vbCrLf & vbCrLf & vbCrLf & vbCrLf) '附圖 '1. 貼圖 '(無關)這邊先去Excel撈圖 With source_worksheet .Activate '1.從Excel抓取Cells範圍當圖片 range(.Cells(1, 1), .Cells(5, 16)).Copy Application.Wait (DateAdd("s", 1, Now)) End With '把圖貼上 Call object_document.Paste '2. 匯入已存好得圖 ' Call object_document.import("JPEG Image", 圖像路徑) '寄出Mail Call object_document.send '關閉Mail視窗 Call object_document.Close(-1) End Sub Private Sub RichText() Dim object_Notes As Object Set object_Notes = CreateObject("Notes.NotesSession") '指定資料庫 Dim object_Database As Object Set object_Database = object_Notes.CURRENTDATABASE '新增文件 Dim object_document As Object Set object_document = object_Database.createDocument With object_document '收件人(to) .SendTo = Array("WeiCheng Lee/ASEK/ASE@ASE") '收件人(CC) .CopyTo = Array("WeiCheng Lee/ASEK/ASE@ASE") '信件標題 .Subject = "VBA Test (Security C)" '機密等級(Security A/B/C/D) .SecurityLevel = "C" '不知道有沒有效 '格式指定 .form = "Memo" '寄件備份 .SAVEMESSAGEONSEND = True End With '設定內文 '物件 Dim object_contextItem As Object Set object_contextItem = object_document.CREATERICHTEXTITEM("Body") '文字 Call object_contextItem.APPENDTEXT("RichText") '換行 Call object_contextItem.ADDNEWLINE(2) '附件 Call object_contextItem.EMBEDOBJECT(1454, "", source_workbook.Path & "\Rowdata_(Security C).csv") '參考:https://help.hcltechsw.com/dom_designer/9.0.1/appdev/H_EMBEDOBJECT_METHOD.html '寄出Mail Call object_document.send(False) End Sub Private Sub Html() Dim object_Notes As Object Set object_Notes = CreateObject("Notes.NotesSession") '指定資料庫 Dim object_Stream As Object Set object_Stream = object_Notes.CREATESTREAM '新增文件 Dim object_document As Object Set object_document = object_Notes.CURRENTDATABASE.createDocument '不將內文轉成 RichText形式 object_Notes.CONVERTMIME = False With object_document '收件人(to) .SendTo = Array("WeiCheng Lee/ASEK/ASE@ASE") '收件人(CC) .CopyTo = Array("WeiCheng Lee/ASEK/ASE@ASE") '信件標題 .Subject = "VBA Test (Security C)" '機密等級(Security A/B/C/D) .SecurityLevel = "C" '格式指定 .form = "Memo" End With '物件 Dim object_MimeEntity As Object Set object_MimeEntity = object_document.CREATEMIMEENTITY '設定內文 '寫Html(內文) Dim object_ContentEntity As Object Set object_ContentEntity = object_MimeEntity.CREATECHILDENTITY With object_ContentEntity object_Stream.WRITETEXT _ "<html><head><p><font size=""3"">** Security C ** <br></p><br></head>" & _ "<body><h2>Html<br></h2><p><font face=""微軟正黑體"", size=""3"">Image</font></p><img src=""cid:TestImage.jpg"" alt=""<圖片遺失!!>""><p>this is Test from VBA Send Notes</p><p><br>Thanks.</p><br><br></body>" .SETCONTENTFROMTEXT object_Stream, "text/HTML;charset=UTF-8", 1725 object_Stream.Close object_Stream.TRUNCATE End With '圖片物件 Dim object_ImageEntity As Object Set object_ImageEntity = object_MimeEntity.CREATECHILDENTITY '給圖片的存放路徑 & 名子 With object_ImageEntity .CREATEHEADER("Content-ID").SETHEADERVAL "TestImage.jpg" object_Stream.Open ThisWorkbook.Path & "\DownloadData\TestImage.jpg", "binary" .SETCONTENTFROMBYTES object_Stream, "image/jpeg;name=""TestImage.jpg""", 1730 '<參考2><參考3> object_Stream.Close object_Stream.TRUNCATE End With '附件 '跟圖片物件一樣,每一個附件都要在 object_MimeEntity 底下,建立一個子項目(childEntity)。然後在定義其參考等設定 Dim object_FileEntity As Object Set object_FileEntity = object_MimeEntity.CREATECHILDENTITY With object_FileEntity .CREATEHEADER("Content-ID").SETHEADERVAL "Rowdata_(Security C).xlsx" object_Stream.Open ThisWorkbook.Path & "\DownloadData\Rowdata_(Security C).xlsx", "binary" .SETCONTENTFROMBYTES object_Stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;name=""Rowdata_(Security C).xlsx""", 1730 object_Stream.Close object_Stream.TRUNCATE End With 'ASE Notes後綴 Dim object_Suffix As Object Set object_Suffix = object_MimeEntity.CREATECHILDENTITY With object_Suffix object_Stream.WRITETEXT _ "<foot><br><br><p><font face=""Default Monospace"", size=""2"">WeiCheng Lee<br>ASE Group<br>Tel : 886-7-3617131 # 87979<br>Email Address : WeiCheng_Lee@aseglobal.com</p>" & _ "<p><font face=""Default Monospace"", size=""2"">----- ASE Confidentiality Notice -----<br>The preceding message (including any attachments) contains proprietary information that may be confidential, privileged, or constitute non-public information. It is to be read and used solely by the intended recipient(s) or <br>conveyed only to the designated recipient(s). If you are not an intended recipient of this message, please notify the author or sender immediately either by replying to this message or by telephone at 886-7-3617131 and delete <br>this message (including any attachments hereto) immediately from your system. You should not read ,retain, disseminate, distribute, copy or use this message in whole or in part for any purpose, not disclose all or any part of <br>its content to any other person.<br>----- ASE Confidentiality Notice -----</p></foot></html>" .SETCONTENTFROMTEXT object_Stream, "text/HTML;charset=UTF-8", 1725 object_Stream.Close object_Stream.TRUNCATE End With '存取郵件 object_document.SAVEMESSAGEONSEND = True '忽略錯誤 On Error Resume Next '寄出Mail object_document.send False End Sub ``` # PPT ``` Option Explicit Sub Main_PPT() '(無關)資料來源 Dim source_workbook As Workbook Set source_workbook = Workbooks.Open(ThisWorkbook.Path & "\DownloadData\Rowdata_(Security C).csv") Dim source_worksheet As Worksheet Set source_worksheet = source_workbook.Sheets("Rowdata_(Security C)") 'PPT Main 'include 函式庫 , Create PPT file Dim object_PPT As Object ' Dim object_PPT As Powerpoint.Application Set object_PPT = CreateObject("Powerpoint.Application") Dim presentation_PPT As Object ' Dim presentation_PPT As Presentation 'presentation VS presentations Set presentation_PPT = object_PPT.Presentations.Add Dim slide_PPT As Object ' Dim Slide_PPT As Slide Set slide_PPT = presentation_PPT.Slides.Add(1, ppLayoutBlank) 'ppLayoutBlank 暫時沒想到怎代替 (先/後 導入) '開始設定PPT object_PPT.ActiveWindow.ViewType = ppViewNormal presentation_PPT.PageSetup.SlideOrientation = msoOrientationHorizontal '投影片方向 -> 橫向 presentation_PPT.PageSetup.SlideSize = ppSlideSizeCustom '投影片大小自訂 presentation_PPT.PageSetup.SlideWidth = CMtoPixel(29.7) presentation_PPT.PageSetup.SlideHeight = CMtoPixel(21) presentation_PPT.PageSetup.FirstSlideNumber = 1 presentation_PPT.SlideMaster.HeadersFooters.SlideNumber.Visible = msoTrue '投影片可見 ; SlideMaster -> 投影片母片 ; HeadersFooters -> 頁首頁尾 object_PPT.ActiveWindow.WindowState = ppWindowMaximized 'PPT畫面放最大 '設定PPT投影片 With presentation_PPT.Slides(1) '建立文字 .Shapes.AddTextbox(msoTextOrientationHorizontal, _ Left:=CMtoPixel(0.02), Top:=CMtoPixel(0.01), Width:=CMtoPixel(29.68), Height:=CMtoPixel(1.37)) _ .TextFrame.TextRange = "Hello World!!! 我我我" '設定(建立那一個文字的)字體格式 With .Shapes(1).TextFrame.TextRange.Font .Name = "微軟正黑體" .Size = 26 .Bold = msoTrue End With '建立圖片 With source_worksheet .Activate '1.從Excel抓取Cells範圍當圖片 range(.Cells(1, 1), .Cells(5, 16)).Copy Application.Wait (DateAdd("s", 1, Now)) presentation_PPT.Slides(1).Shapes.Paste Application.Wait (DateAdd("s", 1, Now)) With object_PPT.ActiveWindow.Selection.ShapeRange .Width = CMtoPixel(20) .Height = CMtoPixel(12.83) .Left = CMtoPixel(0.18) .Top = CMtoPixel(6.33) End With Application.Wait (DateAdd("s", 1, Now)) '2.從Excel建立群組後,以圖片輸出 <- 能吃Excel圖表 '在Excel事先建立 群組後 ' .Shapes.Range(Array("群組 1")).Copy ' Application.Wait (DateAdd("s", 3, Now)) ' Presentation.Slides(1).Shapes.PasteSpecial (ppPasteJPG) '後面一樣,設定大小 (With object_PPT.ActiveWindow.Selection.ShapeRange...略) End With End With '儲存&關閉 presentation_PPT.SaveAs ThisWorkbook.Path & "\Result\PPT_(Security C).pptx" object_PPT.ActiveWindow.Close ' object_PPT.Quit Set object_PPT = Nothing source_workbook.Close End Sub Private Function CMtoPixel(digits) CMtoPixel = digits * 28.35 '28.35 -> cm 轉 Pixel (大概相符) End Function ``` # SQL ## Main ``` Private Sub function_SQL() Dim SQL As New class_SQL SQL.Setting_fileSource = "D:\ASEKH\" & Environ("USERNAME") & "\RPA\(RPA)AutoPSN_Release(2900FCB)\PSNRawData_(Security C).xlsx" SQL.Setting_Code = "select PSN_No, CUST from [Sheet1$] where (CUST <> 'QM' and CUST <> 'TP' and CUST <> 'TZ' and CUST <> 'T4')" SQL.Run range("B2"), False ' Dim A As Object ' Set A = SQL.Getting_Data SQL.Clear End Sub ``` ## class_SQL ``` '<備註> ' 1. 範例: ' Dim SQL As New class_SQL ' SQL.Setting_fileSource = "D:\ASEKH\" & Environ("USERNAME") & "\RPA\(RPA)AutoPSN_Release(2900FCB)\PSNRawData_(Security C).xlsx" ' SQL.Setting_Code = "select PSN_No, CUST from [Sheet1$] where (CUST <> 'QM' and CUST <> 'TP' and CUST <> 'TZ' and CUST <> 'T4')" ' SQL.Run Range("B2"), False '' Dim A As Object '' Set A = SQL.Getting_Data ' SQL.Clear ' ' 2. (檔案來源) "D:\ASEKH\" & Environ("USERNAME") & "\RPA\(RPA)AutoPSN_Release(2900FCB)\PSNRawData_(Security C).xlsx" ' ' (SQL指令) "select PSN_No, CUST from [Sheet1$] where (CUST <> 'QM' and CUST <> 'TP' and CUST <> 'TZ' and CUST <> 'T4')" ' ' ' 3. 三種用法:(1) 正常帶入值 (bool_Field = True or 不輸入) -> 依序輸入標頭 ' (2) (bool_Field = false) -> 不輸入標頭 ' (3) 皆無帶入值 -> 可以用Getting_Data取得資料,後續自定義執行 Option Explicit Dim object_SQL_Connect As Object, object_SQL_Data As Object Dim str_SQL_Connect As String, str_SQL_Code As String, str_fileSource As String Dim int_i As Integer '輸入/更改參值 (檔案來源, SQL指令) <註1> Public Property Let Setting_fileSource(inputStr_fileSource As String) str_fileSource = inputStr_fileSource End Property Public Property Let Setting_Code(inputStr_SQL_Code As String) str_SQL_Code = inputStr_SQL_Code End Property ''取得參值 () 'Public Property Get Getting_Data() As Object ' Getting_Data = object_SQL_Data 'End Property '開始執行程式 ps:使用完畢要記得釋放記憶體 <註2> Public Sub Run(Optional range_location As range, Optional bool_Field As Boolean = True) If object_SQL_Connect Is Nothing Then Set object_SQL_Connect = CreateObject("adodb.connection") Else object_SQL_Connect.Close End If '不知道為啥CSV不能直接打開(後面的str_SQL_Connect賦值),這邊裝個擴充防呆吧;順便把txt用csv輸入的地方一起 <擴充1> Dim workbook_EMS As Workbook Dim bool_open As Boolean bool_open = False If Right(str_fileSource, 4) = ".csv" Or Right(str_fileSource, 4) = ".CSV" Then Set workbook_EMS = Workbooks.Open(str_fileSource) bool_open = True End If 'txt打開 -> 待擴充 'AAA '正式 If Application.Version < 12 Then str_SQL_Connect = "Provider=Microsoft.jet.OLEDB.4.0;Extended Properties=Excel 8.0;Data Source=" & str_fileSource Else str_SQL_Connect = "Provider=Microsoft.ACE.OLEDB.12.0;Extended Properties=Excel 12.0;Data Source=" & str_fileSource End If object_SQL_Connect.Open str_SQL_Connect Set object_SQL_Data = object_SQL_Connect.Execute(str_SQL_Code) If Not range_location Is Nothing Then If bool_Field Then For int_i = 0 To object_SQL_Data.Fields.Count - 1 range_location.Cells(1, int_i + 1) = object_SQL_Data.Fields(int_i).Name Next range_location.Offset(1).CopyFromRecordset object_SQL_Data Else range_location.CopyFromRecordset object_SQL_Data End If End If '<擴充1-後段> If bool_open = True Then workbook_EMS.Close SaveChanges:=False End If End Sub '結束時釋放記憶體 Public Sub Clear() object_SQL_Connect.Close Set object_SQL_Connect = Nothing Set object_SQL_Data = Nothing End Sub '更新紀錄 '初版:2024/05/02 By WeiCheng_Lee ``` # Workbook 儲存範圍轉圖片抓取 ## Main ``` Private Sub Sub_CacheChart() Dim CacheChart As New class_CacheChart ' CacheChart.Setting_range = range("A1:A1") CacheChart.Setting_FileFolder = "C:\Users\K17805\Downloads\新增資料夾\" ' CacheChart.Setting_FileName = "ABC.jpg" Call CacheChart.Run(range("A1:A1"), "ABC.jpg") End Sub ``` ## class_CacheChart ``` '<備註> ' 1. 範例: ' Dim CacheChart As New class_CacheChart ' ' With worksheet_CHART ' .Activate ' ' CacheChart.Setting_FileFolder = GlobalValue.str_ResultDataFolder ' ' ' CacheChart.Run .Range("A2:P26"), str_Chart1_Name ' ' CacheChart.Run .Range("A59:P75"), str_Chart2_Name ' ' End With ' 2. 截圖要抓到主頁面,才能擷取 ' 3. 檔案名稱,這邊鎖死JPG (可擴充) Option Explicit 'Dim rng As Range Dim shp As shape Dim nm$, myFolder$ 'Dim nm$, myFolder$, pictureName$ '末尾$是字串的意思 (As String) '輸入/更改參值 (擷取範圍,資料夾路徑,檔案名稱) 'Public Property Let Setting_range(input_rng As Range) ' rng = input_rng 'End Property Public Property Let Setting_FileFolder(inputStr_Folder As String) myFolder$ = inputStr_Folder End Property 'Public Property Let Setting_FileName(inputStr_FileName As String) ' pictureName$ = inputStr_FileName 'End Property Public Sub Run(input_Range As range, inputStr_FileName As String) input_Range.Copy ActiveSheet.Pictures.Paste For Each shp In ActiveSheet.Shapes If shp.Type = 13 Then If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If shp.CopyPicture With ActiveSheet.ChartObjects.Add(0, 0, shp.Width, shp.Height).Chart .Parent.Select .Paste .Export myFolder & inputStr_FileName, "JPG" .Parent.Delete End With shp.Delete End If Next End Sub '更新紀錄 '初版:2024/05/02 By WeiCheng_Lee ``` # 將檔案轉UTF-8 ``` Sub ConvertToUTF8(strInput_Path, strInput_Name) Dim command_shell As Variant Dim code As String code = "PowerShell -Command " & "&{Get-Content '" & strInput_Path & "\" & strInput_Name _ & "' | Set-Content -Encoding utf8 '" & strInput_Path & "\utf8_" & strInput_Name & "'}" command_shell = Shell(code, vbNormalFocus) Sleep 8000 End Sub ``` # 去除Worksheet底部空白 ``` '去Excel工作表底部,空白儲存格 (似乎會發生在去重複之後,Excel內部殘值? 總之先試看看) Sub DeleteBlankCell_FromWorksheet(worksheet_Current As Worksheet, long_lastRow As Long) With worksheet_Current .Activate If long_lastRow < 1048576 Then .Rows(CStr(long_lastRow + 1) & ":1048576").Delete Shift:=xlUp End With End Sub ``` # 列行字母&列行數轉換 ## 行數轉字母 ``` Function Column_DigitToChar(ByVal Col_Dig As Variant) 'Int 、 Long Column_DigitToChar = Replace(Cells(1, Col_Dig).Address(False, False), "1", "") End Function ``` ## 字母轉行數 ``` Function Column_CharToDigit(ByVal Col_Chr As String) As Long Dim i As Long, colNum As Long colNum = 0 For i = 1 To Len(Col_Chr) colNum = colNum * 26 + Asc(UCase(Mid(Col_Chr, i, 1))) - 64 Next i Column_CharToDigit = colNum End Function ``` # 取得最後行列數 ## 最後 Row ``` Function GetLastRow(Optional inputStr_Range As String = "A1") As Long If Range(inputStr_Range).Value <> "" Then GetLastRow = Cells.Find(What:="*", _ After:=Range(inputStr_Range), _ LookAt:=xlPart, _ LookIn:=xlFormulas, _ SearchOrder:=xlByRows, _ SearchDirection:=xlPrevious, _ MatchCase:=False).Row Else GetLastRow = 1 End If End Function ``` ## 最後 Column ``` Function GetLastColumn(Optional inputStr_Range As String = "A1") As Long If Range(inputStr_Range).Value <> "" Then GetLastColumn = Cells.Find(What:="*", _ After:=Range(inputStr_Range), _ LookAt:=xlPart, _ LookIn:=xlFormulas, _ SearchOrder:=xlByColumns, _ SearchDirection:=xlPrevious, _ MatchCase:=False).Column Else GetLastColumn = 1 End If End Function ``` # Excel執行初始/結束設定 ## 開始設定 ``` Sub Close_Excel_fuction_for_efficiency() Application.ScreenUpdating = False '(不)顯示螢幕更新 Application.DisplayStatusBar = False '(不)顯示狀態列 Application.EnableEvents = False '(不)物件觸發事件 Application.DisplayAlerts = False '(不)顯示對話視窗 Application.AskToUpdateLinks = False '不顯示更新 Application.Calculation = xlCalculationManual '(不)顯示Excel公式更新 End Sub ``` ## 結束設定 ``` Sub Open_Excel_fuction_for_EndVBA() Application.ScreenUpdating = True Application.DisplayStatusBar = True Application.EnableEvents = True Application.DisplayAlerts = True Application.AskToUpdateLinks = True Application.Calculation = xlCalculationAutomatic End Sub ``` # 呼叫Excel公式 ## Match & Index ``` For int_i = int_CurrentRow_Destination To int_lastRow_Destination int_temp = Application.Match(.Cells(int_i, Column_CharToDigit("C")).Value, Worksheets("WIP").Columns("I:I"), 0) .Cells(int_i, Column_CharToDigit("CE")) = Application.Index(Worksheets("WIP").Columns("F:F"), int_temp) .Cells(int_i, Column_CharToDigit("CF")) = Application.Index(Worksheets("WIP").Columns("G:G"), int_temp) .Cells(int_i, Column_CharToDigit("CJ")) = Application.Index(Worksheets("WIP").Columns("J:J"), int_temp) .Cells(int_i, Column_CharToDigit("CK")) = Application.Index(Worksheets("WIP").Columns("K:K"), int_temp) .Cells(int_i, Column_CharToDigit("DC")) = Application.Index(Worksheets("WIP").Columns("M:M"), int_temp) Next ``` # 判斷檔案是否被開啟 ``` Function IsFileOpen(filePath As String) As Boolean On Error Resume Next Open filePath For Input Lock Read As #1 IsFileOpen = (Err <> 0) Close #1 On Error GoTo 0 End Function ``` # 網頁爬蟲 ## IE ### 前文 > VBA唯一不需外部插件,可讀取網站動態JS的功能 使用CreateObject("InternetExplorer.Application") ``` Dim IE As Object Set IE = CreateObject("InternetExplorer.Application") ``` > 本身動態/靜態讀取皆支持 | 方法比較 | 特性 | 觸發網頁 JS 事件 | 適用情境 | | ----- | ----- | ----- | ----- | | **VBA 直接操作 IE DOM **<br>`IE.Document.getElementById("username").Value = "myUser"` | 靜態、執行效率高 | 否 | 大多數標準表單輸入 | | **在網頁執行 JavaScript**<br>`execScript "document.getElementById('username').value='myUser'"` | 動態、可操作網頁 | 是 | 須模擬使用者行為的情境 | ### IE.Visible > True/False : 顯示瀏覽器視窗/於背景執行 ``` IE.Visible = True ``` ### IE.navigate > 前往指定網頁 通常會搭配網頁載入偵測使用 ``` IE.navigate "http://myvf.kh.asegroup.com/vf/root/" Do While IE.Busy Or IE.readyState <> 4: DoEvents: Loop ``` ### IE.Busy > True/False : IE 正在進行網路請求或載入資源/目前沒有進行載入動作 ### IE.readyState > IE 載入狀態,回傳 int ![image](https://hackmd.io/_uploads/Hy9ZSSedll.png) ### DoEvents > 讓 VBA 暫時把控制權交回給系統,允許其他事件(例如瀏覽器繼續載入)正常運作。 p.s. async非同步的概念,沒有這行,迴圈可能「卡住」導致 Excel 停止回應(Not Responding)。 ### IE.document.parentWindow.execScript > 操作網頁JS執行指令 ``` IE.document.parentWindow.execScript "location.href='https://myvf.kh.asegroup.com:18181/webrpt/home_page.asp'" IE.document.parentWindow.execScript "document.getElementById('username') = myUser" IE.document.parentWindow.execScript "document.getElementById('div_tab').children[0].children[1].children[5].children[2].children[1].value = '070000'" IE.document.parentWindow.execScript "document.getElementById('div_tab').children[0].children[1].children[5].children[5].children[0].value = '" & curT & "'" '網站定義函數 "查詢" IE.document.parentWindow.execScript "runquery();" ``` ### 實際應用 - 複製網頁資訊,從剪貼簿取得至VBA > JS 原本語法 ``` var str = document.querySelector("#form1 > div.card.bg-light.mb-3 > div.card-body > button").innerText; btn(); function btn() { var value = str; var el = document.createElement('textarea'); el.value = value; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); }; ``` > 更改成 VBA 語法 (code那段的元素路徑會更改) ``` Const Copycode = "btn();" _ & "function btn() {" _ & "var value = str;" _ & "var el = document.createElement('textarea');" _ & "el.value = value;" _ & "document.body.appendChild(el);" _ & "el.select();" _ & "document.execCommand('copy');" _ & "document.body.removeChild(el);};" '將網站查詢結果,抓到剪貼簿 code = "var str = document.getElementById('div_data').innerText;" & Copycode IE.document.parentWindow.execScript code Sleep 500 '從剪貼簿抓資料 (下載 / data not found),存到VBA裡面 objData.GetFromClipboard '使用物件呼叫當前剪貼簿資料 str = objData.GetText() '將物件資料,儲存到$str ``` # 從剪貼簿取值 > 使用 MSForms.DataObject (VBA的剪貼物件) ``` Dim objData As New MSForms.DataObject objData.GetFromClipboard '使用物件呼叫當前剪貼簿資料 str = objData.GetText() '將物件資料,儲存到$str ``` # API 呼叫 > 會因呼叫網站功能不同,導致mydata寄送的內容有相異 ``` Sub Event_Hub_Api(str_Token As String, Optional str_value As String = "") Dim httpsource As Object Set httpsource = CreateObject("WinHttp.WinHttpRequest.5.1") ' 對目標網址執行 POST 命令 httpsource.Open "POST", "https://eventhub.kh.asegroup.com/v1/web_api/", False Dim mydata As String ' vba 的 json mydata = "{""token"": """ & str_Token & """,""event_data"": {""value1"": """ & str_value & """}}" ' 送出命令並接收資料 httpsource.send mydata Set httpsource = Nothing End Sub ``` # 更改圖片大小 ``` '更改圖片大小,強化Note文字清晰度 (因為公司的信箱沒辦法讀取CSS縮放格式,自動調整高度 height : auto) Public Sub ResizeJPG_PowerShell(str_FilePath As String, Optional long_widthPixcel As Long = 1800) Dim wsh As Object Dim psCmd As String '<防呆> 檢查路徑是否存在 If Dir(str_FilePath) = "" Then Err.Raise vbObjectError + 5487, "ResizeJPG_PowerShell", "未發現檔案路徑" & vbCrLf & str_FilePath ' 執行 PowerShell 並等待完成 psCmd = "powershell -NoProfile -Command " & _ """Add-Type -AssemblyName System.Drawing; " & _ "$img = [System.Drawing.Image]::FromFile('" & str_FilePath & "'); " & _ "$ratio = " & CStr(long_widthPixcel) & " / $img.Width; " & _ "$newH = [int]($img.Height * $ratio); " & _ "$bmp = New-Object System.Drawing.Bitmap(" & CStr(long_widthPixcel) & ", $newH); " & _ "$gfx = [System.Drawing.Graphics]::FromImage($bmp); " & _ "$gfx.DrawImage($img, 0, 0, " & CStr(long_widthPixcel) & ", $newH); " & _ "$img.Dispose(); $gfx.Dispose(); " & _ "$bmp.Save('" & str_FilePath & "', [System.Drawing.Imaging.ImageFormat]::Jpeg); $bmp.Dispose();""" Set wsh = CreateObject("WScript.Shell") wsh.Run psCmd, 0, True '0=隱藏PowerShell視窗, True=VBA 等待 PowerShell 完成後才繼續 Set wsh = Nothing '<防呆> 檢查路徑是否存在 If Dir(str_FilePath) = "" Then Err.Raise vbObjectError + 5487, "ResizeJPG_PowerShell", "縮放後圖片未生成,請檢查 PowerShell 環境" & vbCrLf & str_FilePath End Sub ``` # 擷取儲存格,轉成圖片 ``` '<備註> ' 1. 範例: ' Dim CacheChart As New class_CacheChart ' ' CacheChart.Setting_FileFolder = str_Folder_Chart ' ' Call CacheChart.Run(range_CacheChart, str_fileName) ' 2. 檔案名稱,這邊鎖死JPG (可擴充) Option Explicit Dim shp As Shape Dim nm$, myFolder$ '末尾$是字串的意思 (As String) '輸入/更改參值 (資料夾路徑) Public Property Let Setting_FileFolder(inputStr_Folder As String) myFolder$ = inputStr_Folder End Property Public Sub Run(input_Range As Range, inputStr_FileName As String) Dim chtObj As ChartObject Dim timeout As Double Set chtObj = worksheet_Marco.ChartObjects.Add(0, 0, input_Range.Width, input_Range.Height) timeout = Timer + 120 Do On Error Resume Next input_Range.CopyPicture xlScreen, xlPicture If Err.Number = 0 Then Exit Do DoEvents If Timer > timeout Then Exit Do Loop On Error GoTo 0 ' 將圖片貼到圖表中 chtObj.Activate chtObj.Chart.Paste timeout = Timer + 10 Do While chtObj.Chart.Shapes.Count = 0 DoEvents If Timer > timeout Then Exit Do Loop ' 匯出為 JPG chtObj.Chart.Export Filename:=myFolder & inputStr_FileName, FilterName:="JPG" ' 刪除暫存物件 chtObj.Delete ' 後處理:縮放 Call ResizeJPG_PowerShell(myFolder & inputStr_FileName) Set chtObj = Nothing End Sub ``` ## HBPOP OS Summary 工具原工程師寫法 ``` Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Sub TXT匯入(Optional ByVal inputStr_FilePath As String = "") ' ' TXT匯入 ' ' 快速鍵: Ctrl+w ' Dim myFolder$ Sheets("Raw").Select If inputStr_FilePath <> "" Then myFolder$ = inputStr_FilePath Else myFolder$ = InputBox("輸入路徑(TXT)") End If With ActiveSheet.QueryTables.Add(Connection:= _ "TEXT;" & myFolder$ _ , Destination:=Range("$A$1")) '.CommandType = 0 .name = myFolder$ .FieldNames = True .RowNumbers = False .FillAdjacentFormulas = False .PreserveFormatting = True .RefreshOnFileOpen = False .RefreshStyle = xlInsertDeleteCells .SavePassword = False .SaveData = True .AdjustColumnWidth = True .RefreshPeriod = 0 .TextFilePromptOnRefresh = False .TextFilePlatform = 950 .TextFileStartRow = 1 .TextFileParseType = xlDelimited .TextFileTextQualifier = xlTextQualifierDoubleQuote .TextFileConsecutiveDelimiter = True .TextFileTabDelimiter = True .TextFileSemicolonDelimiter = True .TextFileCommaDelimiter = True .TextFileSpaceDelimiter = True .TextFileOtherDelimiter = "(" .TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1) .TextFileTrailingMinusNumbers = True .Refresh BackgroundQuery:=False End With Cells.Select Selection.AutoFilter Selection.Replace What:=")", Replacement:="", LookAt:=xlPart, _ SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _ ReplaceFormat:=False ActiveSheet.Range("$A$1:$W$340").AutoFilter Field:=2, Criteria1:="=DUT", _ Operator:=xlOr, Criteria2:="=Fail" Columns("B:Y").Select Selection.ColumnWidth = 5 Cells.Select Sheets("Button").Select End Sub Sub Screenshot(Optional ByVal inputStr_ScheduleName As String = "", Optional bool_ChartOutput As Boolean = True) Dim i, j, LC As Integer Dim rng, rng_1 As Range Dim shp As shape Dim nm$, myFolder$, pictureFullName$, pictureName$, name$, folder$, SI, Bump, SI_1, Bump_1 Dim bool_Open_ToTemp As Boolean '判斷是手動執行還是自動執行 (手動執行沒有temp分頁,也不用匯入資訊到總表) If ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count).name <> "temp" Then bool_Open_ToTemp = False Else bool_Open_ToTemp = True End If Dim worksheet_temp As Worksheet Dim strArray_temp() As String If bool_Open_ToTemp Then Set worksheet_temp = Worksheets("temp") Sheets("Raw").Range("A1") = "=COUNTIFS(B:B,""Fail"")" If Sheets("Raw").Range("A1") = 0 Then Sheets("Raw").Select Last_Data_Row = Sheets("Raw").Cells(Rows.Count, "B").End(xlUp).Row Sheets("Raw").Range("A2:A" & Last_Data_Row) = "=CONCATENATE(LEFT(RC[7],1),RC[3])" '編碼 ActiveSheet.Range("$A$1:$W$1500").AutoFilter Field:=8, Criteria1:="Short" allrowscount = ActiveSheet.UsedRange.Rows.Count '篩選後個數 Range("D1:D" & allrowscount) = "=COUNTIFS(C[4],""Short"",C[-2],""DUT"")-COUNTIFS(R[1]C[4]:R[1500]C[4],""Short"",R[1]C[-2]:R[1500]C[-2],""DUT"")" ActiveSheet.Range("$A$1:$W$1500").AutoFilter Field:=8, Criteria1:="Open" allrowscount = ActiveSheet.UsedRange.Rows.Count '篩選後個數 Range("D1:D" & allrowscount) = "=COUNTIFS(C[4],""Open"",C[-2],""DUT"")-COUNTIFS(R[1]C[4]:R[1500]C[4],""Open"",R[1]C[-2]:R[1500]C[-2],""DUT"")" ActiveSheet.Range("$A$1:$W$1500").AutoFilter Field:=8 Cells.Select Selection.Copy Sheets("Rawdata").Select Range("A1").Select Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False name$ = Sheets("Button").Range("F2").Value If inputStr_ScheduleName <> "" Then folder$ = inputStr_ScheduleName Else folder$ = InputBox("輸入資料夾名稱") End If myFolder = name$ & "\" & folder$ & "\" '資料夾路徑(要改) LC = Sheets("Button").Range("F4").Value Last_Data_Row = Sheets("Rawdata").Cells(Rows.Count, "B").End(xlUp).Row For i = 2 To Last_Data_Row If Sheets("Rawdata").Range("I" & i) > LC Then Sheets("Rawdata").Range("J" & i & ",L" & i & ",N" & i & ",P" & i & ",R" & i & ",T" & i & ",V" & i & ",X" & i & ",Z" & i).Copy SI_1 = Sheets("Button").Range("F11").Value Sheets("SI").Range(SI_1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False Bump_1 = Sheets("Button").Range("F12").Value Sheets("Bump").Range(Bump_1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False If bool_ChartOutput Then SI = Sheets("Button").Range("F7").Value Set rng = Sheets(3).Range(SI) If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If pictureName = Sheets("Rawdata").Range("A" & i).Value pictureFullName = pictureName & ".jpg" Sleep (double_ChartSleepTime * 1000) rng.CopyPicture With Sheets("SI").ChartObjects.Add(0, 0, rng.Width, rng.Height).Chart .Parent.Select .Paste .Export myFolder & "\" & pictureFullName .Parent.Delete End With Bump = Sheets("Button").Range("F8").Value Set rng_1 = Sheets("BUMP").Range(Bump) If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If pictureName = Sheets("Rawdata").Range("A" & i).Value pictureFullName = pictureName & "-1.jpg" Sleep (double_ChartSleepTime * 1000) rng_1.CopyPicture With Sheets("BUMP").ChartObjects.Add(0, 0, rng_1.Width, rng_1.Height).Chart .Parent.Select .Paste .Export myFolder & "\" & pictureFullName .Parent.Delete End With End If Else Sheets("Rawdata").Range("J" & i & ",L" & i & ",N" & i & ",P" & i & ",R" & i & ",T" & i & ",V" & i & ",X" & i & ",Z" & i).Copy Bump_1 = Sheets("Button").Range("F12").Value Sheets("Bump").Range(Bump_1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False If bool_ChartOutput Then Bump = Sheets("Button").Range("F8").Value Set rng_1 = Sheets("BUMP").Range(Bump) If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If pictureName = Sheets("Rawdata").Range("A" & i).Value pictureFullName = pictureName & ".jpg" Sleep (double_ChartSleepTime * 1000) rng_1.CopyPicture With Sheets("SI").ChartObjects.Add(0, 0, rng_1.Width, rng_1.Height).Chart .Parent.Select .Paste .Export myFolder & "\" & pictureFullName .Parent.Delete End With End If End If 'Ver 2.0 Get defectLocation Data Array If bool_Open_ToTemp Then strArray_temp = Main2.GetStringArray_ByDefectLocation() worksheet_temp.Cells(i - 1, 1).Resize(1, UBound(strArray_temp)).Value = strArray_temp End If Next i Sheets("Button").Select Else Sheets("Raw").Select Last_Data_Row = Sheets("Raw").Cells(Rows.Count, "B").End(xlUp).Row Sheets("Raw").Range("A2:A" & Last_Data_Row) = "=IF(RC[1]=""Fail"",CONCATENATE(LEFT(R[-1]C[7],1),R[-1]C[3]),CONCATENATE(LEFT(RC[7],1),RC[3]))" '編碼 ActiveSheet.Range("$A$1:$W$1500").AutoFilter Field:=8, Criteria1:="Short" allrowscount = ActiveSheet.UsedRange.Rows.Count '篩選後個數 Range("D1:D" & allrowscount) = "=COUNTIFS(C[4],""Short"",C[-2],""DUT"")-COUNTIFS(R[1]C[4]:R[1500]C[4],""Short"",R[1]C[-2]:R[1500]C[-2],""DUT"")" ActiveSheet.Range("$A$1:$W$1500").AutoFilter Field:=8, Criteria1:="Open" allrowscount = ActiveSheet.UsedRange.Rows.Count '篩選後個數 Range("D1:D" & allrowscount) = "=COUNTIFS(C[4],""Open"",C[-2],""DUT"")-COUNTIFS(R[1]C[4]:R[1500]C[4],""Open"",R[1]C[-2]:R[1500]C[-2],""DUT"")" ActiveSheet.Range("$A$1:$W$1500").AutoFilter Field:=8 ActiveSheet.Range("$A$1:$Y$1500").AutoFilter Field:=2, Criteria1:="Fail" Cells.Select Selection.Copy Sheets("Rawdata").Select Range("A1").Select Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False name$ = Sheets("Button").Range("F2").Value If inputStr_ScheduleName <> "" Then folder$ = inputStr_ScheduleName Else folder$ = InputBox("輸入資料夾名稱") End If myFolder = name$ & "\" & folder$ & "\" '資料夾路徑(要改) Last_Data_Row = Sheets("Rawdata").Cells(Rows.Count, "B").End(xlUp).Row LC = Sheets("Button").Range("F4").Value For i = 2 To Last_Data_Row If Sheets("Rawdata").Range("E" & i) > LC Then Sheets("Rawdata").Range("F" & i & ",H" & i & ",J" & i & ",L" & i & ",N" & i & ",P" & i & ",R" & i & ",T" & i & ",V" & i & ",X" & i).Copy SI_1 = Sheets("Button").Range("F11").Value Sheets("SI").Range(SI_1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False Bump_1 = Sheets("Button").Range("F12").Value Sheets("Bump").Range(Bump_1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False If bool_ChartOutput Then SI = Sheets("Button").Range("F7").Value Set rng = Sheets("SI").Range(SI) If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If pictureName = Sheets("Rawdata").Range("A" & i).Value pictureFullName = pictureName & ".jpg" Sleep (double_ChartSleepTime * 1000) rng.CopyPicture With Sheets("SI").ChartObjects.Add(0, 0, rng.Width, rng.Height).Chart .Parent.Select .Paste .Export myFolder & "\" & pictureFullName .Parent.Delete End With Bump = Sheets("Button").Range("F8").Value Set rng_1 = Sheets("BUMP").Range(Bump) If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If pictureName = Sheets("Rawdata").Range("A" & i).Value pictureFullName = pictureName & "-1.jpg" Sleep (double_ChartSleepTime * 1000) rng_1.CopyPicture With Sheets("BUMP").ChartObjects.Add(0, 0, rng_1.Width, rng_1.Height).Chart .Parent.Select .Paste .Export myFolder & "\" & pictureFullName .Parent.Delete End With End If Else Sheets("Rawdata").Range("F" & i & ",H" & i & ",J" & i & ",L" & i & ",N" & i & ",P" & i & ",R" & i & ",T" & i & ",V" & i & ",X" & i).Copy Bump_1 = Sheets("Button").Range("F12").Value Sheets("Bump").Range(Bump_1).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False If bool_ChartOutput Then Bump = Sheets("Button").Range("F8").Value Set rng_1 = Sheets(2).Range(Bump) If Len(Dir(myFolder, vbDirectory)) = 0 Then '若myFolder不存在則新增資料夾 MkDir myFolder End If pictureName = Sheets("Rawdata").Range("A" & i).Value pictureFullName = pictureName & ".jpg" Sleep (double_ChartSleepTime * 1000) rng_1.CopyPicture With Sheets("SI").ChartObjects.Add(0, 0, rng_1.Width, rng_1.Height).Chart .Parent.Select .Paste .Export myFolder & "\" & pictureFullName .Parent.Delete End With End If End If 'Ver 2.0 Get defectLocation Data Array If bool_Open_ToTemp Then strArray_temp = Main2.GetStringArray_ByDefectLocation() worksheet_temp.Cells(i - 1, 1).Resize(1, UBound(strArray_temp)).Value = strArray_temp End If Next i Sheets("Button").Select End If End Sub Sub 清除() Sheets("Rawdata").Select Cells.Select Application.CutCopyMode = False Selection.Delete Shift:=xlUp Sheets("Raw").Select Cells.Select Selection.Delete Shift:=xlUp Selection.Delete Shift:=xlUp Dim shp As shape For Each shp In Sheets("Raw").Shapes shp.Delete Next shp Sheets("Button").Select End Sub ``` GPT 說明 ``` 非常好 👍 你提供的這段 VBA 程式主要是用來 從 TXT 檔案匯入資料到「Raw」工作表,再進行格式處理與篩選。 以下是完整、清楚的逐行說明與邏輯分析,方便你日後維護或修改。 📘 程式說明:Sub TXT匯入(Optional ByVal inputStr_FilePath As String = "") 🔹 功能概要 這支程式會: 讓使用者輸入或指定 TXT 檔案路徑。 將該 TXT 檔案的內容匯入到 Raw 分頁中。 進行基本清理、篩選、欄寬調整。 最後切換回 Button 分頁。 🔹 逐步說明 Sub TXT匯入(Optional ByVal inputStr_FilePath As String = "") 宣告一個名為「TXT匯入」的子程序。 參數 inputStr_FilePath 是可選的,若有傳入值,就直接用來指定檔案路徑;若沒傳,會跳出輸入框讓使用者自行輸入。 Dim myFolder$ Sheets("Raw").Select 宣告變數 myFolder(字串型態)用來存放檔案路徑。 將目前工作表切換到 Raw,準備匯入資料。 If inputStr_FilePath <> "" Then myFolder$ = inputStr_FilePath Else myFolder$ = InputBox("輸入路徑(TXT)") End If 若外部呼叫時已傳入檔案路徑,則直接使用該路徑。 否則顯示一個輸入框,讓使用者手動輸入 TXT 檔案路徑。 With ActiveSheet.QueryTables.Add(Connection:= _ "TEXT;" & myFolder$ _ , Destination:=Range("$A$1")) 使用 QueryTables.Add 建立一個「資料查詢連線」, 將 TXT 檔案作為資料來源,匯入至 A1 起始的儲存格。 接下來這一段是設定 匯入參數與格式: .Name = myFolder$ .FieldNames = True .RowNumbers = False .PreserveFormatting = True .RefreshStyle = xlInsertDeleteCells .TextFilePlatform = 950 .TextFileParseType = xlDelimited .TextFileConsecutiveDelimiter = True .TextFileTabDelimiter = True .TextFileSemicolonDelimiter = True .TextFileCommaDelimiter = True .TextFileSpaceDelimiter = True .TextFileOtherDelimiter = "(" .TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1) .TextFileTrailingMinusNumbers = True .Refresh BackgroundQuery:=False End With 重點: .TextFilePlatform = 950 → 指定使用 繁體中文 (Big5) 編碼。 .TextFileParseType = xlDelimited → 以「分隔符號」解析 TXT。 .TextFileTabDelimiter、.TextFileCommaDelimiter、.TextFileSemicolonDelimiter、.TextFileOtherDelimiter 等 → 同時允許多種分隔符號(Tab、逗號、分號、空格、括號)。 .Refresh → 實際執行匯入。 Cells.Select Selection.AutoFilter Selection.Replace What:=")", Replacement:="" 對整張表套用篩選。 將所有 ) 替換成空白(刪除右括號)。 ```